// Sound program (for 4MHz MCU) #pragma warn- #include #define begin { #define end } #define Song0 0x00 #define Song1 0x10 #define Song2 0x20 #define Song3 0x30 #define Song4 0x40 #define Song5 0x50 #define Song6 0x60 #define Song7 0x70 #define Off 0x80 /* Notes, frequencies and timer 1 matches at CLK 0 Pause 1 G3 196 319 2 G#3/Ab3 207.65 301 3 A3 220 284 4 A#3/Bb3 233.08 268 5 B3 246.94 253 6 C4 261.63 239 7 C#4/Db4 277.18 225 8 D4 293.66 213 9 D#4/Eb4 311.13 201 10 E4 329.63 190 11 F4 349.23 179 12 F#4/Gb4 369.99 169 13 G4 392 159 14 G#4/Ab4 415.3 150 15 A4 440 142 16 A#4/Bb4 466.16 134 17 B4 493.88 127 18 C5 523.25 119 19 C#5/Db5 554.37 113 20 D5 587.33 106 21 D#5/Eb5 622.25 100 22 E5 659.26 95 23 F5 698.46 89 24 F#5/Gb5 739.99 84 25 G5 783.99 80 26 G#5/Ab5 830.61 75 27 A5 880 71 28 A#5/Bb5 932.33 67 29 B5 987.77 63 30 C6 1046.5 60 31 C#6/Db6 1108.73 56 32 D6 1174.66 53 33 D#6/Eb6 1244.51 50 */ register unsigned char sample @4; register unsigned char note @5; register unsigned char time @6; register unsigned char state @7; register unsigned char temp @8; register unsigned char temp2 @9; unsigned char length[8]={185,143,111,104,72,178,139,243}; // Song lengths // Music arrays, first array is the notes, second array is the note lengths (in 32ms chunks) flash unsigned char song0[2][185]={{22,17,18,20,18,17,15,0,15,18,22,20,18,17,18,20,22,18,15,0,15,20,23,27,25,23,22, 18,22,20,18,17,0,17,18,20,22,18,15,0,15,0,22,17,18,20,18,17,15,0,15,18,22,20,18, 17,18,20,22,18,15,0,15,20,23,27,25,23,22,18,22,20,18,17,0,17,18,20,22,18,15,0, 15,0,10,6,8,5,6,3,2,5,10,6,8,5,6,10,15,14,0,22,17,18,20,18,17,15,0,15,18,22,20, /* Russian Bloc song */ 18,17,18,20,22,18,15,0,15,20,23,27,25,23,22,18,22,20,18,17,0,17,18,20,22,18,15, 0,15,0,22,17,18,20,18,17,15,0,15,18,22,20,18,17,18,20,22,18,15,0,15,20,23,27,25, 23,22,18,22,20,18,17,0,17,18,20,22,18,15,0,15,0}, {12,6,6,12,6,6,11,1,6,6,12,6,6,18,6,12,12,12,12,1,23,18,6,12,6,6,18,6,12,6,6,11, 1,6,6,12,12,12,12,1,23,3,12,6,6,12,6,6,11,1,6,6,12,6,6,18,6,12,12,12,12,1,23, 18,6,12,6,6,18,6,12,6,6,11,1,6,6,12,12,12,12,1,23,3,24,24,24,24,24,24,24, 24,24,24,24,24,12,12,24,48,3,12,6,6,12,6,6,11,1,6,6,12,6,6,18,6,12,12,12,12,1, 23,18,6,12,6,6,18,6,12,6,6,11,1,6,6,12,12,12,12,1,23,3,12,6,6,12,6,6,11,1,6,6, 12,6,6,18,6,12,12,12,12,1,23,18,6,12,6,6,18,6,12,6,6,11,1,6,6,12,12,12,12,1,23, 100}}; flash unsigned char song1[2][143]={{21,0,21,20,18,20,21,23,16,18,13,20,21,23,25,27,28,27,25,23,27,25,23,21,25,23, 21,20,23,20,18,16,18,20,21,18,20,21,23,0,23,25,27,25,23,0,23,25,27,28,27,25,23, 27,25,23,21,25,23,21,20,23,20,18,16,18,20,21,18,20,21,23,0,23,25,27,23,28,23, /* Bub & Bob */ 25,26,27,23,25,27,28,23,25,27,30,23,25,27,32,28,30,32,33,0,33,32,30,32,0,32,30, 25,32,30,23,25,26,27,23,25,27,28,23,25,27,30,23,25,27,32,28,30,32,33,0,33,32, 30,32,0,32,30,23,32,23,32,28,0}, {24,1,24,8,16,8,16,8,32,24,24,16,24,24,24,24,8,8,12,4,8,8,8,8,8,8,4,12,24,4,4,8, 8,8,8,8,8,8,8,1,8,8,8,8,8,1,8,8,8,8,8,12,4,8,8,8,8,8,8,4,12,24,4,4,8,8,8,8,8,8, 8,8,1,8,8,8,8,8,8,8,8,40,8,8,8,40,8,8,8,40,8,8,8,40,8,8,8,24,1,16,8,16,48,1,16, 24,24,16,40,8,8,8,40,8,8,8,40,8,8,8,40,8,8,8,40,8,8,8,24,1,16,8,16,48,1,16,24, 16,8,8,8,64,100}}; flash unsigned char song2[2][111]={{13,18,13,15,17,10,0,10,15,13,11,13,6,0,6,8,0,8,10,11,0,11,13,15,17,18,20,13,22, 20,18,20,17,13,18,17,15,17,10,0,10,15,13,11,13,6,0,6,18,17,15,13,22,20,18,17,18, 20,13,0,13,18,17,15,13,15,17,10,0,10,18,15,17,18,15,17,18,15,18,23,0,23,22,20, /* Commie Song */ 18,20,22,18,0,18,20,18,17,15,17,18,15,0,15,18,17,15,13,6,0,6,13,15,17,18,0}, {7,21,14,7,21,10,1,10,21,14,7,21,10,1,10,20,1,14,7,21,1,10,10,21,14,7,42,7,21, 14,7,21,11,10,21,14,7,21,10,1,10,21,11,10,21,10,1,10,21,14,7,42,42,11,10,11,10, 30,11,1,42,42,11,10,11,10,30,11,1,42,21,14,7,21,14,7,21,11,10,42,1,42,11,10,11, 10,30,11,1,42,42,11,10,11,10,30,11,1,42,21,11,10,21,10,1,10,42,21,21,56,100}}; flash unsigned char song3[2][104]={{16,11,0,11,16,14,12,14,16,12,0,12,16,15,13,15,16,11,16,0,16,18,20,21,23,0,23, 24,26,28,0,28,0,28,26,24,26,24,23,0,23,21,0,21,23,24,23,21,19,0,19,21,23,22, 20,18,0,18,20,22,25,23,16,11,16,0,16,18,20,21,23,0,23,24,26,28,31,30,27,23,24, 28,27,23,0,23,24,28,27,23,20,21,24,23,19,16,18,0,18,20,22,25,23,0}, /* Link's Song */ {50,10,1,10,10,5,5,80,50,10,1,10,10,5,5,80,20,30,10,1,5,5,5,5,60,1,7,6,7,50,1, 10,1,7,6,7,15,5,60,1,20,10,1,5,5,40,10,10,10,1,5,5,40,10,10,10,1,5,5,40,20,80, 20,30,10,1,5,5,5,5,60,1,7,6,7,60,20,20,60,20,60,20,20,40,1,20,60,20,20,40,20, 60,20,20,40,20,10,1,5,5,40,20,80,100}}; flash unsigned char song4[2][72]={{8,10,12,13,15,16,17,0,17,0,17,0,17,0,17,13,22,21,22,13,15,17,18,20,22,21,23,22, 13,20,19,20,13,15,17,18,19,20,13,23,22,13,25,0,25,0,25,0,25,27,25,23,0,23,0,23, 0,23,25,23,22,15,18,23,22,0,22,0,22,17,18,0}, /* Underwater */ {9,9,9,9,9,9,4,1,4,1,8,1,8,1,22,6,27,27,31,5,5,5,5,4,27,27,5,58,5,27,27,31,5,5,5, 5,4,27,27,5,58,5,26,1,26,1,26,1,9,13,5,26,1,26,1,26,1,9,13,5,26,9,9,9,4,1,4,1,13, 5,27,100}}; flash unsigned char song5[2][178]={{13,0,13,0,13,0,13,9,0,9,13,0,13,0,13,0,13,9,0,9,13,0,13,0,13,9,16,13,9,16, 13,20,0,20,0,20,21,16,12,9,16,13,25,13,25,24,23,22,21,22,14,19,18,17,16,15,16,9, 12,9,13,16,13,16,20,25,13,25,24,23,22,21,22,14,19,18,17,16,15,16,9,12,9,16,13, 9,16,13,0,13,0,13,0,13,0,13,12,0,12,13,0,13,0,13,0,13,21,0,21,13,0,13,0,13,9, 16,13,9,16,13,20,0,20,0,20,21,16,12,9,16,13,25,13,25,24,23,22,21,22,14,19,18, 17,16,15,16,9,12,9,13,16,13,16,20,25,13,25,24,23,22,21,22,14,19,18,17,16,15, 16,9,12,9,16,13,9,16,13,0}, /* Cornell Death March */ {19,1,19,1,14,1,5,10,1,9,19,1,19,1,14,1,5,10,1,9,20,1,19,1,19,15,5,20,15,5,40, 20,1,19,1,19,15,5,20,15,5,40,20,20,20,15,5,5,5,25,5,20,15,5,5,5,25,5,20,15,5, 20,15,5,40,20,20,20,15,5,5,5,25,5,20,15,5,5,5,25,5,20,15,5,20,15,5,40,1,19,1,19, 1,14,1,5,10,1,9,19,1,19,1,14,1,5,10,1,9,20,1,19,1,19,15,5,20,15,5,40,20,1,19, 1,19,15,5,20,15,5,40,20,20,20,15,5,5,5,25,5,20,15,5,5,5,25,5,20,15,5,20,15,5, 40,20,20,20,15,5,5,5,25,5,20,15,5,5,5,25,5,20,15,5,20,15,5,40,100}}; flash unsigned char song6[2][139]={{11,0,11,0,11,16,23,21,20,18,28,23,21,20,18,28,23,21,20,21,18,16,23,21,20,18,28, 23,21,20,18,28,23,21,20,21,18,11,0,11,13,0,13,21,20,18,16,0,16,18,20,18,13,15, 11,0,11,13,0,13,21,20,18,16,23,18,0,18,11,0,11,13,0,13,21,20,18,16,0,16,18,20, 18,13,15,23,0,23,28,26,24,23,21,19,18,16,23,11,0,11,13,16,21,11,0,11,16,23,21, 20,18,28,23,21,20,18,28,23,21,20,21,18,16,23,21,20,18,28,23,21,20,18,28,23,25, 23,25,27,0}, /* The Jedi Song */ {5,1,5,1,5,36,36,5,5,5,36,18,5,5,5,36,18,5,5,5,54,36,36,6,6,5,36,18,6,6,5,36,18, 6,6,5,54,12,1,5,23,1,8,8,8,8,8,1,6,5,5,13,5,18,12,1,5,23,1,8,8,8,8,8, 12,5,1,36,12,1,5,23,1,8,8,8,8,8,1,6,5,5,13,5,18,12,1,5,8,8,13,5,8,8,13, 5,54,12,1,5,30,8,18,12,1,5,36,36,6,6,5,36,18,6,6,5,36,18,6,6,5,54,36,36,6,6,5, 36,18,6,6,5,36,18,6,6,5,54,100}}; flash unsigned char song7[2][243]={{10,11,13,18,8,10,11,13,15,17,23,15,17,18,20,22,10,11,13,18,20,22,23,13,0,13,22, 20,13,22,20,13,22,20,13,22,20,10,11,13,18,8,10,11,13,15,17,23,15,17,18,20,22,10, 11,13,18,20,22,23,13,0,13,22,20,13,22,20,13,22,20,13,22,20,10,13,11,8,11,10,13, 22,10,13,11,8,11,10,13,22,20,22,23,20,23,21,20,18,0,18,21,20,13,12,13,20,13,12, 13,20,18,17,18,10,13,11,8,11,10,13,22,10,13,11,8,11,9,8,6,10,13,11,8,11,10,13, 22,20,22,23,16,15,16,23,16,15,16,23,21,20,18,20,22,23,16,15,16,23,16,15,16,21, 0,21,23,25,10,11,13,18,8,10,11,13,15,17,23,15,17,18,20,22,10,11,13,18,20,22,23, 13,0,13,22,20,13,22,20,13,22,20,13,22,20,11,12,14,19,9,11,12,14,16,18,24,16,18, 19,21,23,11,12,14,19,21,23,24,14,0,14,23,21,14,23,21,14,24,23,21,24,23,21,19,0}, /* Indy */ {10,5,8,22,10,5,48,10,5,8,42,10,5,15,15,15,10,5,8,42,10,5,48,10,1,5,15,10,5,15, 10,5,15,10,5,8,8,10,5,8,42,10,5,48,10,5,8,42,10,5,15,15,15,10,5,8,42,10,5,48,10, 1,5,15,10,5,15,10,5,15,10,5,8,8,10,5,48,10,5,5,5,42,10,5,48,10,5,5,5,42,10,5,48, 10,5,5,5,47,1,8,8,8,4,4,8,8,4,4,8,8,4,4,48,10,5,48,10,5,5,5,42,10,5,48,10,5,5,5, 42,10,5,48,10,5,5,5,48,8,8,8,4,4,8,8,4,4,8,8,4,4,48,8,8,8,4,4,8,8,4,4,8,8,1,4,4, 48,10,5,8,42,10,5,48,10,5,8,42,10,5,15,15,15,10,5,8,42,10,5,48,10,1,5,15,10,5, 15,10,5,15,10,5,8,8,10,5,8,42,10,5,48,10,5,8,42,10,5,15,15,15,10,5,8,42,10,5,48, 10,1,5,15,10,5,15,10,5,15,10,5,15,10,5,80,100}}; // Note frequencies unsigned int notes[34]={65535,319,301,284,268,253,239,225,213,201,190,179,169,159,150,142,134,127,119,113,106,100, 95,89,84,80,75,71,67,63,60,56,53,50}; // 64 sinewave samples unsigned char sine[64]={0x80,0x8C,0x98,0xA4,0xB1,0xBB,0xC5,0xCF,0xDA,0xE1,0xE8,0xEF,0xF6,0xF8,0xFA,0xFC, 0xFF,0xFC,0xFA,0xF8,0xF6,0xEF,0xE8,0xE1,0xDA,0xCF,0xC5,0xBB,0xB1,0xA4,0x98,0x8C, 0x80,0x73,0x67,0x59,0x4F,0x44,0x3A,0x30,0x26,0x1F,0x18,0x11,0x0A,0x07,0x05,0x02, 0x00,0x02,0x05,0x07,0x0A,0x11,0x18,0x1F,0x26,0x30,0x3A,0x44,0x4F,0x59,0x67,0x73}; // Timer 0 overflow clocked at CLK/1024 (overflow every 32.64ms) #pragma savereg- interrupt [TIM0_OVF] void timer0_overflow(void) begin #asm("in r9,SREG") if(state <= Song7) // If song is playing begin time++; // Increment times switch(state) begin case Song0: // If note is over if(time == song0[1][note]) // Play the next note begin TCCR1B = 0; time = 0; if(++note == length[0]) note = 0; temp = song0[0][note]; end break; case Song1: if(time == song1[1][note]) begin TCCR1B = 0; time = 0; if(++note == length[1]) note = 0; temp = song1[0][note]; end break; case Song2: if(time == song2[1][note]) begin TCCR1B = 0; time = 0; if(++note == length[2]) note = 0; temp = song2[0][note]; end break; case Song3: if(time == song3[1][note]) begin TCCR1B = 0; time = 0; if(++note == length[3]) note = 0; temp = song3[0][note]; end break; case Song4: if(time == song4[1][note]) begin TCCR1B = 0; time = 0; if(++note == length[4]) note = 0; temp = song4[0][note]; end break; case Song5: if(time == song5[1][note]) begin TCCR1B = 0; time = 0; if(++note == length[5]) note = 0; temp = song5[0][note]; end break; case Song6: if(time == song6[1][note]) begin TCCR1B = 0; time = 0; if(++note == length[6]) note = 0; temp = song6[0][note]; end break; case Song7: if(time == song7[1][note]) begin TCCR1B = 0; time = 0; if(++note == length[7]) note = 0; temp = song7[0][note]; end break; end if((time == 0) && (temp != 0)) // Reset the timers begin TCNT1 = 0; OCR1A = notes[temp]; TCCR1B = 9; end end TCNT0 = 128; #asm("out SREG,r9") end // Timer 1 compare match run at CLK, updates sine wave sample interrupt [TIM1_COMPA] void cmpA_overflow(void) begin #asm in r8, SREG mov r30, r4 inc r4 clr r31 subi r30, low(-_sine) sbci r31, high(-_sine) ld r30, z out 0x18, r30 ldi r30, low(64) cp r30, r4 brne PC+2 clr r4 out SREG, r8 #endasm end // External interrupt (commands from the game board) interrupt [EXT_INT0] void external_int0(void) begin #asm("in r9,SREG") TCCR1B = 0; // Turn off timer 1 TCCR0 = 0; // Turn off timer 0 TCNT1 = 0; TCNT0 = 0; TIFR = 0; sample = 0; note = 0; // Reset everything time = 0; state = PIND & 0xf0; // Get the command from Port D switch(state) begin case Off: OCR1A = 0xffff; break; case Song0: OCR1A = notes[song0[0][0]]; break; case Song1: OCR1A = notes[song1[0][0]]; break; case Song2: OCR1A = notes[song2[0][0]]; break; case Song3: OCR1A = notes[song3[0][0]]; break; case Song4: OCR1A = notes[song4[0][0]]; break; case Song5: OCR1A = notes[song5[0][0]]; break; case Song6: OCR1A = notes[song6[0][0]]; break; case Song7: OCR1A = notes[song7[0][0]]; break; end if(state != Off) // If command is not "Off" begin // Start playing the new song TCCR1B = 9; TCCR0 = 5; end #asm("out SREG,r9") end #pragma savereg+ void main(void) begin DDRB = 0xff; // Port B connects to the DAC PORTB = 0x80; DDRD = 0; // Port D pins connected to game board (except 0 and 1) PORTD = 0xff; // Enable pullups sample = 0; note = 0; // Reset everything time = 0; state = Off; // Initial state is sound off GIMSK = 0x40; // Enable external interrupt 0 MCUCR = 3; // Rising edge on pin D.2 triggers interrupt OCR1A = 0xffff; TCNT0 = 128; TCNT1 = 0; TCCR0 = 0; TCCR1B = 0; // Reset timers TIMSK = 0x11; // Turn on timer 0 overflow, timer 1 match #asm("sei") // Enable interrupts while(1) {} // Loop (program run from interrupts) end