WAYNE CHORA-TONE PROJECTOR DIY // JC MAILLET (c) 2016,2023

William Wayne designed an interesting contraption that aimed to de-synchronize the output of (synchronous, ie., Hammond) tone-wheel organs; that is, to produce a chorusing effect. It is said that Jimi Hendrix played thru a (vacuum tube based) unit manufactured by Baldwin sometime in Seattle with amp-tech/guru Dave Weyer and liked its sound texture. It was marketed as the CHORA-TONE PROJECTOR (CTP). In his time he patented several different circuit design approaches to produce his intended effect.

When I first started on this I thought it might not be too hard to embody the key CTP effect “mechanism” using slightly more modern solid-state resources than Wayne might have had at the time (good/better op-amps, SPICE software, etc …). In the process of “trans-cloning” the original circuit I eventually started to wonder how we could make the oscillator variable in speed and depth and thus understand further how we could use the effect in a more general effect (guitar/bass/keys) setting. The output filters that split the audio (organ) band into sections is gone and the phase-rotator effect is applied to the whole audio band. In that respect it’s a little bit different than Wayne’s original idea but turns out to sound very chorus-ey nonetheless … maybe it sounds fuller than what Baldwin had, I’m not sure

Even up until quite recently I was trying to figure out how to do this strictly using analog means – that’s the part that turned out to be impossible. My last attempt involved triple-ganged pots (purchased on eBay two years ago) to run an op-amp based 3-phase ring-oscillator. It worked to a degree but, mainly, the outputs never achieved balanced symmetry between phases despite my best efforts. Even with 1% resistor and diode matching the outputs varied too much in amplitude. Plus, like any ring oscillator the whole works needs a kicker switch to get the ring moving (perfect for steam punking, I know). So, I officially give up – the only thing that holds promise for an all-analog solution is an obscure idea by Barry Gilbert and I’m gonna leave that one for another lifetime perhaps. I even built a Finite State Machine version to see what a square wave 3-phase oscillator would do for the circuit (it allowed better fine tuning of the lattice actually).

What is left in terms of providing variable speed and depth are my two mixed-signal designs I did with TEK465B – my partner in crime for about two years where he assisted in helping me design digital-PWM circuits besides some of the analog-PWM stuff I was doing on my side (eg., like a 4016 based PWM Univibe) // … indeed, I went thru a PWM circuit design phase and explored the limitations and applicability of switched-resistor circuits for a few years – but I digress. This is probably the right way to go, as the perfromance on this side of the equation is very good.

One version of my AVR-CTP circuit does the mixing using a matched trio of NSL32-SR3 opto-couplers thru an op-amp and the other does the same via CD4016 analog gates. Despite the seeming simplicity of the gate version I prefer the feel of the opto version and this is the version I’m offering here.

Indeed, the controller part is from a programmable digital AVR module, which allows a time-linear PWM duty cycle variation in 0.39% increments for each time staggered phase output … this 8-bit 42khz embodiment we’re presenting produces a time sweep that’s fine enough incrementally to produce a desired channel attenuation without incurring zipper noise in the process …


CIRCUIT RUNDOWN

There are three main sections to the circuit:

(I) the PSU runs off a 9vac/1A adapter and supplies +7.5v, -7.5v for the thee dual op-amp chips and +5v to the AVR module

(II) the CONTROLLER part generates three 0-5v PWM outputs running at 42khz that vary in sync relative to each other as a linear 3-phase oscillator, with an LFO range of .1hz to 20hz … the outputs have triangle shaped duty cycle cycling in time and the circuit uses three 5k linear pots to control the SPEED, DEPTH and VERTICAL-OFFSET of the PWM outputs … notice that unlike a lot of similar PWM circuits out there I am driving the opto-couplers directly with PWM signal (thru a 10k current limiting resistor) // there is NO need for some kind of DC conversion filter here since the opto cell performs an averaging function that is already built into the physics of the cell material …

(III) the SIGNAL path is designed with pro (high level signal) applications in mind – that is, unlike a standard chorus pedal for example, it can handle 10Vpp signal levels (and more) without issue … the signal path presented here runs exclusively on op-amps that are configured for low gain (unity) which translates into low noise and low circuit offsets … the low offset/gain part means we can DC-couple as much as we want …

