[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