design
intro
conclusions
results
schematics
source
work log
budget
Michael Karpelson, Julian Chang, ECE 476 Spring 2004

#include <Mega32.h>

#include <stdio.h>

#include <Math.h>

#include <delay.h>

#include <stdlib.h>

#include <ctype.h>

#include <String.h>

 

#define begin {

#define end }

#define tempo1           275        // Playback speed

#define sint           500        // Sampling interval

#define timeout         2000         // Sampling timeout

#define bdeb           50        // Debounce time

 

// Some useful note definitions

#define A        0x01

#define B      0x02

#define C      0x03

#define D      0x04

#define E      0x05

#define F      0x06

#define G           0x07

#define a      0x08

#define b      0x41

#define c      0x42

#define Ds     0x43

#define Fs     0x44

#define Gs     0x45

 

// Encoding for notes - bits 0-3

#define        NOTE_PAUSE        0b01000000

#define NOTE_A          0b00000001

#define NOTE_B               0b00000010

#define NOTE_C              0b00000011

#define NOTE_D               0b00000100

#define NOTE_E              0b00000101

#define NOTE_F              0b00000110

#define NOTE_G              0b00000111

#define NOTE_a               0b00001000

#define NOTE_b              0b01000001

#define NOTE_c               0b01000010

#define NOTE_DS              0b01000011

#define NOTE_FS         0b01000100

#define NOTE_GS         0b01000101

 

// Encoding for note length - bits 4-5

#define EIGHTH         0b00000000

#define QUARTER        0b00010000

#define HALF           0b00100000

#define FULL           0b00110000

 

// Encoding for chord/nochord - bit 7

#define CHORD          0b10000000

#define NO_CHORD        0b00000000        

       

// Song length

#define SONG_LEN        200

 

// Stored melody slots

eeprom char SONG_ONE[SONG_LEN] = {0};

eeprom char SONG_TWO[SONG_LEN] = {0};

eeprom char SONG_THREE[SONG_LEN] = {0};

eeprom char SONG_FOUR[SONG_LEN] = {0};

eeprom char SONG_FIVE[SONG_LEN] = {0};

eeprom char* songs[6] = {SONG_ONE, SONG_TWO, SONG_THREE, SONG_FOUR, SONG_FIVE};

 

// Random melody storage

unsigned char music[200];

                  

// TIME VARIABLES

int tempo = tempo1;

int dtime = 0;

int tout = 0;

int btime = 0;

 

// PITCH DETECTION VARIABLES

unsigned char data[1500];

unsigned char temp;

bit sready;

unsigned char dstring[6];        // Set of detected notes

char dscores[5];            // Scores for stored melodies matched to user input

 

// UART VARIABLES

unsigned char rtemp;

 

// INTERFACE VARIABLES

unsigned char lstop;          // Stop playback flag

unsigned char pflag = 0;        // Play started flag

 

// SOLENOID INTERFACE

char beat = 3;                 // Pulse width variable

int ptime = 0;                 // Playing time

char tinused;                  // Current timer interrupt used flag

 

// GENERAL VARIABLES

int i;                        // General index

 

// Markov probability tables (2 scales, 1 rhythm are defined)

//        A     B     C     D     D#    E     F     F#    G     G#    a     b     c

 

// Tone tables

flash char njump[26][13]={

        {0x05, 0x0a, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

        {0x04, 0x07, 0x0b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

        {0x03, 0x06, 0x09, 0x0c, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x03, 0x06, 0x09, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x03, 0x08, 0x00, 0x0a, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0x0c, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x09, 0x00, 0x0c, 0x0f, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x00, 0x0a, 0x0c, 0x0f, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x08, 0x0f, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0f, 0x0f, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x08, 0x0f, 0x0c, 0x0f},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x08, 0x0f, 0x0b, 0x0f},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x08, 0x0f, 0x0a, 0x0f},

                                                                                      

       

        {0x00, 0x05, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x05, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x05, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x09, 0x0f, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x05, 0x00, 0x09, 0x0f, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x09, 0x0f, 0x00},

        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x0f, 0x00}

        };

 

