This textfile has been put together with the information from http://www.buchi.de/MonoVoice/Source.ASP. Visit this page for more up to date information about the code and about the MonoVoice project. --------------------------------------------------------------------------------------------------------- The MonoVoice The Source Code ! The MonoVoice OS was written in standard ANSI C using the CodeVision AVR development system. It should run with other compilers, too. If the code looks ugly in your web browser, do not be confused. Copy the code section and paste it in any editor, then the tabs will work OK. ---------- Begin of Code ---------- /*******************************************************************************************************/ /*******************************************************************************************************/ /** **/ /** M I D I S I D - V 1 . 3 **/ /** **/ /**---------------------------------------------------------------------------------------------------**/ /** **/ /** Firmware for the MonoVoice MIDI Synthesizer. A moniphonic 3-oscillator synth with a simple **/ /** resonant lowpass filter using the Commodore 6582 SID chip as sound source. **/ /** **/ /**---------------------------------------------------------------------------------------------------**/ /** **/ /** (C) 2000 by Michael Buchstaller of GENERAL HARMONICS AUDIO PROCESSORS **/ /** all Rights reserved. **/ /** **/ /*******************************************************************************************************/ /*******************************************************************************************************/ #include <90s8515.h> // I/O register definitions for AT90S8515 //#include // floating point library /*******************************************************************************************************/ /* */ /* Declarations of global veriables and constants */ /* */ /*******************************************************************************************************/ unsigned char MIDI_CHANNEL; // Channel (1...16) Musician´s number not 0...15 unsigned short int PLAYING_NOTE = 65535; // note being played unsigned char PROGRAM = 4; // Program for ModWheel values (Default: Filter Resonance) unsigned char RST = 0; // MIDI Running Status Byte eeprom unsigned char SYNTH_A = 0; // Attack (global) (0...15) eeprom unsigned char SYNTH_D = 0; // Decay (global) (0...15) eeprom unsigned char SYNTH_S = 15; // Sustain (global) (0...15) eeprom unsigned char SYNTH_R = 15; // Release (global) (0...15) eeprom unsigned char SYNTH_A1 = 0; // Attack (Osc. #1) (0...15) eeprom unsigned char SYNTH_D1 = 0; // Decay (Osc. #1) (0...15) eeprom unsigned char SYNTH_S1 = 15; // Sustain (Osc. #1) (0...15) eeprom unsigned char SYNTH_R1 = 15; // Release (Osc. #1) (0...15) eeprom unsigned char SYNTH_A2 = 0; // Attack (Osc. #2) (0...15) eeprom unsigned char SYNTH_D2 = 0; // Decay (Osc. #2) (0...15) eeprom unsigned char SYNTH_S2 = 15; // Sustain (Osc. #2) (0...15) eeprom unsigned char SYNTH_R2 = 15; // Release (Osc. #2) (0...15) eeprom unsigned char SYNTH_A3 = 0; // Attack (Osc. #3) (0...15) eeprom unsigned char SYNTH_D3 = 0; // Decay (Osc. #3) (0...15) eeprom unsigned char SYNTH_S3 = 15; // Sustain (Osc. #3) (0...15) eeprom unsigned char SYNTH_R3 = 15; // Release (Osc. #3) (0...15) eeprom unsigned char SYNTH_WAVEFORM = 2; // Waveform(global) (0...15) // 1 - Tri, 2 - Saw, 4 - Pulse, 8 - Noise eeprom unsigned char SYNTH_WAVEFORM1 = 2; // Waveform(Osc. #1) (0...15) eeprom unsigned char SYNTH_WAVEFORM2 = 2; // Waveform(Osc. #1) (0...15) eeprom unsigned char SYNTH_WAVEFORM3 = 1; // Waveform(Osc. #1) (0...15) eeprom unsigned char SYNTH_FILTERTYPE = 1; // Filter type (0...7) // 1 - LP, 2 - Bandpass, 4 - HP eeprom unsigned char SYNTH_VOLUME = 10; // Output volume eeprom unsigned int SYNTH_CUTOFF = 65; // Filter Cutoff Freq. (0...2048) eeprom unsigned char SYNTH_RESONANCE = 15; // Filter Resonance (0...15) eeprom unsigned char SYNTH_DETUNE2 = 0; // linear Detune voice2 (0...127) eeprom unsigned char SYNTH_DETUNE3 = 0; // linear Detune voice3 (0...127) eeprom unsigned char FILTER_A = 2; // Attack (0...127) eeprom unsigned char FILTER_D = 3; // Decay (0...127) eeprom unsigned char FILTER_S = 40; // Sustain (0...127) eeprom unsigned char FILTER_R = 1; // Release (0...127) eeprom unsigned char FILTER_ModDepth = 32; // Filter modulation (0...127) eeprom char FILTER_Vorzeichen = 1; // 1 or -1 for envelope reversal short int FILTER_ADSR = 0; // current ADSR value unsigned char FILTER_State = 0; short int FILTER_ADD = 0; // value to add to filter cutoff unsigned char SID_REG[24 + 1]; // SID registerset copy in RAM unsigned char SID_REG_OLD[24 + 1]; // old SID registers eeprom unsigned short int NOTE_TABLE[128] = { 268, 284, 301, 318, 337, 358, // 1st Octave C-0 379, 401, 425, 451, 477, 506, 536, 568, 602, 637, 675, 716, // 2nd Octave C-1 758, 803, 851, 902, 955, 1012, 1072, 1136, 1204, 1275, 1351, 1432, // 3rd Octave C-2 1517, 1607, 1703, 1804, 1911, 2025, 2145, 2273, 2408, 2551, 2703, 2864, // 4th Octave C-3 3034, 3215, 3406, 3608, 3823, 4050, 4291, 4547, 4817, 5103, 5407, 5728, // 5th Octave C-4 6069, 6430, 6812, 7217, 7647, 8101, 8583, 9094, 9634,10207,10814,11457, // 6th Octave C-5 12139,12860,13625,14435,15294,16203, 17167,18188,19269,20415,21629,22915, // 7th Octave C-6 24278,25721,27251,28871,30588,32407, 34334,36376,38539,40830,43258,45830, // 8th Octave C-7 48556,51443,54502,57743,61176,64814}; unsigned char MIDI_STACK[128]; // FIFO for MIDI-In Bytes unsigned char MIDI_STACK_Bytes = 0; // # of Bytes in FIFO unsigned char MIDI_STACK_Write = 0; // Byte position to write next unsigned char MIDI_STACK_Read = 0; // Byte position to read next long Wert_A = 26004; long Wert_B = 26088; long Letzte_ZahlX = 26004; long Letzte_ZahlY = 26088; unsigned char SYNTH_GATE = 0; // Gate-Signal /*******************************************************************************************************/ /* */ /* RND - gets a random number between 0 and 1 */ /* */ /*******************************************************************************************************/ double RND(void) { long x; long y; double rw; x = Wert_A * (Letzte_ZahlX & 65535) + (Letzte_ZahlX >> 16); y = Wert_B * (Letzte_ZahlY & 65535) + (Letzte_ZahlY >> 16); rw = (x << 16) + (y & 65525); Letzte_ZahlX = x; Letzte_ZahlY = y; return (rw / 4294967296 +.5); } /*******************************************************************************************************/ /* */ /* warte(ms) - waits for the given amount of milliseconds */ /* */ /*******************************************************************************************************/ void warte(unsigned long int ms) { unsigned long int t; register unsigned char i; for (t = 0;t < ms * 6;t++) // 3 for 4 MHz, 6 for 8 MHz for (i = 0;i < 125;i++); } /*******************************************************************************************************/ /* */ /* writesid(Register,Value) - writes to a SID register */ /* */ /*******************************************************************************************************/ // Connections from the AVR to the SID: // // ## AVR ## SID // 39 Port A bit 0 15 Data0 // 38 Port A bit 1 16 Data1 // 37 Port A bit 2 17 Data2 // 36 Port A bit 3 18 Data3 // 35 Port A bit 4 19 Data4 // 34 Port A bit 5 20 Data5 // 33 Port A bit 6 21 Data6 // 32 Port A bit 7 22 Data7 // 21 Port C bit 0 9 Address 0 // 22 Port C bit 1 10 Address 1 // 23 Port C bit 2 11 Address 2 // 24 Port C bit 3 12 Address 3 // 25 Port C bit 4 13 Address 4 // 26 Port C bit 5 8 -CS // 27 Port C bit 6 7 Read/-Write // 28 Port C bit 7 5 -Reset // // note: "-" means active-low (reversed) logic ! void writesid(unsigned char RegNo,unsigned char RegVal) { PORTC = RegNo + 32 + 128; // attach the Register number to the address lines PORTA = RegVal; // put the data byte on the port PORTC = RegNo + 128; // Select the chip (Write is always enabled) #asm nop nop nop nop nop nop nop nop #endasm PORTC = RegNo + 32 + 128; // deselect it... DONE ! #asm nop nop nop nop nop nop nop nop #endasm } /*******************************************************************************************************/ /* */ /* resetsid - resets the SID chip and initializes the 6502 state machine to sane values */ /* */ /*******************************************************************************************************/ void resetsid() { PORTC = 0; // All Bits low: Address=0, Chip selected, Write, Reset PORTA = 0; // Data lines = 0 warte (250); // hold this state for 50 ms PORTC = 0; // Select & RESET #asm nop nop nop nop nop nop nop nop #endasm PORTC = 32 + 128; // remove the RESET signal, delect Chip #asm nop nop nop nop nop nop nop nop #endasm } /*******************************************************************************************************/ /* */ /* flushsid - writes all SID registers to that chip */ /* */ /*******************************************************************************************************/ void flushsid(unsigned char Alle) { unsigned char t; if (Alle != 0) { for (t = 0;t <= 24;t++) { SID_REG_OLD[t] = SID_REG[t]; writesid(t,SID_REG[t]); } } else { for (t = 0;t <= 24;t++) { if (SID_REG[t] != SID_REG_OLD[t]) { SID_REG_OLD[t] = SID_REG[t]; writesid(t,SID_REG[t]); } } } } /*******************************************************************************************************/ /* */ /* UART Receive Interrupt Service Routine - deals with incoming MIDI bytes */ /* */ /*******************************************************************************************************/ interrupt [UART_RXC] void uart_isr(void) { unsigned char MIDI_Byte; // Data byte read from UART MIDI_Byte = UDR; // fetch data from UART data register if (MIDI_STACK_Bytes < 255) // put in FIFO only if there is room, else trash data { MIDI_STACK_Write++; // increase write pointer MIDI_STACK_Write &= 127; // and normalize to max. 128 bytes MIDI_STACK[MIDI_STACK_Write] = MIDI_Byte; // put Byte in the FIFO queue MIDI_STACK_Bytes++; // increase byte counter } } /*******************************************************************************************************/ /* */ /* GetMIDIByte - Holen eines Datenbytes aus dem FIFO */ /* */ /*******************************************************************************************************/ unsigned char GetMIDIByte(void) { unsigned char MIDI_Byte = 0; // Data byte read from FIFO if (MIDI_STACK_Bytes > 0) // pull data only if the FIFO is not empty { MIDI_STACK_Read++; // increase read pointer MIDI_STACK_Read &= 127; // and normalize to max. 128 bytes MIDI_Byte = MIDI_STACK[MIDI_STACK_Read]; // get byte from the FIFO queue MIDI_STACK_Bytes--; // decrease byte counter } return (MIDI_Byte); } /*******************************************************************************************************/ /* */ /* PROCESSBYTE(Byte) - deals with incoming MIDI data bytes and processes them */ /* */ /*******************************************************************************************************/ void ProcessByte(unsigned char MIDI_Byte) { unsigned char channel; // MIDI-Channel static unsigned char ByteCounter; // counter for incoming data bytes static unsigned char Byte1; // 1st Data Byte static unsigned char Byte2; // 2nd Data Byte if (MIDI_Byte == 0xFE) return; // ignore "Active sensing" if (MIDI_Byte > 127) // is it a control byte ? { channel = (MIDI_Byte & 15) + 1; // extract channel # (0...f) from Byte, add 1 for musician´s number if (channel != MIDI_CHANNEL) { RST = 0; // set RunningStatus invalid, so that following data bytes will be ignored return; // discard if wrong channel } RST = MIDI_Byte / 16; // get command ByteCounter = 0; // and reset the ByteCounter to Zero to flush old data from return; // previously sent data to probably other devices } ByteCounter++; // increment the Byte counter if (ByteCounter == 1) Byte1 = MIDI_Byte; // memorize 1st Byte if (ByteCounter == 2) Byte2 = MIDI_Byte; // memorize 2nd Byte // put all other data bytes in location 2 (overwrite it) /***** now test if enough data for the supported commands has arrived *****/ switch (RST) { case 8: // NOTE OFF 0x08 { SwitchOff: if (ByteCounter >= 2) { if (Byte1 == 0x78) goto AllOff; if (Byte1 == 0x7B) goto AllOff; if (NOTE_TABLE[Byte1 - 24] == PLAYING_NOTE) { ByteCounter = 0; // reset the Bytecounter SID_REG[ 4] = SYNTH_WAVEFORM1 * 16 + 0; // Gate off Osc. #1 SID_REG[11] = SYNTH_WAVEFORM2 * 16 + 0; // Gate off Osc. #2 SID_REG[18] = SYNTH_WAVEFORM3 * 16 + 0; // Gate off Osc. #3 flushsid(0); PLAYING_NOTE = 65535; // no note is playing SYNTH_GATE = 0; // reset global Gate flag to "OFF" FILTER_State = 0; } } break; } case 9: // NOTE ON 0x09 { if (ByteCounter >= 2) { PLAYING_NOTE = NOTE_TABLE[Byte1 - 24]; // get the note to be played if (Byte2 == 0) goto SwitchOff; ByteCounter = 0; // reset the Bytecounter SID_REG[ 0] = (unsigned char) (PLAYING_NOTE & 255); // low byte Frequency Osc. #1 SID_REG[ 1] = (unsigned char) (PLAYING_NOTE / 256); // high byte SID_REG[ 4] = SYNTH_WAVEFORM1 * 16 + 1; // Gate on Osc. #1 SID_REG[ 7] = (unsigned char) (PLAYING_NOTE + SYNTH_DETUNE2) & 255; // low byte Frequency Osc. #2 SID_REG[ 8] = (unsigned char) ((PLAYING_NOTE + SYNTH_DETUNE2) / 256); // high byte SID_REG[11] = SYNTH_WAVEFORM2 * 16 + 1; // Gate on Osc. #2 SID_REG[14] = (unsigned char)(PLAYING_NOTE - SYNTH_DETUNE3) & 255; // low byte Frequency Osc. #3 SID_REG[15] = (unsigned char) ((PLAYING_NOTE - SYNTH_DETUNE3) / 256); // high byte SID_REG[18] = SYNTH_WAVEFORM3 * 16 + 1; // Gate on Osc. #3 flushsid(0); SYNTH_GATE = 1; // set the global Gate flag to "ON" } break; } case 11: // CONTROLLER CHANGE 0x0B { if (ByteCounter >= 2) { switch (Byte1) { case 10: // global VCA Attack time { SYNTH_A = Byte2 / 8; // set the Value mod 16 SYNTH_A1 = SYNTH_A; SYNTH_A2 = SYNTH_A; SYNTH_A3 = SYNTH_A; SID_REG[ 5] = SYNTH_A1 * 16 + SYNTH_D1; // set A/D for Osc. #1 SID_REG[12] = SYNTH_A2 * 16 + SYNTH_D2; // set A/D for Osc. #2 SID_REG[19] = SYNTH_A3 * 16 + SYNTH_D3; // set A/D for Osc. #3 flushsid(0); break; } case 11: // global VCA Decay time { SYNTH_D = Byte2 / 8; // set the Value mod 16 SYNTH_D1 = SYNTH_D; SYNTH_D2 = SYNTH_D; SYNTH_D3 = SYNTH_D; SID_REG[ 5] = SYNTH_A1 * 16 + SYNTH_D1; // set A/D for Osc. #1 SID_REG[12] = SYNTH_A2 * 16 + SYNTH_D2; // set A/D for Osc. #2 SID_REG[19] = SYNTH_A3 * 16 + SYNTH_D3; // set A/D for Osc. #3 flushsid(0); break; } case 12: // global VCA Sustain volume { SYNTH_S = Byte2 / 8; // set the Value mod 16 SYNTH_S1 = SYNTH_S; SYNTH_S2 = SYNTH_S; SYNTH_S3 = SYNTH_S; SID_REG[ 6] = SYNTH_S1 * 16 + SYNTH_R1; // set S/R for Osc. #1 SID_REG[13] = SYNTH_S2 * 16 + SYNTH_R2; // set S/R for Osc. #2 SID_REG[20] = SYNTH_S3 * 16 + SYNTH_R3; // set S/R for Osc. #3 flushsid(0); break; } case 13: // global VCA Release time { SYNTH_R = Byte2 / 8; // set the Value mod 16 SYNTH_R1 = SYNTH_R; SYNTH_R2 = SYNTH_R; SYNTH_R3 = SYNTH_R; SID_REG[ 6] = SYNTH_S1 * 16 + SYNTH_R1; // set S/R for Osc. #1 SID_REG[13] = SYNTH_S2 * 16 + SYNTH_R2; // set S/R for Osc. #2 SID_REG[20] = SYNTH_S3 * 16 + SYNTH_R3; // set S/R for Osc. #3 flushsid(0); break; } case 14: // Filter resonance { SYNTH_RESONANCE = Byte2 / 8; // set the Value mod 16 SID_REG[23] = 1 + 2 + 4 + 16 * SYNTH_RESONANCE; // Filter control: all Osc. through the filter flushsid(0); break; } case 15: // Detune2 { SYNTH_DETUNE2 = Byte2; // set the Value SID_REG[7] = (unsigned char) (PLAYING_NOTE + SYNTH_DETUNE2/2) & 255; // low byte Frequency Osc. #2 SID_REG[8] = (unsigned char) ((PLAYING_NOTE + SYNTH_DETUNE2/2) / 256); // high byte flushsid(0); break; } case 16: // Detune3 { SYNTH_DETUNE3 = Byte2; // set the Value SID_REG[14] = (unsigned char)(PLAYING_NOTE - SYNTH_DETUNE3) & 255; // low byte Frequency Osc. #3 SID_REG[15] = (unsigned char) ((PLAYING_NOTE - SYNTH_DETUNE3) / 256); // high byte flushsid(0); break; } case 17: // Filter Attack time { FILTER_A = (127 - Byte2) / 16 + 1; // set the Value break; } case 18: // Filter Decay time { FILTER_D = (127 - Byte2) / 16 + 1; // set the Value break; } case 19: // Filter Sustain level { FILTER_S = Byte2; // set the Value break; } case 20: // Filter Release time { FILTER_R = (127 - Byte2) / 16 + 1; // set the Value break; } case 21: // Filter Modulation Depth { FILTER_ModDepth = Byte2; // set the Value break; } case 22: // Filter ADSR Reversal { FILTER_Vorzeichen = 1; // set the Value if (Byte2 > 63) FILTER_Vorzeichen = -1; break; } case 23: // Oscillator 1 VCA Attack time { SYNTH_A1 = Byte2 / 8; // set the Value mod 16 SID_REG[ 5] = SYNTH_A1 * 16 + SYNTH_D1; // set A/D for Osc. #1 flushsid(0); break; } case 24: // Oscillator 1 VCA Decay time { SYNTH_D1 = Byte2 / 8; // set the Value mod 16 SID_REG[ 5] = SYNTH_A1 * 16 + SYNTH_D1; // set A/D for Osc. #1 flushsid(0); break; } case 25: // Oscillator 1 VCA Sustain volume { SYNTH_S1 = Byte2 / 8; // set the Value mod 16 SID_REG[ 6] = SYNTH_S1 * 16 + SYNTH_R1; // set S/R for Osc. #1 flushsid(0); break; } case 26: // Oscillator 1 VCA Release time { SYNTH_R1 = Byte2 / 8; // set the Value mod 16 SID_REG[ 6] = SYNTH_S1 * 16 + SYNTH_R1; // set S/R for Osc. #1 flushsid(0); break; } case 27: // Oscillator 2 VCA Attack time { SYNTH_A2 = Byte2 / 8; // set the Value mod 16 SID_REG[12] = SYNTH_A2 * 16 + SYNTH_D2; // set A/D for Osc. #2 flushsid(0); break; } case 28: // Oscillator 2 VCA Decay time { SYNTH_D2 = Byte2 / 8; // set the Value mod 16 SID_REG[12] = SYNTH_A2 * 16 + SYNTH_D2; // set A/D for Osc. #2 flushsid(0); break; } case 29: // Oscillator 2 VCA Sustain volume { SYNTH_S2 = Byte2 / 8; // set the Value mod 16 SID_REG[13] = SYNTH_S2 * 16 + SYNTH_R2; // set S/R for Osc. #2 flushsid(0); break; } case 30: // Oscillator 2 VCA Release time { SYNTH_R2 = Byte2 / 8; // set the Value mod 16 SID_REG[13] = SYNTH_S2 * 16 + SYNTH_R2; // set S/R for Osc. #2 flushsid(0); break; } case 31: // Oscillator 3 VCA Attack time { SYNTH_A3 = Byte2 / 8; // set the Value mod 16 SID_REG[19] = SYNTH_A3 * 16 + SYNTH_D3; // set A/D for Osc. #3 flushsid(0); break; } case 32: // Oscillator 3 VCA Decay time { SYNTH_D3 = Byte2 / 8; // set the Value mod 16 SID_REG[19] = SYNTH_A3 * 16 + SYNTH_D3; // set A/D for Osc. #3 flushsid(0); break; } case 33: // Oscillator 3 VCA Sustain volume { SYNTH_S3 = Byte2 / 8; // set the Value mod 16 SID_REG[20] = SYNTH_S3 * 16 + SYNTH_R3; // set S/R for Osc. #3 flushsid(0); break; } case 34: // Oscillator 3 VCA Release time { SYNTH_R3 = Byte2 / 8; // set the Value mod 16 SID_REG[20] = SYNTH_S3 * 16 + SYNTH_R3; // set S/R for Osc. #3 flushsid(0); break; } case 36: // global Waveform { SYNTH_WAVEFORM = Byte2 & 15; // set the Value mod 16 SYNTH_WAVEFORM1 = SYNTH_WAVEFORM; SYNTH_WAVEFORM2 = SYNTH_WAVEFORM; SYNTH_WAVEFORM3 = SYNTH_WAVEFORM; SID_REG[ 4] = SYNTH_WAVEFORM1 * 16 + SYNTH_GATE; // set Waveform for Osc. #1 SID_REG[11] = SYNTH_WAVEFORM2 * 16 + SYNTH_GATE; // set Waveform for Osc. #2 SID_REG[18] = SYNTH_WAVEFORM3 * 16 + SYNTH_GATE; // set Waveform for Osc. #3 flushsid(0); break; } case 37: // Oscillator #1 Waveform { SYNTH_WAVEFORM1 = Byte2 & 15; // set the Value mod 16 SID_REG[ 4] = SYNTH_WAVEFORM1 * 16 + SYNTH_GATE; // set Waveform for Osc. #1 flushsid(0); break; } case 38: // Oscillator #2 Waveform { SYNTH_WAVEFORM2 = Byte2 & 15; // set the Value mod 16 SID_REG[11] = SYNTH_WAVEFORM2 * 16 + SYNTH_GATE; // set Waveform for Osc. #2 flushsid(0); break; } case 39: // Oscillator #2 Waveform { SYNTH_WAVEFORM3 = Byte2 & 15; // set the Value mod 16 SID_REG[18] = SYNTH_WAVEFORM3 * 16 + SYNTH_GATE; // set Waveform for Osc. #3 flushsid(0); break; } case 40: // Filter Type { SYNTH_FILTERTYPE = Byte2 & 7; // set the Value mod 8 SID_REG[24] = SYNTH_VOLUME + 16 * SYNTH_FILTERTYPE; // set Volume and Filter type flushsid(0); break; } case 41: // Output Volume { SYNTH_VOLUME = Byte2 / 8; // set the Value mod 16 SID_REG[24] = SYNTH_VOLUME + 16 * SYNTH_FILTERTYPE; // set Volume and Filter type flushsid(0); break; } } if (Byte1 == 0x11) // Joystick Hoch/runter ? { SYNTH_RESONANCE = Byte2 / 16; // set the Resonance SID_REG[23] = 1 + 2 + 4 + 16 * SYNTH_RESONANCE; // Filter control flushsid(0); } ByteCounter = 0; // reset the Bytecounter } break; } case 14: // PITCHBEND 0x0E { if (ByteCounter >= 2) { SYNTH_CUTOFF = Byte1 + 128 * (unsigned short int) Byte2; SYNTH_CUTOFF /= 30; SID_REG[21] = ((SYNTH_CUTOFF + FILTER_ADD) / 8) & 7; // filter cutoff low byte (only bits 0...2 are used) SID_REG[22] = (SYNTH_CUTOFF + FILTER_ADD) / 64; // filter cutoff high byte [f(HZ)= 30+(number)*5.8] 81 = 500 Hz flushsid(0); ByteCounter = 0; // reset the Bytecounter } break; } case 12: // Program Change 0x0C { if (ByteCounter >= 1) { PROGRAM = 0; // set PROGRAM to default (ModWheel = Detune) if (Byte1 <= 6) { PROGRAM = Byte1; // set PROGRAM to the desired value // ( 0: ModWheel = VCA A) // ( 1: ModWheel = VCA D) // ( 2: ModWheel = VCA S) // ( 3: ModWheel = VCA R) // ( 4: ModWheel = Filter Resonance) // ( 5: ModWheel = Detune Voice 2) // ( 6: ModWheel = Detune Voice 3) // ( 8: ModWheel = Filter A) // ( 9: ModWheel = Filter D) // (10: ModWheel = Filter S) // (11: ModWheel = Filter R) // (12: ModWheel = Filter modulation Depth) } ByteCounter = 0; // reset the Bytecounter } break; } } return; /***** Switch off all voices immediately if those special MIDI commands are encountered *****/ AllOff: SID_REG[4] = 32 + 0; // saw, gate off #1 SID_REG[11] = 32 + 0; // saw, gate off #2 SID_REG[18] = 32 + 0; // saw, gate off #3 flushsid(0); PLAYING_NOTE = 65535; return; } /*******************************************************************************************************/ /* */ /* Interrupt-Routine für den Timer0 (Timing-Funktion für SW-LFOs) */ /* */ /*******************************************************************************************************/ interrupt [TIM0_OVF] void timer0_ovf_isr(void) { static unsigned short int i; i--; if (i > 0) return; // has the 10 mx timeout expired ? // 80 sind 100 Hz i = 800; // Yes, so reset the counter to its starting value if (SYNTH_GATE == 1) { FILTER_ADSR += FILTER_A; if (FILTER_ADSR > 300) FILTER_ADSR = 300; } if (SYNTH_GATE == 0) { FILTER_ADSR -= FILTER_A; if (FILTER_ADSR < 0) FILTER_ADSR = 0; } } /*******************************************************************************************************/ /* */ /* main program; does initialization of I/O registers and self test, then enables SIO IRQ and waits */ /* */ /*******************************************************************************************************/ void main(void) { unsigned char t; signed short int tMerk = 0; /***** Set Data Direction Registers for the used Ports *****/ DDRA = 255; // PORTA and PORTC are programmed as outputs DDRC = 255; DDRB = 0; // all PORTB pins are inputs PORTA = 0; // switch off all bits PORTC = 0; GIMSK = 0; // all interrupt sources are disabled ChannelChange: /***** global disable interrupts *****/ #asm cli #endasm /***** Initialize the Synthesizer´s registers to a sane state *****/ SID_REG[ 0] = 0; // VCO 1 frequency (low byte) SID_REG[ 1] = 0; // VCO 1 frequency (high byte) SID_REG[ 2] = 0; // PWM voice 1 (low byte) SID_REG[ 3] = 8; /* 50 % duty cycle */ // PWM voice 1 (high byte, only bity 0...3 are used) SID_REG[ 4] = 32; /* Saw */ // voice 1 Control register // bit 0: Gate // bit 1: Sync to Oscillator 3 // bit 2: Ringmodulation: Triangle voice 1 * ((voice 2 + voice 3)/2) // bit 3: Test (reset voice) // bit 4: Triangle // bit 5: Saw // bit 6: Pulse // bit 7: Noise SID_REG[ 5] = 10 + 16*10; /* 6 / 6 */ // voice 1 loudness contour AD (A: bits 4...7, D: bits 0...3) SID_REG[ 6] = 8*16 + 12; /* 12 / 10 */ // voice 1 loudness contour SR (S: bits 4...7, R: bits 0...3) SID_REG[ 7] = 0; // VCO 2 frequency (low byte) SID_REG[ 8] = 0; // VCO 2 frequency (high byte) SID_REG[ 9] = 0; // PWM voice 2 (low byte) SID_REG[10] = 8; /* 50 % duty cycle */ // PWM voice 2 (high byte, only bity 0...3 are used) SID_REG[11] = 32; /* Saw */ // voice 2 Control register // bit 1: Sync to Oscillator 1 // bit 2: Ringmodulation: Triangle voice 2 = voice 1 * voice 3 SID_REG[12] = 10 + 16*10; /* 6 / 6 */ // voice 2 loudness contour AD (A: bits 4...7, D: bits 0...3) SID_REG[13] = 8*16 + 12; /* 12 / 10 */ // voice 2 loudness contour SR (S: bits 4...7, R: bits 0...3) SID_REG[14] = 0; // VCO 3 frequency (low byte) SID_REG[15] = 0; // VCO 3 frequency (high byte) SID_REG[16] = 0; // PWM voice 3 (low byte) SID_REG[17] = 8; /* 50 % duty cycle */ // PWM voice 3 (high byte, only bity 0...3 are used) SID_REG[18] = 32; /* Saw */ // voice 3 Control register // bit 1: Sync to Oscillator 2 // bit 2: Ringmodulation: Triangle voice 3 = voice 1 * voice 2 SID_REG[19] = 10 + 16*10; /* 6 / 6 */ // voice 3 loudness contour AD (A: bits 4...7, D: bits 0...3) SID_REG[20] = 8*16 + 12; /* 12 / 10 */ // voice 3 loudness contour SR (S: bits 4...7, R: bits 0...3) SID_REG[21] = 0; // filter cutoff low byte (only bits 0...2 are used) SID_REG[22] = 8; // filter cutoff high byte [f(HZ)= 30+(number)*5.8] 81 = 500 Hz SID_REG[23] = 1 + 2 + 4 + 16*10; /* all through filter, Q=0 */ // Filter control // Bit 0: Voice 1 is routed through the filter // Bit 1: Voice 2 is routed through the filter // Bit 2: Voice 3 is routed through the filter // Bit 3: external input is routed through the filter // Bit 4...7: Filter resonance (Q) SID_REG[24] = 5 + 16; /* sound on, LP */ // more filter control // Bit 0...3: Overall output volume // Bit 4: filter is LowPass // Bit 5: filter is BandPass // Bit 6: filter is HighPass // Bit 7: disable voice 3 resetsid(); flushsid(1); /***** Read the MIDI Channel ID to listen on from the DIP switches connected to PB0...3 *****/ warte(150); // wait for contact bouncing to finish MIDI_CHANNEL = (PINB & 15) + 1; // read from switches, add 1 for Musician´s Number 1...16 /***** initialize the serial port input for MIDI *****/ UBRR = 15; // prepare baud rate register for 8 MHz clock (4 MHz = 7, 8 MHz = 15) UCR = 128 + 16; // set "receive enable flag" and "Interrupt" /***** initialize the Oscillators *****/ SID_REG[ 0] = 0; // low byte Frequency Voice 1 SID_REG[ 1] = 0; // high byte SID_REG[ 7] = 0; // low byte Frequency Voice 2 SID_REG[ 8] = 0; // high byte SID_REG[14] = 0; // low byte Frequency Voice 3 SID_REG[15] = 0; // high byte SID_REG[ 4] = SYNTH_WAVEFORM1; // Gate off #1 SID_REG[11] = SYNTH_WAVEFORM2; // Gate off #2 SID_REG[18] = SYNTH_WAVEFORM3; // Gate off #3 SID_REG[24] = SYNTH_VOLUME + 8 * SYNTH_FILTERTYPE; // set Volume and Filter type flushsid(0); /***** initialize Timer0 and Prescaler for 100 Hz interrupt rate *****/ //TCCR0=0x05; // Clock source: System Clock/1024 (8 MHz --> 8 KHz) //TCNT0=0x00; //TIMSK=0x02; // Timer(s)/Counter(s) Interrupt(s) initialization /***** set SID registers according to the EEPROM values *****/ SID_REG[ 5] = SYNTH_A * 16 + SYNTH_D; // set A/D for voice #1 SID_REG[ 6] = SYNTH_S * 16 + SYNTH_R; // set S/R for voice #1 SID_REG[12] = SYNTH_A * 16 + SYNTH_D; // set A/D for voice #2 SID_REG[13] = SYNTH_S * 16 + SYNTH_R; // set S/R for voice #2 SID_REG[19] = SYNTH_A * 16 + SYNTH_D; // set A/D for voice #3 SID_REG[20] = SYNTH_S * 16 + SYNTH_R; // set S/R for voice #3 SID_REG[23] = 1 + 2 + 4 + 16 * SYNTH_RESONANCE; // Filter control: all voices through the filter SID_REG[21] = (SYNTH_CUTOFF / 8) & 7; // filter cutoff low byte (only bits 0...2 are used) SID_REG[22] = SYNTH_CUTOFF /64; // filter cutoff high byte [f(HZ)= 30+(number)*5.8] 81 = 500 Hz flushsid(0); /***** global enable interrupts *****/ #asm sei #endasm goto Beginn; /***** Wait for the thermonuclear destruction of the wold, or for power-off, whichever will happen earlier *****/ Beginn: // wait for incoming MIDI data... if (MIDI_CHANNEL != (PINB & 15) + 1) // Has the MIDI ID jumper been changed ? goto ChannelChange; // Changes will reset all channels and show the new ID... Work: if (MIDI_STACK_Bytes > 0) // Are there any data bytes in the FIFO buffer ? { t = GetMIDIByte(); // Yes, get the Byte ProcessByte(t); // and look what to do with it... goto Work; // more bytes pending ? } warte(20); // wait for 1 mSec if (SYNTH_GATE == 1) { if (FILTER_State == 0) { FILTER_ADSR += FILTER_A; if (FILTER_ADSR > 127) { FILTER_ADSR = 127; FILTER_State = 1; } FILTER_ADD = FILTER_ADSR * 255 / FILTER_ModDepth * FILTER_Vorzeichen; } else { FILTER_ADSR -= FILTER_D; if (FILTER_ADSR < FILTER_S) { FILTER_ADSR = FILTER_S; } FILTER_ADD = FILTER_ADSR * 255 / FILTER_ModDepth * FILTER_Vorzeichen; } } else { FILTER_State = 0; FILTER_ADSR -= FILTER_R; if (FILTER_ADSR < 0) FILTER_ADSR = 0; FILTER_ADD = FILTER_ADSR * 255 / FILTER_ModDepth * FILTER_Vorzeichen; } if (tMerk != FILTER_ADD) { tMerk = FILTER_ADD; SID_REG[21] = ((SYNTH_CUTOFF + FILTER_ADD) / 8) & 7; // filter cutoff low byte (only bits 0...2 are used) SID_REG[22] = (SYNTH_CUTOFF + FILTER_ADD) / 64; // filter cutoff high byte [f(HZ)= 30+(number)*5.8] 81 = 500 Hz flushsid(0); } goto Beginn; // endless loop } ---------- End of Code ----------