Alternative to audio spectrum without additional hardware or FFT on Arduino

I have a robo clock with voice output that works fine. However been mucking around with the audio spectrum output for ages.

Firstly I used an MSGEQ7 circuit that worked well except it’s 7 bands with little flexibility to change too much. It also requires analog reads to get the data out.

The second approach was do the FFT on the fly however this was a bit sad when reading from SD, processing the wave file and trying to calculate the FFT data. It didn’t really leave much time for then doing anything useful with the data.

:o The wav files I play were just standard ones generated in batch on the PC via a text to speech program. The output was trimmed as the default text to speech had like 2 seconds of silence on the start and end. Originally I’d use an external program to trim in batch, then got brave and did it in the same program that processes the text to speech.

As all the wav files I use are static and pieced together in the clock program I had the sudden idea to calculate the FFT data and interleave it with the wav data.

I have just finished implementing the initial test and it works great. For audio @ 11025 it adds about 1-2% to the size for 10 bands. The routine that processes the original wav file (in a vb.net program) is passed the number of bands you want and the framerate. It then creates a new file with the original wav data + the spectrum data interleaved. It’s no longer a .wav file and has a small header that allows the pcm code to read it and play while extracting the spectrum data.

I plan on tidying it up a lot and adding the option for per-channel audio spectrum and if people interested I’ll document it a bit better.

Small snippet of code… reading specrum data is now easy :slight_smile:

tm = millis() + 25000; // 25 second of sampling max

   static int p = 0;

  while (PCM.isPlaying()) // while playing AND has a timer
  {
       PCM.topUpBuffer();    // keep that buffer stuffed up  

	   show_leds();

	   if (millis() > tm) break; // long clip... so beak after 25 secs

	   if (PCM.m_spec_bands) // has spectrum data
	   {
		   fastDigitalWrite(pins[p], PCM.m_spec_data[p] > 30 ? HIGH : LOW); // test of the interleaved spectrum bands - led bar output
		   p++;
		   p &= 7;
	   }
	   
  }

use a math co processor?

I recall - http://playground.arduino.cc/Code/Fpu -

performance is not that great but I expect you should be able to offload some of the math?

Google for experiences.

Maybe this can help? Start watching at 34:56 for the FFT part.

https://youtu.be/wqt55OAabVs?t=34m54s

As you can see, it's able to read a stereo WAV file from the SD card while computing the 1024 point FFT and printing lots of numbers to the serial monitor. No coprocessor required. :)

At the moment I use a MCP4922 (off memory) to output 12 bit mono which, although better than the i2c DAC I had it's still relatively slow.

I'm considering a fast 8 bit parallel dac as I really can't hear the difference in sound quality on these speakers.

MCP4922 can be updated at SPI clock divisor = 4, so 2 MHz. Takes 17 clocks to send out a byte, so 8.5uS.

Two bytes can be sent out every 17uS, or 58,823 Hz. With good filtering that should be nice & clean audio-wise. Sending data out faster will not help.

CrossRoads: MCP4922 can be updated at SPI clock divisor = 4, so 2 MHz. Takes 17 clocks to send out a byte, so 8.5uS.

Two bytes can be sent out every 17uS, or 58,823 Hz. With good filtering that should be nice & clean audio-wise. Sending data out faster will not help.

It works fine, just wondering if it's overkill for what I'm doing. Sampling stereo @ 44100 from the SD on the Due and sending it through the dac and servicing the msgeq7 uses ~60% of the cpu at the moment. Trying to find a balance between quality and speed so I can do more fancy stuff in-between outputting samples and reading the SD :-)

Ideally I want my daughters robo-clock to look and sound a bit like Orac off Blakes 7.