// Duration (rhythm) table

flash char djump[4][4]={

   {0x09,0x0c,0x0f,0x00},

   {0x03,0x0b,0x0f,0x00},

   {0x00,0x04,0x0d,0x0f},

   {0x00,0x02,0x06,0x0f}  

        };            

 

// Tone lookup tables

flash unsigned char tone0[9] = {0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

flash unsigned char tone1[6] = {0x00,0x80,0x40,0x20,0x10,0x08};

 

// Chord lookup tables

flash unsigned char chord0[6] = {0x00,0x00,0x14,0x54,0xa0,0x4a};

flash unsigned char chord1[6] = {0x00,0x00,0x00,0x00,0x40,0x00};

 

// FUNCTIONS

void playmusic(int p);

void playtone(char o, char t);

void playchord(char t);

unsigned char sample(void);

unsigned char listen(void);

void init(void);

char* getString(void); 

void printSong(char);

void commandLine(void);

void program(char);

char str2Note(char*);

void note2Str(unsigned char);

unsigned char PushState;

void randomgen(void);

void randomgen2(void);

void dplay(void);

unsigned char convert(unsigned char nin);

 

//

//        INTERRUPTS

//

 

// TIMER INTERRUPT    

interrupt [TIM0_COMP] void timer0_compare(void)

begin     

        // Playing time

        if (ptime>0)        --ptime;

        // Timer interrupt used flag to prevent race conditions during playback

tinused = 0;

        // Detection time (also used for debounce)

if (dtime>0) --dtime; 

        // Sampling timeout       

if (tout>0) --tout;

// Another debounce time

if (btime>0) --btime;

end 

 

// SERIAL INTERRUPT

interrupt [USART_RXC] void uart_rec(void)

begin

        // Detect input, run programming interface

         UCSRB.7=0;

        rtemp = UDR;

         commandLine();

end

 

 

//

//      MAIN METHOD

//

 

void main()

begin

        // Run initialization function

        init();

        // Main program loop

while(1)

begin

// Poll playback speed control button (with debouncing)

        if (~PIND.7) begin

                dtime = bdeb;

                while (dtime != 0);

                while (~PIND.7) ;

                // Adjust tempo

if (tempo < 500) tempo += 75;

                else tempo = 75;

                dtime = bdeb;

                while (dtime != 0);

        end

        // Poll pitch detection trigger button (with debouncing)

        if (~PIND.6) begin

                lstop = 0;

                tout = timeout;

                dtime = bdeb;

                while (dtime != 0);

                while (~PIND.6);

                pflag = 1;

                // Launch pitch detector

                 dplay();

                dtime = bdeb;

                while (dtime != 0);

        end

        end

end

 

//

// FUNCTIONS

//

 

// PITCH DETECTOR CONTROL

void dplay(void)

begin                     

        unsigned char sample;        // Stores one sample

char i, j, k, d;        // Array indices

        dtime = sint;

        // Acquire 1st note and start timeout counter

        while (dtime != 0) ;

                dstring[0] = listen();

        dtime = sint;

        while (dtime != 0) ;

        tout = timeout;

       

// NOTE: Due to the temperamental nature of the pitch detection mechanism, stable

        // performance could not be guaranteed during the demonstration and the regular

        // code (reproduced further below) was replaced by the segment immediately below

// which represents the proof of concept of the detector by taking one note as an
// input and interpreting it as a trigger to either play one of the five stored

// melodies or generate a random one.

        if (dstring[0] == B) playmusic(1);

        else if (dstring[0] == C) playmusic(2);

        else if (dstring[0] == D) playmusic(3);

        else if (dstring[0] == a) playmusic(4);

        else if (dstring[0] == b) playmusic(5);

        else randomgen2();

       

        // The deactivated code below represents the actual algorithm (performance

        // is somewhat unsteady)

        /*

        // Read more notes

for (i=1;i<5;i++)

        begin

                // Debounced push button input stops pitch detector

                if (~PIND.6 && pflag == 0) begin

                       lstop = 1;

while(~PIND.6);

dtime = bdeb;

while(dtime != 0);

break;

               end

               if (PIND.6 && pflag == 1) begin

                         dtime = bdeb;

while(dtime != 0);

                              pflag = 0;

                    end

                if (lstop != 0) break;

 

                // Take new sample

                dtime = sint;

                while (dtime != 0);

                sample = listen();

                if ((sample != 0)) dstring[i] = sample;

                if (tout == 0) break;

                     dtime = sint;

                while (dtime != 0) ;

                tout = timeout;

end

 

        // Compare notes to stored melodies

        if (i == 5 && lstop == 0)

        begin              

                // Cycle through read notes

                for (i=0; i<5; i++)

                begin

                       // Reset score and cycle through melody

                       dscores[i] = 0;

                       for (j=0; j<5; j++)

                       begin

                                  for (k=0; k<5; k++)

                                  begin

                               // Augment melody score if current note matches stored

                                  if (0x4f & songs[i+1][j] == dstring[k])

begin

dscores[i] += 1;

break;

end

                           end

                       end

                end

                // Determine highest score and play melody if score exceeds threshold

                d = 0;

                for (i=0; i<5; i++)

                       if(dscores[i] > dscores[d]) d = i;                    

                if (dscores[d] > 2) playmusic(d + 1);

                // Otherwise, generate and play random melody

                else randomgen2();

end */         

end     

 

// INITALIZER

void init(void)

begin

        // Pitch detection I/O controls ADC and reads from it

        DDRD = 0x0f;

        DDRB = 0x00;

        PORTD.2 = 1;

        PORTD.3 = 1;

        PORTD.4 = 1;

        PORTD.7 = 1;

        PORTD.6 = 1;

       

        // Solenoid control I/O

        DDRA = 0xff;

        PORTA = 0x00;

        DDRC = 0xff;

        PORTC = 0x00;

 

        // Timer0 ISR

          TIMSK=2;      

        OCR0 = 250;

        TCCR0=0b00001011;       

       

// Serial ISR and UART initializer

        UCSRB = 0b10011000;

        UBRRL = 103;   

       

//Enable the ISRs

        #asm

                 sei

       #endasm

 

        // Initialize certain flags 

        tinused = 0;

        lstop = 0;

end

 

// PITCH DETECTION SAMPLING

unsigned char listen(void)

begin              

        int i = 0;      // Array index

        int pi = 0;    // Previous peak

        unsigned char npeaks = 0;      // Number of peaks

        float freq;                  // Time between peaks

        int pflag = 0;                     // Peak detection flag

        unsigned char buffer = 45;     // Minimum peak duration

        unsigned char max = 0;                // Waveform maximum

        unsigned char min = 0xff;   // Waveform minimum

       

        // Wait for volume to exceed threshold

        while (sample() < 125) if (lstop != 0) break;

        if (lstop == 0) begin

                // Wait for waveform to stabilize

                for (i=0;i<15;i++)  delay_us(10000);

                       temp = sample();

                // Take 1500 samples

                if (temp > 100 && temp < 127) begin

                       for (i = 0; i < 1500; i++) data[i] = sample(); 

                   max = 0;

                          min = 0xff;

                        // Get waveform maximum and minimum

                   for (i = 0; i < 1500; i++)

                                     if (data[i] > max) max = data[i];

                   for (i = 0; i < 1500; i++)

                                if (data[i] < min) min = data[i];

                       // Expand waveform

                       for (i = 0; i < 1500; i++) begin

                                  data[i] -= min;

                                       if (data[i]*(0xff/(max-min)) < 0xff)

data[i] = data[i]*(0xff/(max-min));

                                       else data[i] = 0xff;

                               // Convert to square pulse (zero-crossing)

                                  if (data[i] > 0x80) data[i] = 0xff;

                                else data[i] = 0x00;

                        end

           

                       // Falling edge detection

                       pi = 0;

                        npeaks = 0;

                        freq = 0;

                        pflag = 0;

                // Cycle through samples array

                   for (i = 0; i < 1500; i++) begin

                       // Set flag for potential edge

                        if ((data[i] == 0xff) && (data[i+1] != 0xff) && (pflag == 0))

                                pflag = i;

                       // Clear flag for false edge

                        else if ((pflag != 0) && (i-pflag <= buffer) && (data[i] == 0xff))

                                pflag = 0;

                       // Record falling edge and average with previous values

                       else if ((pflag != 0) && (i-pflag > buffer)) begin

                      if (pi > 0) freq = (freq + (float)i - (float)pi)/2.0;

                                pi = i;

                                pflag = 0;

                                npeaks++;

                       end

                   end

                       // Return note associated with average waveform period

                        if ((freq < 116) && (freq > 109))           return c;

                          else if ((freq < 126) && (freq > 116))   return b;

                        else if ((freq < 140) && (freq > 129))   return a;

                       else if ((freq < 149) && (freq > 139))   return Gs;

                       else if ((freq < 156) && (freq > 148))   return G;

                       else if ((freq < 166) && (freq > 156))   return Fs;            

                       else if ((freq < 175) && (freq > 166))   return F;

                       else if ((freq < 184) && (freq > 175))   return E;

                       else if ((freq < 196) && (freq > 183))   return Ds;                                      

                       else if ((freq < 206) && (freq > 196))   return D;

                       else if ((freq < 229) && (freq > 210))   return C; 

                       else if ((freq < 240) && (freq > 229))   return B;

                       else if ((freq < 260) && (freq > 240))   return A;

                        else return 0x00;

                end

        end

end

 

// ADC CONTROLLER

unsigned char sample(void)

begin

        // Set ADC control bits and read value when ready

       PORTD.2 = 0;

        PORTD.3 = 0;

           while(~PIND.4);

        PORTD.3 = 1;

        PORTD.2 = 1;

        return PINB;

end

 

// SOLENOID PLAYBACK CONTROLLER

void playmusic(int p)

begin  

        // Note parameters and signal flags

        unsigned char tone, length, octave, chord, done, started, now;

        int i = 0;

        // Disable serial ISR during playback

        UCSRB.7=0;

        // Play random melody or one of five stored melodies

        if (p == 0) now = music[i];

        else now = songs[p][i];

        // Cycle through melody array until null terminator

        while (now != 0x00 && lstop == 0)

        begin     

                if (p == 0) now = music[i];

                else now = songs[p][i];

                // Decode tone, duration, octave, chord

                tone = now & 0x0f;

                length = ((now >> 4) & 0x03);

                if (length == 0) length = 1;

                else if (length == 1) length = 2;

                else if (length == 2) length = 4;

                else if (length == 3) length = 8;

                octave = (now >> 6) & 0x01;

                chord = (now >> 7) & 0x01;

                // Reset flags

                done = 0;

                started = 0;

                tinused = 0;

                // Play current note

                while (done == 0 && lstop == 0)

                begin

                       // Wait for timer ISR to play note 

                        if (started == 0)

begin

                              while (ptime != 0);

                                      if (chord == 0) playtone(octave, tone);

                               else playchord(tone);

                                     started = 1;

                            end

                               ptime = tempo;  

                // Delay the necessary amount of beats for note duration

                     while (ptime != 0);

                        // Stop everything on button push (debounced

                                if (~PIND.6 && pflag == 0)

begin

                                        lstop = 1;

while(~PIND.6);

dtime = bdeb;

while(dtime != 0);

break;

                                end

                                if (PIND.6 && pflag == 1) begin

                                               dtime = bdeb;

while(dtime != 0);

                                               pflag = 0;

                                end

                               // Decrement length parameter until enough beats pass

                               if (tinused == 0) begin

                                           tinused = 1;

                                         if (--length == 0) done = 1;

                                     end

                        end

                       // Prepare for next note

                        i++;

                end

        end

        // Reenable serial ISR

        UCSRB.7=1;

end

 

// SINGLE TONE PLAYER

void playtone(char o, char t)

begin

        // Use lookup tables to output pulse to solenoid

        PORTA = o ? 0x00 : tone0[t];

        PORTC = o ? tone1[t] : 0x00;

        for (i=0; i<beat; i++) delay_us(4500);

        PORTA = 0x00;

        PORTC = 0x00;

end

 

// CHORD PLAYER

void playchord(char t)

begin

        // Use lookup tables to output pulse to several solenoids

        PORTA = chord0[t];

        PORTC = chord1[t];

        for (i=0; i<beat; i++) delay_us(5000);

        PORTA = 0x00;

        PORTC = 0x00;

end

 

// SERIAL FUNCTIONS

/* fetches a line from serial communication */

char* getString()

begin

        char current_char; 

        char input_string[20];

        unsigned int count = 0;

 

        //retreive input from serial connection

        while ( (current_char=getchar()) != '\r' )  //carriage return

        begin    

                if (current_char == 0x08 || current_char == 0x7f)                          //backspace 

                begin

                       if(count > 0)

                       begin      

                               --count; 

                               putchar(current_char);

                               putchar(' ');

                               putchar(current_char);

                       end

                end

                else if(isprint(current_char))

                begin  

                       //echo

                       putchar(current_char);

                      

                       input_string[count++] = current_char;

                end

        end   

       

        //echo carriage return and place line feed.

        putchar('\r\n');                                   

 

        //null terminate string

        input_string[count]=0x00;    

       

        return input_string;                

end

 

/* start serial communications */

void commandLine()

begin

        char* input_string; 

        unsigned int length, i;

 

        /* disable interrupts    */

        #asm

                cli

        #endasm                 

 

        putsf("\r> Type 'Help' for help.\r");

 

        while(1)

        begin

                putchar('\r');

                putchar('>');

                putchar(' ');

 

                input_string = getString();

              

                length = strlen(input_string);

                for(i=0; i<length; i++)

                       input_string[i] = toupper(input_string[i]);

 

                if(strcmpf(input_string, "HELP") == 0)

                begin

                       putsf("\r> Available commands are PROGRAM, DISPLAY, HELP, QUIT.");

                       putsf("\r> Enter input as [NOTE/CHORD][DURATION][NOTE].");

                       putsf("\r> Available notes are A,B,C,D,D#,E,F,F#,G,G#,a,b,c.");

                       putsf("\r> Melodies can be up to 200 notes long.");

                end

                else if(strcmpf(input_string, "PROGRAM") == 0)

                begin         

                       while(1)

                       begin

                       putsf("\r> Please indicate song number: (1-5)\r");

                       putchar('>');

                       putchar(' ');

                       input_string = getString();   

                       putchar('\r');

                       putchar('>');

                       putchar(' ');

                       if(strlen(input_string) == 1 && input_string[0]>0x30

&& input_string[0]<0x36)

                       begin

                               program(input_string[0]);

                               break;

                       end

                       end

                end

                else if(strcmpf(input_string, "DISPLAY") == 0)

                begin 

                       while(1)

                       begin

                       putsf("\r> Please indicate song number: (1-5)\r"); 

                       putchar('>');

                       putchar(' ');

                       input_string = getString();            

                       putchar('\r');

                       putchar('>');

                       putchar(' ');

                       if(strlen(input_string) == 1 && input_string[0]>0x30

&& input_string[0]<0x36)

                       begin

                               printSong(input_string[0]); 

                               break;

                       end

                end

                end

                else if(strcmpf(input_string, "QUIT") == 0)

                begin       

                       break;

                end

                else

                begin

                       putsf("\r> Invalid Command. Type 'Help' for help.");

                end

        end

                      

        putsf("\r> Quitting... ");

       

        /* restore interrupts */

        #asm

                sei

        #endasm

        UCSRB.7 = 1;

 

end

       

/* prints song to serial communication */

void printSong(char songNum)

begin

        int k;

        unsigned char note; 

 

        //put note array into flash

        for(k=0; k<SONG_LEN; k++)

        begin

                note = songs[songNum-48][k];

                if(note == 0x00)

                       break;

                note2Str(note);

                putchar(' ');

        end  

        putchar('\r\n');

end

 

/* uses UART to program notes into MCU */

void program(char songNum)

begin

        char* input_string;

        unsigned char notes[SONG_LEN];

        int k=0;

 

        //parse input string into notes

        k = 0;

        while(k<SONG_LEN)

        begin            

                input_string = getString();

              

                if(strlen(input_string) == 0)

                begin

                       notes[k] = 0x00;

                       break;

                end

              

                notes[k] = str2Note(input_string);

                

                if(notes[k] == 0xff)            

                       putsf("\r> ERROR: Note is invalid.");

                else

                       k++; 

                      

                putchar('\r');

                putchar('>');

                putchar(' ');

    end

   

        //put note array into flash

        for(k=0; k<SONG_LEN; k++)   

                songs[songNum-48][k] = notes[k]; 

              

          putsf("\r> PROGRAM COMPLETE.");

end

     

/* outputs note to serial communication */

void note2Str(unsigned char note)

begin 

        switch((note & 0b10000000) >> 7)                 

        begin

                case 1: putchar('M'); break;

                case 0:        putchar('N'); break;

        end

              

        switch(note & 0b00110000)

        begin

                case FULL: putchar('F'); break;

                case HALF: putchar('H'); break;

                case QUARTER: putchar('Q'); break;

                case EIGHTH: putchar('E'); break;

        end

       

        switch(note & 0b01001111)

        begin      

                case NOTE_PAUSE: putchar('_'); break;

                case NOTE_A: putchar('A'); break;

      case NOTE_B: putchar('B'); break;

      case NOTE_C: putchar('C'); break;

      case NOTE_D: putchar('D'); break;

      case NOTE_E: putchar('E'); break;

      case NOTE_F: putchar('F'); break;

      case NOTE_G: putchar('G'); break;

      case NOTE_a: putchar('a'); break;

      case NOTE_b: putchar('b'); break;

      case NOTE_c: putchar('c'); break;

      case NOTE_DS: putchar('D'); putchar('#'); break;

      case NOTE_FS: putchar('F'); putchar('#'); break;   

      case NOTE_GS: putchar('G'); putchar('#'); break;

        end

end

     

/* encodes a string into a note */

unsigned char str2Note(char* in)

begin

        unsigned char output = 0x00;     

        char note[3];

        char chord = 0; 

       

        // invalid note - bad length

        if(strlen(in)<3 || strlen(in)>4)

                return 0xff;

              

        switch(toupper(in[0]))

        begin

                case 'M':

                       output = output | CHORD;  

                       chord = 1;

                       break;

                case 'N':

                       output = output | NO_CHORD;

                       chord = 0;

                       break;

                default:

                       return 0xff;

        end       

       

        switch(toupper(in[1]))

        begin

                case 'F':

                       output = output | FULL;

                       break;

                case 'H':

                       output = output | HALF;

                       break;

                case 'Q':

                       output = output | QUARTER;

                       break;

                case 'E':

                       output = output | EIGHTH;

                       break;

                default:

                       return 0xff;

        end

       

        note[0] = in[2];

        if(strlen(in) == 4) 

        begin

                note[1] = in[3];

                note[2] = 0x00; 

        end

        else

                note[1] = 0x00;

 

        if(strcmpf(note, "_") == 0)

        begin

                output = output | NOTE_PAUSE;

                if(chord)

                       return 0xff;

        end

        else if(strcmpf(note, "A") == 0) 

        begin

                output = output | NOTE_A;

                if(chord)

                       return 0xff;

        end

        else if(strcmpf(note, "B") == 0)

        begin

                output = output | NOTE_B; 

        end

        else if(strcmpf(note, "C") == 0)

        begin

                output = output | NOTE_C;

        end

        else if(strcmpf(note, "D") == 0) 

        begin

                output = output | NOTE_D;

        end

        else if(strcmpf(note, "E") == 0)

        begin

                output = output | NOTE_E;

        end

        else if(strcmpf(note, "F") == 0)

        begin

                output = output | NOTE_F;

        end

        else if(strcmpf(note, "G") == 0)

        begin

                output = output | NOTE_G;

        end

        else if(strcmpf(note, "a") == 0)

        begin

                output = output | NOTE_a;

                if(chord)

                       return 0xff;

        end

        else if(strcmpf(note, "b") == 0)

        begin

                output = output | NOTE_b;

                if(chord)

                       return 0xff;

        end

        else if(strcmpf(note, "c") == 0)

        begin

                output = output | NOTE_c;

                if(chord)

                       return 0xff;

        end

        else if(strcmpf(note, "D#") == 0)

        begin

                output = output | NOTE_DS;

                if(chord)

                       return 0xff;

        end

        else if(strcmpf(note, "F#") == 0)

        begin

                output = output | NOTE_FS;

                if(chord)

                       return 0xff;

        end

        else if(strcmpf(note, "G#") == 0)

        begin

                output = output | NOTE_GS;

                if(chord)

                       return 0xff;

        end

        else

                return 0xff;

              

        return output; 

end

 

// MARKOV CHAIN RANDOM MELODY GENERATOR

void randomgen2(void)

begin

        unsigned char note, dur, scale;

        char rnd;

        int i,j;

        // Use pitch detection note as starting point

        data[0] = dstring[0] | 0x10;

        // Pick a scale randomly

        scale = rand() ^ data[0];

        scale = (scale & 0x01) ? 0 : 13;

        dur = data[0] & 0x30;

        note = data[0] & 0x0f;

       

        // Generate music

for (j=1; j<200; j++)

begin

// Find new duration through probability table

                   rnd = 0x0f & rand();

               for (i=0; i<4; i++)

                          if (djump[dur][i] >= rnd) break;

               dur = (0x03 & (char)i) << 4;

               

                // Find new note through probability table

                rnd = 0x0f & rand();

                if (rnd == 0x00) rnd = 0x01;

                for (i=0; i<13; i++)

                   if (njump[note + scale][i] >= rnd) break;

                note = 0x0f & (char)i;  

               

                // Record new entry

                data[j] = dur | note;

        end

   

        // Convert to encoded format

           music[0] = data[0];

        for (j=1; j<200; j++)

                music[j] = 0x7f & ((0x30 & data[j]) | convert(0x0f & data[j]));

           music[199] = 0x00;

       

        // Play result

              playmusic(0);

end

 

// RANDOM GENERATOR OUTPUT TO STANDARD NOTE ENCODING CONVERTER

unsigned char convert(unsigned char nin)

begin

        // A B C D

        if (nin == 0x00) return (0x01);

        else if (nin == 0x01) return (0x02);

        else if (nin == 0x02) return (0x03);

        else if (nin == 0x03) return (0x04);

        // D#

        else if (nin == 0x04) return (0x43);

        // E F

        else if (nin == 0x05) return (0x05);

        else if (nin == 0x06) return (0x06);

        // F#

        else if (nin == 0x07) return (0x44);

        // G

        else if (nin == 0x08) return (0x07);

        // G#

        else if (nin == 0x09) return (0x45);

        // A

        else if (nin == 0x0a) return (0x08);

        // B C

        else if (nin == 0x0b) return (0x41);

        else if (nin == 0x0c) return (0x42);

        else return (0x00);

end