This particular AVR based approach produces well-behaved performance provided well-matched opto-couplers are present … which reminds me, 20k trimpots can be used in lieu of the current limiting 10k resistors to the opto-LEDs – potentially for adjusting against opto-cell mismatch (which I have not really explored much myself) // … tho, for more easily achieved results results, the first choice here would be to use the same series resistance (10k) and match the opto-cells as closely as possible using the current-DMM approach described below …


DESIGN NOTES:

this version of Wayne’s idea was designed to operate with two separate TUBE amplifiers (preferably Tweed Bassman and early Marshalls), not exactly as the original Baldwin units were but not that different either … rather, I’m coming more from an old-school tube-amp effects loop where the preamp and output stage were merely/typically split open and connected to shorting jacks (yielding a potentially large SEND signals – no problem with some digital gear) … as most know modern versions of this so-called FX-LOOP drops the SEND signal level so that low-level (non-pro level) pedals can be used, and then amplified back up on the RETURN // I understand some people’s need for this but I avoid it like the plague … of course, this version of the CTP circuit can always be used in front of the amp but the way I had it was going between two amplifiers with the same kind of loop and using a Y-chord to split the signal going out of the main amp and using the output stage of the second amp as slave

in this respect notice the absence of input and output DC blocking caps // which need to be included on the amp side, and usually are // this circuit is ground referenced by nature and so is totally compatible directly with the input up front or a LOOP RETURN going into the capacitor preceding the output stage of a tube amp (or other amp) … you can also operate it this way as a “pedal” up front and obtain that much more fidelity (my $0.02 here) … either way, in general I tend to do away with un-necessary signal caps when I can – takes away any unwanted coloration or filtering and just leaves me with a flat form of the effect … if you feel like you need ’em go ahead and put ’em in …

again, it can be configured and used as a stomp-box except there’s no mono-mixing possible here, you still need two amplifiers as the effect is created spatially in the room from two sets of speakers like the ROLAND Jazz-Chorus amplifiers do … electronic wet-dry mixing to mono will create a tremolo effect, not what is intended here

==

ABOUT THE LATTICE …

recap, the heart of the circuit revolves around the 120 degree constant phase shifter lattice (see Darlington’s paper) … in my build the 810pF cap is replaced by 820pF and 450 ohm resistor by 470r … there is also a question I have about the 50r driving point impedance(s) … maybe others can explore this further

the crucial part consist of “mixing” them in time so that we have a linear through-zero phase rotator effect … this is different than back-and-forth phasor, chorus and flanger effects … it’s a different animal altogether

===

some photos of my build …

MATCHING OPTO-COUPLERS

the NSL32-SR3 opto-cells can easily be matched using a two-point approach … take note of cell resistance at 10uA (set using 9v battery, 1Meg pot and DMM), and at 1mA (set using 9v battery, 25k pot and DMM) … from a lot of twenty or so couplers take the three that have closest low-R/high-R value pairs … btw, this is a LOT easier (statistically probable) than trying to score three perfectly matched jFET’s … to give an example, my cells had low-R values of 200r, 190r, and 187r

I forget how to program the PRO-MINI AVR’s but I’m sure all you young tech-savy programers out there can do this in your sleep …

===

The CODE for the AVR was written by TEK465B and supported by myself …

3-phaseLFO-Increase-freq

/*3-phase oscillator
This circuit generate a triangle shaped PWM to digital output 3 6 and 11 with 120° phase delay.
analog input 0 is frequency control (0.1hz to 20hz)
Analog input 1 is Depth control(0% to 100%)
Analog input 2 is OffSet control (min = -100 %, middle = 0% max = 100%)
By Tek465B
*/

//This set the input and output pin number and the analog input poll time
#define Out1 3
#define Out2 6
#define Out3 11
#define FPot 0
#define DPot 1
#define OPot 2
//#define interval2 50

//This set the start position and the direction
byte ch1 = 0;
int ch1O = 0;
byte ch2 = 170;
int ch2O = 0;
byte ch3 = 170;
int ch3O = 0;
int d1 = 1;
int d2 = 1;
int d3 = -1;
//This set the Depth at minimum and offset at middle.
volatile byte PWM = 0;
volatile int Offsetv = 0;

//this is used for the state machine
//unsigned long currentMillis;
//unsigned long previousMillis = 0;

//Variables for storing the analog input reading.
int Freq = 0;
int Freq1 = 0;
int FreqDebounce = 0;
int Depth = 0;
int Offset = 0;

//This store the value for the speed control
long interval;

void setup() {
// put your setup code here, to run once:
//This set the PWM frequency for pin 3 and 11
noInterrupts();
TCCR2B = TCCR2B & B11111000 | _BV(CS20);
TCCR0B = TCCR0B & B11110000 | _BV(CS00);
// this set Phase correct PWM for timer0
TCCR0A = TCCR0A & B11111101 | _BV(WGM00);
//This disable the millis function(overflow interrupt)
TIMSK0 &= ~_BV(TOIE0);
//cbi(TIMSK0, TOIE0);
//This set the timer1 for timer interrupts

TCCR1A = 0;
TCCR1B = _BV(WGM12) | _BV(CS11);
TCNT1 = 0;
OCR1A = 20000;
//TCCR1B |= (1 << WGM12); //TCCR1B |= (1 << CS11); TIMSK1 |= (1 << OCIE1A); interrupts(); } //This Set the Digital output PWM ISR(TIMER1_COMPA_vect) { analogWrite(Out1, ch1O); analogWrite(Out2, ch2O); analogWrite(Out3, ch3O); //Counter for the trianglewave if ((ch1 == 255) && (d1 == 1)) { d1 = -1; } if ((ch1 == 0) && (d1 == -1)) { d1 = 1; } if ((ch2 == 255) && (d2 == 1)) { d2 = -1; } if ((ch2 == 0) && (d2 == -1)) { d2 = 1; } if ((ch3 == 255) && (d3 == 1)) { d3 = -1; } if ((ch3 == 0) && (d3 == -1)) { d3 = 1; } ch1 += d1; //This set the PWM according to the Depth and offset control ch1O = FMap(ch1, PWM, 5, PWM); ch1O += Offsetv; ch1O = constrain(ch1O, 0, 255); ch2 += d2; ch2O = FMap(ch2, PWM, 5, PWM); ch2O += Offsetv; ch2O = constrain(ch2O, 0, 255); ch3 += d3; ch3O = FMap(ch3, PWM, 5, PWM); ch3O += Offsetv; ch3O = constrain(ch3O, 0, 255); } void loop() { // put your main code here, to run repeatedly: //currentMillis = millis(); //Polling of the analog input //if (currentMillis - previousMillis > interval2) {
//previousMillis = currentMillis;
//This read the speed control and store its value into Freq variable.
Freq1 = analogRead(FPot) + 1;
if(Freq1 < (FreqDebounce - 1) || Freq1 > (FreqDebounce + 1)) {
FreqDebounce = Freq1;
//this use a logarithmic to make it a bit more human useable/linear.(output a value from 0 to 300)
Freq = 100 * log10(Freq1);
//This is to invert the value so clockwise = faster(300=0, 0=300).
Freq = 301 – Freq;
//mapping our value to the timer interrupt value.
interval = map(Freq, 0, 300, 196, 39216);
//When a change in speed is detected we temporarly disable interrupts and we set the counter 1 back to 0 and write the new interrupt(speed) value.
if(interval != OCR1A) {
noInterrupts();
TCNT1 = 0;
OCR1A = interval;
interrupts();
}
}
//This read and set the Depth control value
Depth = analogRead(DPot);
PWM = FMap(Depth, 255, 7, 255);
//This read and set the offset control value
Offset = analogRead(OPot);
Offsetv = FMap(Offset, 255, 7, 510);
//}

}

//Function to map number quickly
int FMap(int in, int out, int inr, int sel)
{
return ((in * (out >> 3)) >> inr) + ((255 – sel) >> 1);
}

===

LET ME KNOW IF YOU BUILD THIS
donations for this work greatly appreciated (PP: jc AT lynx DOT net)

… THANK-YOU!!!!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.