Stereo guitar/bass cabinet emulation


Well-known member
Here is a next component for my audio effect library for Teensy4: Stereo guitar/bass cabinet emulation based on
Uniformly-Partitioned Convolution Filter by Brian Millier.
A PlatformIO and ArduinoIDE projects are available in the examples repo:

- 7 guitar cabinet IRs included
- 3 bass cabinets
- Stereo Doubler mode


I have played a bit with the stereo doubler function. Making a nice wide stereo track out of a single mono one, esp with harmonic rich distorted guitars is not a trivial task. There is ia few tricks used in the recording techniques. I have combined 3 of them to make the sound at least usable:
1. Use two copies of the same track, but delay one channel ~10..12ms. This unfortunately shifts the panorama to one side, since one channel is received earlier than the other one.
2. Another technique to shift the pan setting is tone control, lowpass a bit one channel, boost treble on the other - i have used this to compensate the shift created by the step 1.
3. Next trick used with reamping guitar tracks is to flip the phase, run it through the amp/mic, record it and flip the phase back. Stereo doubler flips the channel R phase before doing the convolution and restores it after. It creates a bit more decorellation between the L and R and helps with stereo image and the overall impact on the tone (comb filtering).

There is still quite a signifact tone change when the Doubler is on. The 2nd part of the video shows a direct comparson between two separatly recorded tracks, one mono and the same mono with Doubler enabled. I think it's quite usable and the low end loss is actually usefull within the mix.

Demo project is using the Tone Stack emulator run into the Speaker Emulation.

From one head banger to the sounds!
\m/ :)
More news: managed to port the Neural Network amp modeller from Seed by GuitarML (originally runs on STM32H7 i believe) to Tennsy, added a bunch of other stuff like:
- new Noise Gate with external side chain input. This way i was able to do the same trick as with hardware noise gates: grab the signal envelope before anything gain/distortion related and put the put the actual muting part after the amp emulation, but before the reverb.

- Spring Reverb, in stereo, but not very wide one. Original spring tanks are usually mono.

- Simple 3 band EQ. Initially i used the ToneStack emulation it did not sound good with the RTNeural amp sim.

Finally the amp modeller: these models are more like snapshots of particular gear settings. So the model already includes the Tone Stack present in the original circuit. Hence a simpler 3band EQ works better. After hours of playing i usually set to to flat response anyway. The amp models do sound good, react to playing techniques very nice. What i was also interested in is if these models do sound good with external FX, like fuzz/overdrive. They do!
There is still a bit of small issues to iron out, I'll post the project in the examples repo when ready.
Meanwhile a short track i recorded entirely with Teensy4 (plus one fuzz pedal to test the clean channel):
Yes, the signal chain used in that video was:
I2S->NoiseGate->AmpModeler->EQ->SpringReverb->StereoIR Cabsim->I2S
Load max about 80% with everything turned on.
Oh sorry, I only watched the first video and when I looked at the GitHub I didnt see the web interface you have in the second video. Really cool stuff man!
This is pretty amazing what you are doing Pio!

Have you tried models or IR's?
Yes, i know about tonehunt, however the NAM models are not compatible with this version of the component.
Any chance you will add a parametric EQ instead of the IRs?
IR cabsim can be bypassed or just imply removed. There is an EQ built into the SGTL5000 codec used on the TeensyAudioAdaptor. Just a matter of playing with I2C configuration. No DSP code needed.
Is it possible to use just the AmpModeler in a Arduino IDE sketch? I already have a working sketch that has eq and reverb, it would be cool to try out the amp modeler in it.
I tried, but failed for now. After getting all the path and includes correct Arduino somehow puts a lot of code into RAM1, exceeding the limit. No problems with Platformio.
Dang :( No wonder I couldn't get it to work... I also tried playing around with PlatformIO and couldn't get that to work. Ill just have to wait or spend more time in VS
What problems did you encounter with the PlatformIO?
I have just tested a fresh install of VScode + PIO on Win10, cloned project repo installed all the libraries and compiled fine.
There has been changes to the main library, clicking build does not pull all the changes, so it's important to click on the PlatformIO icon and then Dependencies/Update. This will git pull all the changes in the libraries.
More time in VS might be actually less if you count in the much quicker compile ;)
I played a bit with the Reaper's JS plugin engine. The new Amp Modeler example will include a JS controller plugin, doing pretty much the same as the html+webMDI, but with automation, MIDI clock sync and all the audio tools a DAW provides.

Success! After reading and playing around a bit more I got it working. The web control is very impressive. I really wish I could get this to work on Arduino so I can stick a parametric EQ in the chain. I think it would would be very useful. I also reallllly like your plate reverb! :D

Also, how do we control the audio shield's input and output levels? Looking around I see that I could potentially stick it in "main.cpp"? Thanks!
main.cpp is the main sketch, like *.ino file. The difference is you have to declare all functions before using them just as with regular c/c++ programming.
To add more controls via the web interface, using the codec input level as an example:
1. Decide which MIDI ControlChange number will be setting the gain. Let's make it 30.
2. In the ControlChange callback cb_ControlChange add case for the above value and put the volume controlling commands there. The input value for that callback is in range int 0-127 (raw CC value). I believe the Input Gain range for the SGTL5000 is 0-15...
3. Edit the .html file. Add rows or colums to format the layout if necessary.
4. <midi-encoder label="Input\nGain\n%p" chan="1" cc="30" colour="#B3E5FC" label-scale="0.8"></midi-encoder>
This will add a new "knob" with the InputGain label, sending CC30 on channel 1.

