// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // midi.c - main program for Tiny Synth open project // Copyright (C) 2006 miguel angel labolida // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // implemented with AT89C2051 with 24 MHz and 2k(800h) flash memory // MIDI input is controlled by the serial interface associated to // timer 1 in mode 2 (8 bits auto reload). // The digital oscillator (DCO) frequency is controlled by the // timer 0 in mode 1 (16 bits without auto reload). // compiled with sdcc --no-pack-iram //__code char versn[] = {"_Midi109_"}; // adapt to Tiny 4 ATOM - Leds //__code char versn[] = {"_Midi110_"}; // sample buffer //__code char versn[] = {"_Midi111_"}; // ASR envelope signal __code char versn[] = {"__Midi112__"}; // AR envelope signal #include <8051.h> // standard 8051 header #include #define INT_DISABLE (EA = 0) // disable interrupts #define INT_ENABLE (EA = 1) // enable interrupts #define UCHAR unsigned char #define NOTE_ON 0x90 // midi command note on #define NOTE_OFF 0x80 // midi command note off // pin 6 P3_2 INT0 portamento // pin 16 to 19 P1_4 to 7 vave out #define BUTTON_WAVE P3_1 // pin 3 wave select button #define LED_1 P3_3 // pin 7 INT1 indicator LED 1 #define LED_2 P3_4 // pin 8 T0 indicator LED 2 #define LED_3 P3_5 // pin 9 T1 indicator LED 3 #define LED_4 P3_7 // pin 11 indicator LED 4 #define AR_REF P1_0 // pin 12 AR envelope reference(+) #define AR_LEV P1_1 // pin 13 AR envelope comparator(-) static void dco_ini(void); static void dco_int(void) interrupt 1 using 2; static void midi_ini(void); static void midi_int(void) interrupt 4 using 1; static __data UCHAR input_byte; // input byte MIDI interface static __data UCHAR midi_state; // parser automata state static __data UCHAR note_curr; // current note number static __data UCHAR note_next; // future note number static __data UCHAR note_count; // note on counter static __data UCHAR frqdiv_lo; // freq.divider timer 0 low static __data UCHAR frqdiv_hi; // freq.divider timer 0 high static __data UCHAR wave_current; // index current wave 0 to 3 static __data UCHAR wave_sample[16]; // waveform sample table static __data UCHAR wave_buffer; // wave sample and envelope buffer // bits 7 - 4 wave high to low // bit 3 ASR - bit 2 AR // bit 1 input comp - bit 0 refer. static __data unsigned char toggle; // DEBUG #include "freq.c" // frequency divider table #include "wave.c" // waveform table // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void main() { static __data int wave_debounce; // debounce counter __data unsigned char i; // table notes index midi_ini(); dco_ini(); IT0 = 1; // portamento wave_current = 0; // default waveform LED_1 = 0; // initialize default led LED_2 = LED_3 = LED_4 = 1; // initialize leds memcpy(wave_sample, wave_table[0], // load default sample wave sizeof(wave_sample)); wave_buffer = 0x03; // initialize AR ASR A0 A1 high z while(1) { if (IE0) // INT0 portamento { IE0 = 0; if (note_next > note_curr) { note_curr ++; i = (note_curr - 29)*2; // index of note table frqdiv_lo = note29[i+1];// freq.divider timer 0 low frqdiv_hi = note29[i]; // freq.divider timer 0 high } if (note_next < note_curr) { note_curr --; i = (note_curr - 29)*2; // index of note table frqdiv_lo = note29[i+1];// freq.divider timer 0 low frqdiv_hi = note29[i]; // freq.divider timer 0 high } } if ((! BUTTON_WAVE) // wave selection button on && (! wave_debounce)) // debounce complete { wave_debounce = 500; // load counter wave_current ++; // change wave index wave_current &= 0x03; // truncate memcpy(wave_sample, // store waveform wave_table[wave_current], sizeof(wave_sample)); LED_1 = LED_2 = LED_3 = LED_4 = 1; // initialize leds switch(wave_current) // preparing { case 0: LED_1 = 0; break; // wave leds indicators case 1: LED_2 = 0; break; case 2: LED_3 = 0; break; case 3: LED_4 = 0; break; } } if (BUTTON_WAVE // wave selection button off && wave_debounce) // if counter wave_debounce --; // debounce if (! P3_6) // analog comparator test wave_buffer &= ~0x04; // AR envelope off for (i = 0; i < 10 ;i ++) // delay { i = i; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void dco_ini(void) { INT_DISABLE; // disable interrupts TMOD &= 0xF0; // clear timer 0 mode bits TMOD |= 0x01; // timer 0 in mode 1 ET0 = 1; // enable timer 0 interrupt TR0 = 1; // enable timer 0 counter INT_ENABLE; // enable interrupts } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void dco_int(void) interrupt 1 using 2 { static __data UCHAR w_i = 0; // sample index INT_DISABLE; // disable interrupts TR0 = 0; // stop timer 0 TH0 = frqdiv_hi; // load timer value high TL0 = frqdiv_lo; // load timer value low wave_buffer &= 0x0F; // clear wave bits wave_buffer |= wave_sample[w_i ++]; // set wave sample P1 = wave_buffer; // output wave sample w_i &= 0x0F; // normalize interval 0 - 15 TR0 = 1; // start timer 0 INT_ENABLE; // enable interrupts } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void midi_ini(void) { INT_DISABLE; TR1 = 0; // stop timer ET1 = 0; // disable timer 1 interrupt TI = 0; // clear transmit - not used RI = 0; // clear receiver interrupt SCON = 0x50; // mode 1 and enable receipt PCON = 0x80; // smod 1: baudrate doubler TMOD &= ~0xF0; // clear timer 1 mode bits TMOD |= 0x20; // timer 1 in mode 2 // baud rate counter = 0xfc TH1 = (unsigned char)(256 - (24000000L / (16L * 12L * 31250L))); ES = 1; // enable serial interrupt TR1 = 1; // enable counter timer 1 INT_ENABLE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void midi_int(void) interrupt 4 using 1 { static __data UCHAR note_temp; // table notes index __data UCHAR aux_command; // midi command RI = 0; // reset int. MUST BE 1rst! input_byte = SBUF; // store input byte aux_command = input_byte & 0xF0; // clear channel if (aux_command == NOTE_ON) // midi command parsing { midi_state = 1; return; } if (aux_command == NOTE_OFF) // midi command parsing { midi_state = 4; return; } if ((midi_state == 1) // midi note number parsing || (midi_state == 4)) // for both note on and off { midi_state ++; // appoint to next state note_temp = input_byte; // store future note number return; } if (midi_state == 2) // velocity value parsing { midi_state ++; // appoint to next state if (input_byte) // if greater 0 is note on { wave_buffer |= 0x04; // AR envelope on note_count ++; // increment note on counter note_next = note_temp; // store future note number } else // if velocity 0 is note off note_count --; // decrease note on counter } if (midi_state == 5) // velocity value parsing { midi_state ++; // for note off command note_count --; // decrease note on counter } wave_buffer = // set ASR envelope (note_count) ? wave_buffer | 0x08 // ASR 1 : wave_buffer & ~0x08; // ASR 0 when notes off } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -