Appendix: Source Code
#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