That's pretty much it. WebMidi is sending midi commands, sketch is receiving them and processing via callbacks.
Yes, delay and Reaper JS plugin are in.
I have changed the signal path a bit. The amp sim is mono, but i made the component to work a 2xmono one, summing the L+R inputs when on and sending the same signal to L+R output. However, when bypassed, the signal passing through is stereo. This way i can use the device either as an amp emulator or a stereo effect processor.
I think i'm going to add a stereo/mono switch for the amp emulator, though. Input signal is (L+R)/2, if the user is using a mono path only, the input will be halved reducing the gain range.

Besides that i think the project is pretty much complete, i'll just add physical knob controls for the hardware i'm using.
The goal was to make a kind of guitar amp emulation for silent recording or practicing using headphones:
- Few amp sims + noise gate and EQ
- Good quality stereo speaker emulation with the stereo doubler/enhancer option
- Something to add space in otherwise very acoustically dry headphone environment: reverb
- Versatile delay, which also creates a nice stereo signal plus, it can be a chorus, flanger or semi rotary speaker emulator.

Assuming there is a non true bypass pedal in the chain providing a HiZ instrument input, the simplest form of hardware could be just Tennsy4.1 with installed PSRAM and the audio adapter board.
Does the delay require the PSRAM? My teensy doesn’t have it and I didn’t notice any issues, but I was using the version before you added delay. I also have the guitar plugged straight into the audio shield and it works surprisingly well. I’ll try it with a buffer I have in the parts box… hopefully it will run off 5v.

Also, do the settings save after shutdown? Can I use just a usb power cable without the web control?
Version with Delay requires PSRAM, although you can change it using the delay constructor. Default settings are 400ms in RAM2.
I've set it to 1sec in PSRAM:
AudioEffectDelayStereo_F32 echo=AudioEffectDelayStereo_F32(1000, true); // 1 sec delay, buffer in PSRAM;
Passing false will place the buffers in RAM2, although with everything else it will be too much i think. Play with the delay time until the buffers fit into the RAM2.
Settings are not saved - good idea, i'll try to implement it.

Buffer with 5V supply - ideally it would use a rail-to-rail opamp, ie something from Microchip's MCP600x series. LineIN on SGTL5000 has about 30k input impedance, a bit too low for guitar. Might shift the resonant peak and darken the sound a bit. Unless you have active pickups, in that case it should be ok.
Ive played around a bit more with your last update. I had actually ordered a PSRAM chip when I bought the Teensy so I decided to solder that on. The delay works well on my T4.1 and Audio board. I played around with adding a Boss TU-2 in and out of the circuit and I *THINK* I hear added high end - but it's very slight. Im using a humbucker guitar straight into the Teensy, and straight out to a QSC K10. I find all the cab IR's very dark. I usually have treble turned all the way up and the bass all the way down (even with the buffer). The lead amp models have internal feedback on my setup, even with the guitar turned off. Im not sure if you experience that too.
Im on a mac and am using Chrome - The text on the bottom of the webUI, that shows the cpu usage, etc., has only worked twice for me. Its usually blank down there and I don't know why!!

Ive never heard of the MCP600x chips before, all the buffers I have use TL071/72 chips. I have a 5v to 12v converter coming in the mail so Ill see if I can fit it in the box I made:

I made... a teensy little box... for the teensy. Pretty cool how small this is! Thanks for this project
Nice build!

The difference between an unbuffered (LoZ, under 100k) and bufferred input (>300k-1M) won't be very drastic, usually it's the top end where various overtones live. With clean sound it might be only slightly noticeable. With distortion, the lack of top end usually makes the palm muting a bit blunt, without a sharp attack. Some pedals, like fuzzes explicitly use lower input Z to shape the sound. All is a matter of taste. I'm often using more distorted sounds, so i generally prefer to preserve the mid/top band.

Speaking of buffers and opamps there is a whole world of them beyond TLxxx series. The MCP600x or similar CMOS Rail-Rail ones will have a lot more headroom than the TL071/2 if used with lower supply voltage like 5V.

Using the Lead amp i too have noise and a bif of whining tone. Not sure if is an internal feedback or kind of clock sub-harmonic getting audible due to huge input gain. Noise gate is there to remove that noise. I'm experiencing the same using the NAM VST plugin.

Regarding the status update using webserial, do you reconnect after uploading a new firmware or resetting the board? It works pretty much every time on my setup (Linux + Chromium). One issue i have with it is after connecting Teensy to the WebSerial the Teensy loader can't initiate the upload. I have to either press the program button or disconnect the WebSerial and refresh the page.
I have also notced that:
- if the Teensy is connected via WebSerial
- upload initiated and Program button pressed
- after reset the Teensy will show up with a new TTY device (jumps between ttyACM0 and ttyACM1)
Maybe that's the problem? Does the Teensy show on the SerialPort list when you open it?

because of the headroom and potential clipping problems the 3band EQ emulates a passive one. That is, the response is flat when all knobs are at 100%. EQ can only attenuate bands. All bands at 100% is also the default setting at start. I keep the Treble+Mid usually at 100% and remove a bit of bass. Actually i think i'll add a dedicates high pass filter. I have it on my 2nd IR cabsim using teensy4.0 and it really helps with too much low end producing by some of the IRs.