10 years, 5 months ago.

Simplifying the code

Hi Frank This is great code, but I would like to ask a few questions. I want to change it to a simple "colour organ" using the inbuilt tri-colour LED or an external one. I want the amplitude of the bass frequencies to determine the Red brightness, middle = green and treble = blue. At the present I am finding it difficult to understand what your values for number of pixels do, slowdown and how the very complex hue arithmetic in hsi2rgbw works (parabolic mapping??). I just want to convert the code to have 3 audio bands, and the magnitude of each band changes the PWM mark space ratio for its related LED drive. Have you got any better commented code so that I can start to take it apart? ANy help appreciated Tony

Question relating to:

Audio Spectrum analyser - FFT using mbed-dsp - driving RGB(W) LED or PC python script. Analyzer, audio, FFT, python, rgb, RGBW, Spectrum

1 Answer

10 years, 5 months ago.

The HSI to RGB(W) code is not mine, did you go to this link on the HSI2RGBW_PWM page?
During my search for a decent HSI to RGB(W) conversion function, i found abovementioned link (SaikoLed - maintained by Brian Neltner). His website contains valuable info on RGB(W) Leds and colorspaces. I ported his code to the mbed environment and modified it to allow the user to switch between RGB and RGBW mode.
Note : As you can see on the HSI2RGBW_PWM page, the parabolic mode can be disabled.

The FFT_demo also contains a link to the original Adafruit code. This page has more in-depth info about FFT, as well as a demo video showing how four different leds relate to the PIXEL_COUNT and the frequency spectrum..
The slowdown command is something i added to allow a slower visualization - very useful when a single RGB led is used (explained on the FFT_demo homepage). Unless you use 3 separate leds (Red, Green and Blue), the slowdown function is needed for a single RGB led, otherwise you will get lots of near-white colors.
spectrumSetup() function : The PIXEL_COUNT declaration is used to define the number of leds and the full Hue range (0..360), as well as the the frequency spectrum is evenly spread among all leds.
So, without modifying the code, setting PIXEL_COUNT to 3 and keeping SLOWDOWN above 0 should do the trick. Of course, you can always remove the command parser, rxisr() function, ....
The Adafruit application already covers as much options as possible (user modifiable without having to change the code).
I added functionality to allow the use of a single RGB led.

I thought the Doxygen docs, the comments in the code and the links to the original code were sufficient to understand everything.

A spinoff project is also ready but i haven't had the time to publish it (my daytime job is interfering too much with my mbed time - should be the other way around) : i further added some functions and used a board with 32 RGB leds (PCA9635 based).

Hi Frank Thanks for taking the time to answer. I believe that when I did what you have suggested, I didnt get the colours I wanted because of the hue calculations. I have now managed to simplify the code completely by taking out the hsi2rgbw libraries and including simple calls to the pwm led routines for red green and blue - I now set the hue array values to the amplitude values and set the r g and b pwm values to the first 3. That is now working, except for a strange problem that the LED only works if the processor is sending serial data to the host - I have now got it continually sending some useless text to keep the led lit! BTW, I can get away with no mic preamp by setting the lower signal to 20dB. Thanks again Tony ps there is nothing wrong with the comments in the code and you have documented it very well - its just that I am not a very competent programmer, and trying to use this example for a simple course I am running for some Arduino lovers! So I wanted to keep the LED driving as simple as possible, even though the number crunching going on in the fft is complex (sic).

posted by Tony Abbey 17 Jun 2014

Quite strange you need to keep the serial port busy in order to drive the leds. Did you put the led code in the serial function? If possible, publish your code, we can have a look at it and help to improve it.

posted by Frank Vannieuwkerke 17 Jun 2014

Hi Frank I have published my code here: http://mbed.org/users/tony1tf/code/KL25Z_FFT_Demo_tony/ As far as I can see, the LED driving should be independent of the serial port. Currently the code continually writes "this will make it work " to the serial port and the LED works OK. If you comment out that code at line 371 you will see that the LED stays off, unless you request some data on the serial port. I have added a request command for the 3 "hues" - the R G and B values (0 to 1) - "GET HUES;"

posted by Tony Abbey 17 Jun 2014

