Forum Rule: Always post complete source code & details to reproduce any issue!
project planning for teensy 3.6 audio convolution
I've recently purchased a teensy 3.6 and the audio board. I modified some example code and I have it passing the left audio input to a small FIR filter then out to the left and right outputs, straight to the headphone jack. That's just the barest start to my intended purpose! I was encouraged by Chip's hearing aid project and Frank's software defined radio. They both prove that it should be possible to build what I want. The end-goal is to be able to read an impulse response from the SD card and convolve it with the incoming audio with minimal latency. This will be used for guitar amplifier cabinet simulation.
So I guess I'm going to have way too many questions. I'll get started!
1) is the FIR filter coefficient limit on the audio library really 200? Is that based on a software limitation or the hardware that was available at the time?
2) Do FIR filters have equal frequency spacing like FFT? If they don't, how to I use a huge audio wav impulse (essentially 8800 samples) to generate a much smaller number of FIR coefficients? I looked for octave code and played with a few graphical filter designers on the internet but they were all geared toward very specific and steep filter applications, not the wacky curves I'd like to generate.
3) Several sources on the internet suggest that for a convolution over a given number of points, FFT convolution is superior to FIR methods. I've read threads about the difficulty using DMA and the CMSIS libraries. Is there a straightforward way to get started? I suppose I can copy Frank's code and modify it to suit my needs but I'm still confused as to how to convolve a wav file in ram with the incoming audio. I'm fine with truncating the impulse down to 1024 or 2048 points and it would even be ideal to be able to vary the portion of the IR used in order to compare the sound with different numbers of points. Ideally, I want to use the smallest reasonable size that sounds "right" and leave processor overhead for other things.
I don't expect anyone will be able to say "do this and this and here's the code to do it!" I am hoping for suggestions to point me in the right direction as I now have too many different things to consider!
Thanks all, keep up the good work.
quick update- I'm able to read the wav file in Octave but I'm not so sure how I can parse 8000 odd points down to something that'll work for my application. I guess I will just grab the first 200 or so for now and see what happens and how it sounds.
Next step will be modifying Frank's code to read a longer set of coefficients. Again, I'll use the first 1024 or 2048 points from the impulse, burned into the micro.
Third step would be getting it to read those same points directly from the wav file on the SD card.
Another hurdle would be optimizing the code to use better DSP libraries and reduce the processing time and power.
Please feel free to point out any flaws in my logic!
sounds like a nice project!
Just some thoughts:
- I am not sure where exactly you would get the impulse response from? If you have the coefficients of the desired filter on the SD card, just read them into the memory on start-up of the Teensy, do an FFT of these coefficients once, store the results in a mask_buffer and use them for the complex-multiply after the FFT and before the inverseFFT. Thatīs all. You only need to do the FFT of the FIR coeffs once.
- A real time 8192 point FFT-iFFT with low latency is a contradiction in itself ;-). If you have 44.1ksps sample rate, you will need 8192 / 44100 = 186 milliseconds to gather all the samples until you can start your FFT, so your latency is at least 186 milliseconds (more, if you have overlap, see below)
- you have no limits on FIR filter size. But the Teensy has limits in processing power. Depending on the amount of overlap of the input samples in your FFT-iFFT chain (I use 50% in the Teensy Convolution SDR), you can have up to 4093 taps in your FIR filter with a 8192 point FFT. But thatīs surely at/beyond the limits of the Teensy processing power. I worked with 4096pointFFT and 2049 FIR filter coeffs which turned out fine. Also take into consideration to decimate before the FFT, that saves power. However, if you do a FIR filter in the time domain (which you would not want with such high no. of coefficients), you are -as far as I know- limited to 200 coefficients (which is perfectly fine, because such a huge and mighty filter is more than enough in the time domain and you would choose frequency domain filtering, if your filter exceeds about 80 coeffs anyway)
- you have to activate the FPU in the Teensy and modify the Teensyduino setup to allow for the new CMSIS DSP library in order to work with fast hardware floating point processing. Chip and others have shown that convolution (FFT-iFFT) does not work with acceptable audio results with int16 math. You will find an explanation how to do that compiled by Jan in the Teensy Convolution SDR thread
- a suggestion to start would be: take the relevant parts of the Teensy Convolution SDR code for calculating the FFT for the filter mask (once in setup), for queuing the audio and for the FFT and iFFT. Then try if audio comes through without the complex multiply and with the complex multiply.
- if you succeed in speeding up the processing, I (and probably Chip and others also ;-)) would be very happy!
Good luck with your project!
Have fun with the Teensy 3.6,
Thanks for the reply. It's super late here and I just got in bed but I'll say that the samples of a standard guitar audio impulse are the coefficients.
There are quite a few commercial products (hardware and software) that are able to use speaker cabinet impulses as long as 500ms with minimal latency. How are they doing that!?
Wait a sec, found a link. Partitioned convolution:
OK, will talk tomorrow. Thanks again.
Correct, that why I would not use FFT approach for this type of application.
Originally Posted by DD4WH
Also, real-world impulse response functions tend to contain poles and zeros, so FIR (purely zeros) would not be appropriate or would be very inefficient.
So I would not try to stick with FIR and therefore FFT processing.
Spent some time looking at the SDR code. It appears that the Teensy does a large (4096) FFT on the impulse then uses that FFT to generate a smaller (1024 or something) set of FIR filter coefficients. Am I tracking that correctly? I think I'm still confused by the terminology. It would seem there are quite a few ways to skin this cat, even though to code to do it appears to be rather concise.
Another DSP question regarding FFT convolution vs FIR filtering. I had thought that adding small delays, resonances and phase shifts is part of what makes a convolution speaker simulator (or reverb) sound "real." Will the above method, as used in the SDR, still do this?
I guess the proof is in building and testing it.
I have a commercial product that does more or less what I'd like to do but has frustrating form factor and other limitations. I plotted a sweep on my HP 3562A- I'm an old school analog guy so yeah, I embrace the classic HP dinosaurs! Anyway, usually the 3562A on automatic resolution mode can work its way through an audio band filter in a couple minutes. The enclosed plot of said commercial product with one of my favorite impulses took around an hour!
Somehow all those little dips and troughs and the aforementioned delays, resonances and phase shifts really amount to what makes a guitar sound "right." Preamps and distortion and all of that stuff can be modelled pretty convincingly in the analog domain but convolution is far and away the best way to simulate a speaker.