Synth with C64 like sounds. Played on two piezo buzzers with a PS/2 keyboard. Implemented on FRDM-KL46Z
Dependencies: PS2 TSI beep2 mbed
C64Synth.cpp
- Committer:
- alexanderh
- Date:
- 2014-01-24
- Revision:
- 4:0f73a5d06177
- Parent:
- 3:2cd5dfcad0e6
File content as of revision 4:0f73a5d06177:
/* * C64Synth uses a PS/2 keyboard to play C64 arps and simple tones. * Implemented on a FRDM KL46Z board * * The keyboard is tuned in the C scale as of right now * * Author: Alexander Hentschel 2014 */ /* * TODO LIST * * Implemept sharp (#) notes * Implement scale change * * * */ #include "mbed.h" #include "beep2.h" #include "TSISensor.h" #include "PS2Keyboard.h" #include "stdio.h" #include "keys.h" DigitalOut myled1(LED1); DigitalOut myled2(LED2); Beep arpBuzzer(PTA5); Beep toneBuzzer(PTA12); PS2Keyboard ps2kb(PTC8,PTC9); TSISensor tsi; PS2Keyboard::keyboard_event_t evt_kb; void keyboardSynth(); void playArp(char chord); void playNote(Beep buz,char note,float dc,float len); void playContNote(char note,int oct,float dc); void getNotes(char note, char* point); float getFq(char note, bool sharp); float toneDc = 0.5; char lastNote; bool arpAttack = false; float arpDc = 0.5; float arpSpeed = 0.02; float arpTempovar = 0.1; float arpSpeed2; float arpTime = 0.025; float masterscale=1; int main() { printf("--Program Start--"); myled2 = !myled2; keyboardSynth(); } void keyboardSynth() { int arpOn = 0; int toneOn =0; char keytone = ' '; char playtone = ' '; char playchor = ' '; char chor; char test; int octave; //PS/2 keyboard test while(1) { if (ps2kb.processing(&evt_kb)) { //DEBUG keyboard terminalprint //printf("[%d]:", evt_kb.type); //for (int i = 0; i < evt_kb.length; i++) { // printf("%02x ", evt_kb.scancode[i]); // } //printf("\n"); //KEY PRESS PART if (!evt_kb.type) { switch(evt_kb.scancode[0]) { //FUNCTION KEYS case Space_key: arpOn = 0; toneOn = 0; break; //MULTICODE KEYS case Mod_fn: switch(evt_kb.scancode[1]) { case Up_key: masterscale = masterscale*2; break; //Tune down 1 octave case Down_key: masterscale = masterscale/2; break; //Faster arp speed case Pgup_key: arpTime = arpTime/1.2; break; //Slower arp speed case Pgdown_key: arpTime = arpTime*1.2; break; //Brighter sound case Left_key: toneDc = 0.98; break; //Square wave case Right_key: toneDc = 0.5; break; //Arp Attack case End_key: if (!arpAttack) { arpDc = 0; arpSpeed = 0.02; } else { arpDc = 0.5; } arpAttack = !arpAttack; break; } break; //ARPS case Z_key: chor = 'a'; break; case X_key: // chor = 'b' //arpOn = true; break; case C_key: chor = 'C'; break; case V_key: chor = 'd'; break; case B_key: chor = 'e'; break; case N_key: chor = 'F'; break; case M_key: chor = 'G'; break; // -- TONES -- //ROW 1 case A_key: keytone = 'a'; octave = 1; break; case S_key: keytone = 'b'; octave = 1; break; case D_key: keytone = 'c'; octave = 1; break; case F_key: keytone = 'd'; octave = 1; break; case G_key: keytone = 'e'; octave = 1; break; case H_key: keytone = 'f'; octave = 1; break; case J_key: keytone = 'g'; octave = 1; break; //ROW 2 //TODO speaker 3 case Q_key: keytone = 'a'; octave = 2; break; case W_key: keytone = 'b'; octave = 2; break; case E_key: keytone = 'c'; octave = 2; break; case R_key: keytone = 'd'; octave = 2; break; case T_key: keytone = 'e'; octave = 2; break; case Y_key: keytone = 'f'; octave = 2; break; case U_key: keytone = 'g'; octave = 2; break; } //Set the tone that should be played. Only do this if the key is not already playing if(keytone != playtone) { playtone = keytone; toneOn++; } //Set the chord that should be played. Only do this if the key is not already playing if(chor != playchor) { playchor = chor; arpOn++; } //KEY RELEASE PART } else { test = evt_kb.scancode[1]; //Arp key is released if ( test == Z_key || /*test == S_key ||*/ test == C_key || test == V_key || test == B_key || test == N_key || test == M_key) { //ATTACK MODE if (arpAttack && arpOn == 1) { arpDc = 0; arpSpeed = 0.02; } arpOn--; } //Tone key is released if ( test == Q_key || test == W_key || test == E_key || test == R_key || test == T_key || test == Y_key || test == U_key || test == A_key || test == S_key || test == D_key || test == F_key || test == G_key || test == H_key || test == J_key) { toneOn--; } } } //TONE HANDLER if (toneOn> 0) { playContNote(playtone,octave,0.9); } else { keytone = ' '; playtone = ' '; lastNote = ' '; toneBuzzer.nobeep(); toneOn = 0; } //CHORD/ARP HANDLER if (arpOn>0) { playArp(playchor); } else { chor = ' '; playchor = ' '; arpOn = 0; } } } /** * * Plays an arpeggio of the provided chord. Arp speed can be controlled by touch slider or pgup/pgdown setting. PWM duty cycle is sweeped automatically * * @param chord the chord to be played UPPER CASE is major chords, lower case is minor chords. * */ void playArp(char chord) { static int arpCounter; static char theChord[3]; getNotes(chord, theChord); //keep duty cycle between 0.03 and 0.97. if((arpDc > 0.98 && arpSpeed >0)|| (arpDc < 0.02 && arpSpeed <0)) { arpSpeed = arpSpeed*-1; } arpSpeed2 = tsi.readPercentage()/15; //Play the correct note in the chord. Vary the duty cycle and tempo for cool C64 arp effect playNote(arpBuzzer,theChord[arpCounter],arpDc,arpTime+arpTempovar*arpSpeed+arpSpeed2); arpDc = arpDc+arpSpeed; //Reset the notes arpCounter++; if (arpCounter == 3) { arpCounter= 0; } } /** * * Plays a note on the provided buzzer * * @param buz the buzzer to play the note on, * @param note the note to be played * @param dc the duty cycle value * @param len the length of the note * */ void playNote(Beep buz, char note,float dc,float len) { buz.beep(getFq(note,false),len,dc); myled1 = !myled1; myled2 = !myled2; if (note=='w') { wait(0.05); } wait (len); //wait while the note plays. } /** -- PlayContNote -- * * Plays a continuous note on the second buzzer * * @param note the note to be played * @param oct the octave * @param dc the duty cycle of the note */ void playContNote(char note,int oct,float dc) { static float fq; if(lastNote != note) { fq = getFq(note,false); toneBuzzer.beepNoStop(fq*oct/2,toneDc); myled1 = !myled1; myled2 = !myled2; } else { toneBuzzer.changeDc(toneDc); } //wait (len); //wait while the note plays. lastNote = note; } /** * * Gets the notes in a chord * * @param chord the chord * @param notes the array to save the notes in * */ void getNotes(char chord, char* notes) { if (chord=='a') { notes[0] = 'a'; notes[1] = 'c'; notes[2] = 'e'; } if (chord=='C') { notes[0] = 'g'; notes[1] = 'c'; notes[2] = 'e'; } if (chord=='F') { notes[0] = 'a'; notes[1] = 'c'; notes[2] = 'f'; } if (chord=='G') { notes[0] = 'g'; notes[1] = 'b'; notes[2] = 'd'; } if (chord=='d') { notes[0] = 'a'; notes[1] = 'd'; notes[2] = 'f'; } if (chord=='e') { notes[0] = 'g'; notes[1] = 'b'; notes[2] = 'e'; } } /** * * Gets the frequency of the note * * @param note the note * * @return the frequency as float */ float getFq(char note, bool sharp) { if(!sharp ) { if (note=='a') { return 880*masterscale; } if (note=='b') { return 987.76*masterscale; } if (note=='c') { return 1046.5*masterscale; } if (note=='d') { return 1174.66*masterscale; } if (note=='e') { return 1318.51*masterscale; } if (note=='f') { return 1396.91*masterscale; } if (note=='g') { return 1567.98*masterscale; } //Sharps # } else { if (note=='f') { return 1479.98*masterscale; } } return 0; }