In earlier posts I’ve alluded to the second half of my midiCV box, a hardware pitch and amplitude tracker that would allow me to play my 303 in unison with my bass. Before anyone gets too excited it’s not all there yet, but it’s finally starting to come together and as I need to put it on the back burner for a while I decided now was a good time document it. The dream was and still is to be able to play my double bass, pick out the pitch and amplitude in real time and use my homemade Arduino controlled cv generator to control my 303. Both the double bass and the 303 are inherently slidey beasts and as control voltages have a real advantage over midi in that arena so in my head it seemed like the next logical step after building a CV box. At first I thought all this would be easy and to be honest if I had known how difficult and time consuming this project was going to be I probably would have stopped right there and got on with other more pressing elements of my PhD. More fool me ….
The motivation for doing pitch tracking using hardware rather relying on the ubiquitous laptop MaxMSP combination was twofold. Firstly I really like the idea of freeing myself, the double bass and x0x box from the computer; just plugging the double bass piezo mic into the cv box and going for it. Secondly I tried pitch tracking in Max and I couldn’t get good results for bass. The zerox~ object which counts zero crossings is pretty lousy and my normal go to object for pitch tracking, Tristain Jehan’s port of Miller Puckette’s fiddle~ doesn’t perform well with low frequencies. In fact any FFT based approach is likely to be disappointing for bass due to the fact that to accurately track low frequencies you need large sample sizes which incur enough latency to make the whole thing miserable.
Googling about bass pitch trackers brings up all kinds of academic papers featuring algorithms you haven’t got a cat in hell’s chance of running on an Arduino with latencies low enough or hardware I can’t afford and ouputs MIDI (why play a fretless instrument and use MIDI to drive an analogue synthesizer?). Having read in Sound on Sound magazine about the old roland SPV355 pitch to voltage box and googling around the subject enough to discover the ems pitch to voltage synth I knew there had to be a hardware design that was at least half decent enough to be fun to play.
My first idea was to count zero crossings, or more precisely count the time between them. This lead to a bit of googling which dug up this interesting rf audio demodulator which feeds the the signal through a voltage divider set close to the logical bandgap to trigger the external interrupt on an atmel ATmega8. After building and testing a circuit that fed my double bass’s signal through an overblown op-amp and then used zener diodes to regulate it back down to a 0 to 5 V square wave I realised that zero crossings were not really what I wanted. Using the time between zero crossings to calculate the period only works for sine waves and what I really needed was to measure the time between peaks in the waveform. I’d like to claim this blast of inspiration was my own but in reality it was googling for hours looking for guitar tuner circuits. The straight dope came from this excellent article on electronicdesign.com. This circuit is pretty simple which is why I like it so much, the signal gets filtered a bit then fed to an envelope follower. This then gets potted down to 90% of its original voltage value and compared with that of the signal straight from the filter. Whenever the waveform’s voltage is in its top 10% the compartor goes high and the rest of the time it’s low. After building roughly the same circuit as that on electronicdesign.com I got a nice digital looking pulse with the time between pulses corresponding to the frequency of the incoming signal. This signal swung between +/- 15 V (as this was what was driving the op-amp rails) which I didn’t particularly fancy feeding the external interupt on my Arduino but it only took a diode and potential divider to format this signal to 0 to 5 V range. I adapted the circuit a bit so that the envelope followers output gets buffered, smoothed and fed into one of the Arduino’s analogue inputs, that takes care of the amplitude part of the signal tracking.
At this point it was time to start reading up on how to get the Arduino to accurately measure times on a sub millisecond scale. To get enough resolution to detect the difference between 200 and 201 Hz I would need to be able to measure time in 25 microsecond increments. The Arduino comes with millis() a function for how many milliseconds since you turned it on and delayMicroseconds() for putting it to sleep for a brief while but you can’t measure short (sub millisecond) periods of time without creating your own timer using internal interrupts driven from a sub division of the Arduino’s 16MHz clock. Luckily uchobby.com has a resource that borders on the sublime side of brilliant for this kind of stuff so it wasn’t too hard to set up the arduino so that on external interrupts from the circuit board the time since the last interrupt is stored.
From there the rest is just maths and coding. I wrote a simple algorithm for bonk (note onset) detection and some fancy bits to try and filter octave jumps due to shifting harmonic strengths (more on these later). The code has to be fairly efficient given the strain the internal timer code puts on the CPU so I skipped any floating point maths and saved a load of processor time by using a precomputed lookup table stored in program memory for converting a period reading into a pitch control voltage. Doing all this gave me a new respect for the people who coded on 68K processors like the Amiga back in the day and before when efficiency was really valued and sloppy brute force methods didn’t cut it. In short I felt like the man.
By now I had a box that was wonderful at telling me the frequency and amplitude of sine waves from a test signal generator but how would it fare with signals from my bass? The answer is pretty well if it wasn’t for those damn harmonics. Basically it seems that the ratio between the strengths of the fundamental and first harmonic changes enough on different notes on different strings to produce results that are accurate to pitch class but can vary in octave. This is most obvious on the E and A strings where after being played the reported period suddenly doubles as the first harmonic dies away leaving the fundamental to dominate. On the plus side it plays in tune and is responsive to slides and hammer ons which is one real short fall of commercial units (or so I read in the forums).
I had anticipated harmonics were going to be a bitch so I had built into the input a two stage low pass filter comprising of one pole low pass filter with its filter cutoff at 50 Hz and 4 pole harmonic killer kicking in at 200 Hz. I think this shallow role off on the lower notes is the reason they are more prone to octave jumping while the D and G strings seem better behaved. Either way having read a bit more on how the ems worked I figure my next design is going to have to feature an adaptive low pass filter that tracks with the fundamental. The easiest way I can figure to do this is to use a bank of band pass filters tuned at least half an octave apart each feeding an envelope follower going into the Arduino which can then decide where the lowest frequency energy lies and tune a VCF using a CV from the DAC. If it wasn’t the fact I have a shed load of other work on I would get stuck straight into it but as it stands I’m going to leave it a month or two before picking this back up. As such I will leave you with a circuit diagram, a link to the arduino sketch and a silly video showing the fun results of singing into the device.
For anyone whose interested in the midi-to-CV side of the box I would/will post a circuit diagram if/when I can be bothered, but to be honest with you it’s as simple as wiring inputs on the chip straight up to the digital outputs on the Arduino, supplying it power and wiring the outputs to jacks, I didn’t even bother buffering it given the low current draw from my x0x’s CV inputs. The only extra circuitry I used was to bypass the power supply with capacitors as the datasheet advised.