Synthesizer project using Line6 Tonecore dev kit
I picked up a Tonecore DSP Developer Kit a while back. For $200 you get a DSP dev kit in a guitar pedal form factor that has all the capabilities of Line6's Tonecore pedal line. I had the idea to do some sort of frequency detection algorithm with it. No specific goal or effect in mind, just figured if you can detect the pitch you can do a lot. So that's what this writeup is about. It will probably turn out to be a synthesizer of some sort.
The Tonecore dev kit is a great deal for the price but it has a couple sharp edges. Debug facilities are limited to outputting four words to the host processor (which shows up in the GUI tool they provide). I believe there are internal pins for a JTAG interface but no official support for this (and JTAG debuggers are expensive). Also, despite what the ads say it isn't practical to develop in C for this platform. Straight assembly is the way to go.
Because of this you need to be careful about how you go about development of complicated effects. You don't want to prototype an algorithm on-target -- it will take you years to get it right. The approach I'm taking is to prototype using PyLab, a loose collection of Python libraries aimed at data processing and graphing. This is essentially a homebrew alternative to Matlab, an industry standard for signal processing design. By prototyping in a powerful environment I can get all the kinks worked out of my design and debug only implementation details on-target. At least that's the theory.
I did a little digging and found that some octave pedals use a simple method of pitch detection. Essentially they threshold the signal and calculate the period between where the signal crosses from positive to negative ("zero-crossing"). This is essentially what I'm doing except I'm using a decaying threshold to find the peak crossings in each cycle. Once you can mark off the beginning of each cycle you can calculate the period and therefore you know the frequency of the signal at that point. At least that's the idea...
As you can see it isn't working perfectly yet. The main issue here was that I assumed the waveform would be symmetrical. As it turns out, that's not necessarily true. By tracking both positive and negative amplitudes I can account for this.
Ah, much better. It's stable enough to sound reasonable and adaptable enough to track normal pitch changes (e.g. bends). Abrupt changes in pitch or noise result in a bit of warbling (see the last note in the above graph).
The ToneCore pedals use a Freescale 56364 DSP and are programmed in assembly code. Motorola's 563xx DSP line has been around for a long time so it's easy to find example code for it. The DSP runs at 100 MHz. With a sample frequency of 39kHz this gives us about 2500 instructions per audio sample. Should be plenty for this project. For more info on the internals of the ToneCore pedal see this FAQ
There weren't any real surprises in porting the Python code to assembly. I copied the main detection routine from my Python script into my assembly code as a set of comments and just added the equivalent assembly code underneath it. This made it easy to keep the Python algorithm and the DSP implementation in sync. I did screw up some comparison instructions.
Currently I've got it outputting a square wave (it's dead easy) and have the option to octave double or halve. There is some instability in the frequency output that is noticeable when the octave is halved. I may need stronger frequency filtering when this option is turned on.
One flaw in the detection is it doesn't deal with chords well. If you play two notes it is easily confused and may oscillate between the two notes. It would be nice to be able to prevent this. A correlation routine may be a better idea since it could pick out several frequency peaks and output multiple tones.
Here is a sample showing the effect with various octave settings.