The approach taken here is to find the the 3rd order transfer function and apply the bilinear transform to obtain direct form II digital filter coefficients, and use a standard DFII filter algorithm. This is done directly in the C code. No tables are used. Abruptly changing the filter coefficients in real-time may cause discontinuities in the response and may show up as "zipper noise." However I haven't discerned any audible zipper noise. Your milage may vary. Please let me (dtyeh at hotmail.com) know if you can hear them.
An alternate approach provided is to tabulate the digital filter coefficients for different settings of the controls (a 25 x 25 x 25 matrix) and use the Gray-Markel algorithm (tf2latc in Matlab) to convert the 3rd order direct form coefficients to a lattice filter implementation. While not implemented here, this has the advantage of being able to fade smoothly between different coefficient sets using multidimensional interpolation. (An efficient choice would be 3-D linear interpolation, see Numerical Recipes in C for multi-dimensional linear interpolation). In addition, lattice structures are well suited for fixed point implementation because their coefficients are nicely behaved and more easily quantized.
While the coefficients given here are for the 1959 Fender Bassman tone stack, most tone stacks (Fender, Marshall, Vox) are the same circuit with different component values for the capacitors and resistors, or different relationship between the controls and the resistances. You can find the schematics on the web for the particular amp whose tone stack you want, find the resistor and capacitor values and plug in to the code.
General Tone Stack Approach
The formulas given in the paper are specific to the Bassman/Marshall circuit. I will post formulas for the other amps when I get around to it.
Second-Order-Section Approximation and Implementation
The treble resistor represents a fade between a high pass capacitor and the 2nd order section below. This information can be used to divide the circuit into second order sections (one ends up being first order) for implementation on fixed point systems. From experimentation in simulation, it seems that the second order section is typicaly isolated from the high pass filter section, and the equivalent loading when separated can be calcuated by circuit analysis (I'm verifying that this approach works before I post it).
Apparently the frequency response of the tone stack makes a big different in the perceived feel of the amp. See the Tone Stack Mods link.
The choice of the 1959 Bassman was inspired by the book Circuit Analysis of a Legendary Tube Amplifier: The Fender Bassman 5F6-A by Richard Kuehnel.
Tone Stack patents
There are a couple of patents/applications regarding digital simulation of the tone stack.
Curtis, Dale V., Chapman, Keith L., and Adams, Charles, C. Simulated tone stack for electric guitar. US Patent number 6,222,110. Filed June 15, 2000, granted Apr. 24, 2001.
- Gallien, Robert. A., Robertson, Kevin. A. Programmable tone control filters for electric guitar. US Patent application US2007/0168063. Filed Jan. 18, 2006. Published Jul. 19, 2007.
They measure actual tone stacks, and fit filters to the measured response, using 3-D linear interpolation to reduce the table size. This approach is a practical one for digitizing a bunch of different, real tone stacks by measuring them in the lab..
Claim that accurately modeling phase response is novel work and that this is important. Claim full analysis is too complicated to be practical. Therefore they come up with a really clever approximate circuit model that incorporates and implements the parameter controls. Then SPICE is used to provide a point of calibration for the control.
DownloadsProvided for archival purposes. Current version of CAPS (0.4.2) includes the tone stack plugins.
- CAPS 0.3.0 by Tim Goetze (CAPS Home Page), need this to apply tone stack patch.
- Patch to CAPS 0.3.0 code to add tone stack. Matlab code included.
Instructions to use patchtar xzf caps-0.3.0.tar.gz
patch p0 < patch_caps-0.3.0_tonestack.diff