I had a quick look at your code (haven't had time to run it). I think the problem is that the code runs too fast, that's why the printf you added makes it work (not only it slows down the while loop but you also steal time from the FFT conversion - will result in incorrect conversions). You should be able to get the same result by raising the SLOWDOWN value (note that this value is a cpu-clock dependent counter). As this is non-blocking, it won't interfere with the FFT conversion.

I assume you didn't remove the hues spreading code in spectrumSetup() when you tried using PIXEL_COUNT = 3?

posted by Frank Vannieuwkerke 17 Jun 2014

Hi Frank SLOWDOWN doesn't appear to do anything. I did try removing the hue spreading code in your original code, but the whole thing is too complex for me to understand and remove unwanted parts, which is why I simplified the code. I have been experimenting and found that there are places where I can't get printf to do anything (for instance I wanted to echo anything typed, or the whole command when the ";" was detected - have now added a flag to turn printing something on or off in the main loop rather than modifying the code each time - that does work and allow the LED to light. Clearly, I dont quite understand how the various parts of the code work.

posted by Tony Abbey 19 Jun 2014

Hi again Added a simple 10ms wait before "restart audio sampling". Now the simplified code works well, and seems a lot more sensitive. I will have to learn why the sampling and fft code is affected by this.

posted by Tony Abbey 19 Jun 2014

Mystery solved : We need to raise the FFT_SIZE. Due to memory constraints, i had to keep the FFT_SIZE low as i was using a high PIXEL_COUNT. Setting both PIXEL_COUNT and FFT_SIZE to a low value results in erroneous output. Using following settings in my original code works very well : SLOWDOWN = 10 - SAMPLE_RATE_HZ = 40000 - SPECTRUM_MIN_DB = 30.0 - SPECTRUM_MAX_DB = 80.0 - LEDS_ENABLED = 1 - FFT_SIZE = 128 - PIXEL_COUNT = 4 - MAX_CHARS = 65

Notice that PIXEL_COUNT is set to 4 instead of 3 (the hues spreading calculation in spectrumSetup() subtracts 1 from PIXEL_COUNT) and SAMPLE_RATE_HZ = 40000 (sample rate needs to be twice the frequency, so for 20kHz, we need to sample at 40kHz). To confirm we really get RED, GREEN an BLUE, change SLOWDOWN to 1000, 1001 and 1002.

posted by Frank Vannieuwkerke 20 Jun 2014

Hi Frank Thanks for the additional info. I have gone back to your original code using these parameters, and have 2 problems. Firstly, there has been an update to mbed and I get the following error: Error: Symbol NMI_Handler multiply defined (by mbed_overrides.o and main.cpp.KL25Z.o). I got rid of this by deleting the 3 lines: extern "C" void NMI_Handler() { DigitalIn test(PTA4); }

Not sure whether doing this has a knock on effect, since I am still having problems - with sound input the LED just cycles through the 3 colours - brightly if I put my finger on the input - I dont get a colour corresponding to a frequency. I have checked that SLOWDOWN of 1000, 1001 and 1002 gives the 3 separate colours. The code certainly doesn't seem to work like my simplified code. I'll carry on experimenting and see if I can understand it - I have added commands to view hues and frequency bands like in my previous code. The hues command gives 0, 120, 240, 360 irrespective of the input. Tony

posted by Tony Abbey 13 Jul 2014

You are right, the NMI handler needs to be removed as the latest mbed libs change the NMI input to a plain DigitalIn (https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KLXX/TARGET_KL25Z/mbed_overrides.c).

The color cycling is because i set SLOWDOWN=10. This is similar to the 10ms delay you introduced in your main loop but, as i mentioned before, your delay is blocking while SLOWDOWN is non-blocking. This means that, every time you add code/calls to your main loop, you'll probably need to update the delay as well. Not that it's very important in this application, but, whenever possible, it's good practice to avoid blocking delays. As SLOWDOWN behaves differently from your ms delay (SLOWDOWN shows each color a little longer), you could use a 10ms timer in your program to call samplingBegin(). As a result, the main loop will not be blocked = lots of additional time to do other stuff.

Quite strange the hues command returns these fixed values.

posted by Frank Vannieuwkerke 13 Jul 2014