[sdiy] MIDI state machine for arpeggiator
Matthew Smith
matt at smiffytech.com
Sat Feb 28 06:43:37 CET 2009
Hi Folks
I am minded to build myself a little monophonic synth/organ thingy.
Dual oscillator - one takes a detune, but both receiving the same note
data. As I've got spare pins and timers on the microcontrollers I'll be
using, I'm going to bring out 1, 2, and 3 octaves below the requested note.
Each output of each uC will have its own choice of straight square wave
or integrated square wave. All of these outputs go into a mixer. The
whole lot then goes into filters as yet to be decided. If there's a
VCA, it will only be on an LFO, no ADSR as I'm more after the on/off of
a pipe organ.
The digital side will consist of 3 Freescale 'Nitron' uCs, nice little
16-bin DIP jobbies. One for each oscillator, one as a MIDI filter plus
arpeggiator (the assigner.) I'm going to try to keep the code as
processor-neutral as possible so that it can be adapted for other
platforms (at least those platforms with the same number of timers. Or
you could just lose octave outputs I suppose.)
Assigner will receive MIDI input, work out what's relevant and then pass
note on/off messages to the oscillators. So as the oscillators don't
need to know about what MIDI channel the thing is listening on (that's
the assigner's job,) they will receive note on/off messages to MIDI
channel one, minus the velocity byte.
At the end of this message there is a little fragment of C (if I
remember to paste it!) - I would appreciate any comments on the finite
state machine that I'm using to filter the incoming MIDI stream.
Thought I should get this in now when people are still thinking
arpeggiators from this morning.
Many thanks to those who responded on the synth/organ thread, by the
way. This is what I had in mind all along and I still don't know if it
counts as a synth or an organ!
Cheers
M
unsigned char state=0; // State machine state.
unsigned char channel=0; // MIDI channel 0x00 to 0x0F
/*
* state_machine() is called when the
* UART receives a byte.
*/
void state_machine(unsigned char i)
{
unsigned char r;
r=repeater(); // Handle timing or reset stuff.
if (r)
{
if (state==0) // Awaiting command.
{
if (i==(0x80 & channel))
state=1; // Note off received.
elsif (i==(0x90 & channel))
state=3; // Note on received.
}
else if (state==1) // Note off.
{
if (i<128)
{
arp_del(i); // Remove note from arp queue.
state=2; // Wait for velocity data.
}
}
else if (state==2) // Note off data.
{
if (i<128) // Ignore velocity.
{
state=0;
}
}
else if (state==3) // Note on.
{
if (i<128)
{
state=4; // Wait for velocity data.
}
}
else if (state==4)
{
if (i<128 && i>0) // Ignoring velocity.
{
// Add to arp queue only if note has velocity!
arp_add(i);
state=0;
}
}
}
}
/*
* Check for and send on MIDI clock, start, stop,
* continue and reset.
*/
void repeater(unsigned char i)
{
if (i==0xF8 || i==0xFA || i==0xFB || i==0xFC || i==0xFF)
{
midi_send_byte(i);
if (i==0xF8)
{
tick(); // Increment the arpeggiator counter.
}
else if (i==0xFF)
{
system_reset();
}
return(0);
}
else
{
return(1);
}
}
/*
* Handle a MIDI-initiated reset.
*/
void system_reset(void)
{
// Do something to clear out the arpeggiator.
}
/*
* Pointers in arpeggiator buffers
* incremented.
*/
void tick(void)
{
}
More information about the Synth-diy
mailing list