diff --git a/Arduinoboy/Arduinoboy.ino b/Arduinoboy/Arduinoboy.ino index 3162f26..08320a9 100644 --- a/Arduinoboy/Arduinoboy.ino +++ b/Arduinoboy/Arduinoboy.ino @@ -105,6 +105,8 @@ #define MEM_MIDIOUT_BIT_DELAY 61 #define MEM_MIDIOUT_BYTE_DELAY 63 +// #define PRO_MICRO // define this for Pro Micro custom Arduino (not detectable from regular defines) + /*************************************************************************** * User Settings ***************************************************************************/ @@ -140,6 +142,8 @@ byte defaultMemoryMap[MEM_MAX] = { }; byte memory[MEM_MAX]; +#include + /*************************************************************************** * Lets Assign our Arduino Pins ..... ***************************************************************************/ @@ -153,9 +157,8 @@ byte memory[MEM_MAX]; * Be sure to compile ***************************************************************************/ #if defined (__MK20DX256__) || defined (__MK20DX128__) || defined (__MKL26Z64__) -#define USE_TEENSY 1 -#define USE_USB 1 -#include +#define HAS_USB_MIDI +#include #if defined (__MKL26Z64__) #define GB_SET(bit_cl,bit_out,bit_in) GPIOB_PDOR = ((bit_in<<3) | (bit_out<<1) | bit_cl) @@ -173,12 +176,35 @@ int pinButtonMode = 2; //toggle button for selecting the mode HardwareSerial *serial = &Serial1; +/*************************************************************************** +* Pro Micro (ATmega32U4, with different pin config) +***************************************************************************/ +#elif defined (PRO_MICRO) +#define HAS_USB_MIDI +#include + +#define GB_SET(bit_cl, bit_out, bit_in) PORTF = (PINF & B00011111) | ((bit_cl<<7) | ((bit_out)<<6) | ((bit_in)<<5)) +// ^ The reason for not using digitalWrite is to allign clock and data pins for the GB shift reg. +// Pin distribution comes from official Arduino Leonardo documentation + +int pinGBClock = A0; // Analog In 0 - clock out to gameboy +int pinGBSerialOut = A1; // Analog In 1 - serial data to gameboy +int pinGBSerialIn = A2; // Analog In 2 - serial data from gameboy +int pinMidiInputPower = 4; // power pin for midi input opto-isolator +int pinStatusLed = 10; // Status LED +int pinLeds[] = {9,8,7,6,5,10}; // LED Pins +int pinButtonMode = 3; //toggle button for selecting the mode + +HardwareSerial *serial = &Serial1; + + + /*************************************************************************** * Arduino Leonardo/Yún/Micro (ATmega32U4) ***************************************************************************/ #elif defined (__AVR_ATmega32U4__) -#define USE_LEONARDO -#include +#define HAS_USB_MIDI +#include #define GB_SET(bit_cl, bit_out, bit_in) PORTF = (PINF & B00011111) | ((bit_cl<<7) | ((bit_out)<<6) | ((bit_in)<<5)) // ^ The reason for not using digitalWrite is to allign clock and data pins for the GB shift reg. @@ -200,9 +226,8 @@ HardwareSerial *serial = &Serial1; ***************************************************************************/ #elif defined (__SAM3X8E__) #define USE_DUE - -#define USE_LEONARDO -#include +#define HAS_USB_MIDI +#include #include @@ -267,12 +292,12 @@ boolean sysexProgrammingMode = 0; boolean sysexProgrammingWaiting = 0; boolean sysexProgrammingConnected = 0; -unsigned long sysexProgrammerWaitTime = 2000; //2 seconds -unsigned long sysexProgrammerCallTime = 1000; //1 second +const unsigned long PROGRAMMER_MAX_WAIT_TIME = 2000; //2 seconds +const unsigned long PROGRAMMER_MAX_CALL_TIME = 1000; //1 second unsigned long sysexProgrammerLastResponse = 0; unsigned long sysexProgrammerLastSent = 0; -byte sysexManufacturerId = 0x69; //har har harrrrr :) +const byte SYSEX_MFG_ID = 0x69; //har har harrrrr :) int sysexPosition; byte sysexData[128]; byte longestSysexMessage = 128; @@ -421,6 +446,24 @@ uint8_t mapQueueWaitUsb = 5; //5ms - Needs to be longer because message packet i ***************************************************************************/ #define GB_MIDI_DELAY 500 //Microseconds to delay the sending of a byte to gb +/*************************************************************************** +* MIDI Setup (Serial and USB) +***************************************************************************/ +USING_NAMESPACE_MIDI; + +#ifdef HAS_USB_MIDI +typedef USBMIDI_NAMESPACE::usbMidiTransport __umt; +typedef MIDI_NAMESPACE::MidiInterface<__umt> __ss; +__umt usbMIDI_t(0 /** cable no */); +__ss uMIDI((__umt&)usbMIDI_t); +#endif + +#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) + MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, sMIDI); +#else + MIDI_CREATE_INSTANCE(HardwareSerial, Serial, sMIDI); +#endif + void setup() { /* Init Memory @@ -437,26 +480,23 @@ void setup() { pinMode(pinGBSerialIn,INPUT); pinMode(pinGBSerialOut,OUTPUT); -/* - Set MIDI Serial Rate -*/ - -#ifdef USE_USB - serial->begin(31250); //31250 -#else - if(usbMode == true) { + /* + Set MIDI Serial Rate + */ + if(usbMode) { serial->begin(38400); } else { pinMode(pinMidiInputPower,OUTPUT); digitalWrite(pinMidiInputPower,HIGH); // turn on the optoisolator - #ifdef USE_LEONARDO - Serial1.begin(31250); //31250 - #else - Serial.begin(31250); //31250 + sMIDI.begin(MIDI_CHANNEL_OMNI); + + // Enable serial MIDI in to serial MIDI out "thru mode" + sMIDI.turnThruOn(Thru::Full); + + #ifdef HAS_USB_MIDI + uMIDI.begin(MIDI_CHANNEL_OMNI); #endif } -#endif - /* Set Pin States */ @@ -489,10 +529,7 @@ void setup() { #endif lastMode = memory[MEM_MODE]; -/* - usbMidi sysex support -*/ - usbMidiInit(); + initProgrammerSysexHandlers(); startupSequence(); diff --git a/Arduinoboy/Mode_LSDJ_Keyboard.ino b/Arduinoboy/Mode_LSDJ_Keyboard.ino index ab39ece..927eaae 100644 --- a/Arduinoboy/Mode_LSDJ_Keyboard.ino +++ b/Arduinoboy/Mode_LSDJ_Keyboard.ino @@ -16,9 +16,6 @@ void modeLSDJKeyboardSetup() digitalWrite(pinStatusLed,LOW); pinMode(pinGBClock,OUTPUT); digitalWrite(pinGBClock,HIGH); - #ifdef USE_TEENSY - usbMIDI.setHandleRealTimeSystem(NULL); - #endif blinkMaxCount=1000; /* The stuff below makes sure the code is in the same state as LSDJ on reset / restart, mode switched, etc. */ @@ -38,75 +35,50 @@ void modeLSDJKeyboardSetup() void modeLSDJKeyboard() { - while(1){ //Loop foreverrrr - modeLSDJKeyboardMidiReceive(); - if (serial->available()) { //If MIDI is sending - incomingMidiByte = serial->read(); //Get the byte sent from MIDI - if(!checkForProgrammerSysex(incomingMidiByte) && !usbMode) serial->write(incomingMidiByte);//Echo the Byte to MIDI Output + while (1) { + modeLSDJKeyboardUsbMidiReceive(); + modeLSDJKeyboardSerialMidiReceive(); + updateStatusLed(); // Update our status blinker + setMode(); // Check if mode button was depressed + } +} - /*************************************************************************** - * Midi to LSDJ Keyboard Handling * - ***************************************************************************/ - //If the byte is a Status Message - if(incomingMidiByte & 0x80) { - /* Status message Information (# = midi channel 0 to F [1-16] ) - 0x8# = Note Off - 0x9# = Note On - 0xA# = AfterTouch (ie, key pressure) - 0xB# = Control Change - 0xC# = Program (patch) change - 0xD# = Channel Pressure - 0xE# = Pitch Wheel - 0xF0 - 0xF7 = System Common Messages - 0xF8 - 0xFF = System Realtime Messages - */ +void modeLSDJKeyboardUsbMidiReceive() +{ +#ifdef HAS_USB_MIDI + while(uMIDI.read(memory[MEM_KEYBD_CH]+1)) { - //Weee hello world bitwise and. ... make the second hex digit zero so we can have a simple case statement - // - the second digit is usually the midi channel 0 to F (1-16) unless its a 0xF0 message... - switch (incomingMidiByte & 0xF0) { - case 0x90: - //Note-On Status Message (Note: we have to treat this carefully because note status isnt sent on every note-on, damn it) - //There are 3 bytes total we need: Channel, Note, and velocity, these wil be assigned to a array until we have the velocity, - //at that point we can then call our note out function to LSDJ - midiNoteOnMode = true; //Set our stupid "Note on mode" on - midiData[0] = incomingMidiByte; //Assign the byte to the first position of a data array. (this is the midi channel) - midiData[1] = false; //Force the second position to false (this will hold the note number) - break; - case 0xC0: - //Program change message - midiProgramChange = true; //Set our silly "Program Change mode" ... we need to get the next byte later - midiNoteOnMode = false; //Turn Note-on mode off - midiData[0] = incomingMidiByte - 48;//Set the number to a "note on" message so we can use the same "channel" variable as note on messages - break; - case 0xF0: - //Do nothing, these dont interfear with our note-on mode - break; - default: - //Turn Note-On mode off - midiNoteOnMode = false; - break; - } - } else if(midiNoteOnMode) { - //It wasnt a status bit, so lets assume it was a note message if the last status message was note-on. - if(!midiData[1]) { - //If we dont have a note number, we assume this byte is the note number, get it... - midiData[1] = incomingMidiByte; - } else { - //We have our note and channel, so call our note function... + byte type = uMIDI.getType(); + byte data1 = uMIDI.getData1(); + byte data2 = uMIDI.getData2(); - playLSDJNote(midiData[0], midiData[1], incomingMidiByte); - midiData[1] = false; //Set the note to false, forcing to capture the next note - } - } else if (midiProgramChange) { - changeLSDJInstrument(midiData[0], incomingMidiByte); - midiProgramChange = false; - midiData[0] = false; - } + handleLSDJKeyboardMessage(type, data1, data2); } +#endif +} + +void modeLSDJKeyboardSerialMidiReceive() { + if (!sMIDI.read(memory[MEM_KEYBD_CH])) return; + + byte type = sMIDI.getType(); + byte data1 = sMIDI.getData1(); + byte data2 = sMIDI.getData2(); + + handleLSDJKeyboardMessage(type, data1, data2); +} - updateStatusLed(); // Update our status blinker - setMode(); // Check if mode button was depressed +void handleLSDJKeyboardMessage(byte type, byte data1, byte data2) { + switch(type) { + case midi::NoteOff: + playLSDJNote(midi::NoteOff + memory[MEM_KEYBD_CH], data1, 0); + break; + case midi::NoteOn: + playLSDJNote(midi::NoteOn + memory[MEM_KEYBD_CH], data1, data2); + break; + case midi::ProgramChange: + changeLSDJInstrument(midi::ProgramChange + memory[MEM_KEYBD_CH], data1); + break; } } @@ -118,10 +90,10 @@ void changeLSDJInstrument(byte channel,byte message) { keyboardCurrentIns = message; //set the current instrument number - if(channel == (0x90+memory[MEM_KEYBD_CH]) && keyboardCurrentIns != keyboardLastIns) { + if(channel == (midi::NoteOn+memory[MEM_KEYBD_CH]) && keyboardCurrentIns != keyboardLastIns) { //if its on our midi channel and the instrument isnt the same as our currrent if(!memory[MEM_KEYBD_COMPAT_MODE]) { - sendKeyboardByteToGameboy(0x80 | message); // <- this is suppose to work but doesn't :/ + sendKeyboardByteToGameboy(midi::NoteOff | message); // <- this is suppose to work but doesn't :/ } else { //We will find out which is greater, the current instrument or the last instrument. then //cycle up or down to that instrument @@ -147,7 +119,7 @@ void changeLSDJInstrument(byte channel,byte message) */ void playLSDJNote(byte channel,byte note, byte velocity) { - if(channel == (0x90+memory[MEM_KEYBD_CH]) + if(channel == (midi::NoteOn+memory[MEM_KEYBD_CH]) && velocity > 0x00) { //If midi channel = ours and the velocity is greater then 0 if(note >= keyboardNoteStart) { keyboardNoteOffset = 0; @@ -233,54 +205,4 @@ void sendKeyboardByteToGameboy(byte send_byte) delayMicroseconds(50); GB_SET(1,1,0); delayMicroseconds(4000); -} - -void modeLSDJKeyboardMidiReceive() -{ -#ifdef USE_TEENSY - - while(usbMIDI.read(memory[MEM_KEYBD_CH]+1)) { - switch(usbMIDI.getType()) { - case 0x80: // note off - playLSDJNote(0x90+memory[MEM_KEYBD_CH], usbMIDI.getData1(), 0); - break; - case 0x90: // note on - playLSDJNote(0x90+memory[MEM_KEYBD_CH], usbMIDI.getData1(), usbMIDI.getData2()); - break; - case 0xC0: // PG - changeLSDJInstrument(0xC0+memory[MEM_KEYBD_CH], usbMIDI.getData1()); - break; - /* - case 3: // CC - break; - case 5: // AT - break; - case 6: // PB - break; - */ - } - } -#endif -#ifdef USE_LEONARDO - - midiEventPacket_t rx; - do { - rx = MidiUSB.read(); - switch (rx.header) - { - case 0x08: // note off - playLSDJNote(0x90+memory[MEM_KEYBD_CH], rx.byte2, 0); - statusLedOn(); - break; - case 0x09: // note on - playLSDJNote(0x90+memory[MEM_KEYBD_CH], rx.byte2, rx.byte3); - statusLedOn(); - break; - case 0x0C: // PG - changeLSDJInstrument(0xC0+memory[MEM_KEYBD_CH], rx.byte2); - statusLedOn(); - break; - } - } while (rx.header != 0); -#endif -} +} \ No newline at end of file diff --git a/Arduinoboy/Mode_LSDJ_Map.ino b/Arduinoboy/Mode_LSDJ_Map.ino index cc7fe9d..a114942 100644 --- a/Arduinoboy/Mode_LSDJ_Map.ino +++ b/Arduinoboy/Mode_LSDJ_Map.ino @@ -16,82 +16,22 @@ void modeLSDJMapSetup() digitalWrite(pinStatusLed,LOW); pinMode(pinGBClock,OUTPUT); digitalWrite(pinGBClock, HIGH); - #ifdef USE_TEENSY - usbMIDI.setHandleRealTimeSystem(usbMidiLSDJMapRealtimeMessage); - #endif blinkMaxCount=1000; modeLSDJMap(); } void modeLSDJMap() { - while(1){ //Loop forever + while (1) { + modeLSDJMapUsbMidiReceive(); + checkMapQueue(); - modeLSDJMapUsbMidiReceive(); - checkMapQueue(); - if (serial->available()) { //If MIDI Byte Availaibleleleiel - incomingMidiByte = serial->read(); //Read it - - checkForProgrammerSysex(incomingMidiByte); - - if(incomingMidiByte & 0x80) { //If we have received a MIDI Status Byte - switch (incomingMidiByte) { - case 0xF8: - setMapByte(0xFF, false); - usbMidiSendRTMessage(incomingMidiByte); - break; - case 0xFA: // Case: Transport Start Message - case 0xFB: // and Case: Transport Continue Message - sequencerStart(); // Start the sequencer - usbMidiSendRTMessage(incomingMidiByte); - break; - case 0xFC: // Case: Transport Stop Message - sequencerStop(); - setMapByte(0xFE, false); - usbMidiSendRTMessage(incomingMidiByte); - break; - default: - midiData[0] = incomingMidiByte; - midiNoteOnMode = true; - - if(midiData[0] == (0x90+memory[MEM_LIVEMAP_CH]) - || midiData[0] == (0x90+(memory[MEM_LIVEMAP_CH]+1))) resetMapCue(); - } - } else if(midiNoteOnMode) { //if we've received a message thats not a status and our note capture mode is true - - midiNoteOnMode = false; - midiData[1] = incomingMidiByte; - - usbMidiSendTwoByteMessage(midiData[0],midiData[1]); - if(midiData[0] == (0x90+memory[MEM_LIVEMAP_CH]) - || midiData[0] == (0x90+(memory[MEM_LIVEMAP_CH]+1))) resetMapCue(); - - } else { - midiNoteOnMode = true; - if(midiData[0] == (0x90+memory[MEM_LIVEMAP_CH]) - || midiData[0] == (0x90+(memory[MEM_LIVEMAP_CH]+1))) { - if(incomingMidiByte) { - if(midiData[0] == (0x90+(memory[MEM_LIVEMAP_CH]+1))) { - setMapByte(128+midiData[1], false); - } else { - setMapByte(midiData[1], false); - } - } else { - setMapByte(0xFE, false); - } - } else if (midiData[0] == (0x80+memory[MEM_LIVEMAP_CH]) - || midiData[0] == (0x80+(memory[MEM_LIVEMAP_CH]+1))) { - setMapByte(0xFE, false); - } - usbMidiSendThreeByteMessage(midiData[0], midiData[1], incomingMidiByte); + if (!modeLSDJMapSerialMidiReceive()) { + setMode(); + updateStatusLight(); checkMapQueue(); + updateBlinkLights(); } - } else { - setMode(); //Check if the mode button was depressed - updateStatusLight(); - checkMapQueue(); - updateBlinkLights(); - } } } @@ -103,10 +43,10 @@ void setMapByte(uint8_t b, boolean usb) } switch(b) { - case 0xFF: + case midi::SystemReset: setMapQueueMessage(0xFF, wait); break; - case 0xFE: + case midi::ActiveSensing: if(!sequencerStarted) { sendByteToGameboy(0xFE); } else if (mapCurrentRow >= 0) { @@ -150,86 +90,66 @@ void checkMapQueue() } } +void modeLSDJMapUsbMidiReceive() { +#ifdef HAS_USB_MIDI + while (uMIDI.read()) { -void usbMidiLSDJMapRealtimeMessage(uint8_t message) -{ - switch(message) { - case 0xF8: - setMapByte(0xFF, true); - break; - case 0xFA: // Case: Transport Start Message - case 0xFB: // and Case: Transport Continue Message - resetMapCue(); - sequencerStart(); // Start the sequencer - break; - case 0xFC: // Case: Transport Stop Message - sequencerStop(); // Stop the sequencer - setMapByte(0xFE, true); - break; + byte type = uMIDI.getType(); + byte channel = uMIDI.getChannel() - 1; + byte data1 = uMIDI.getData1(); + + if (channel != memory[MEM_LIVEMAP_CH] && channel != (memory[MEM_LIVEMAP_CH] + 1)){ + continue; } + + handleLsdjMapMessage(type, channel, data1); + } +#endif } -void modeLSDJMapUsbMidiReceive() -{ -#ifdef USE_TEENSY +bool modeLSDJMapSerialMidiReceive() { + if (!sMIDI.read()) return false; - while(usbMIDI.read()) { - uint8_t ch = usbMIDI.getChannel() - 1; - if(ch != memory[MEM_LIVEMAP_CH] && ch != (memory[MEM_LIVEMAP_CH] + 1)){ - continue; - } + byte type = sMIDI.getType(); + byte channel = sMIDI.getChannel() - 1; + byte data1 = sMIDI.getData1(); - switch(usbMIDI.getType()) { - case 0x80: // note off - setMapByte(0xFE, true); - break; - case 0x90: // note on - if(ch == (memory[MEM_LIVEMAP_CH] + 1)) { - setMapByte(128+usbMIDI.getData1(), true); - } else { - setMapByte(usbMIDI.getData1(), true); - } - break; - /* - case 3: // CC - break; - case 4: // PG - break; - case 5: // AT - break; - case 6: // PB - break; - */ - } - } -#endif -#ifdef USE_LEONARDO - midiEventPacket_t rx; - do - { - rx = MidiUSB.read(); - usbMidiLSDJMapRealtimeMessage(rx.byte1); - uint8_t ch = rx.byte1 & 0x0F; - if (ch != memory[MEM_LIVEMAP_CH] && ch != (memory[MEM_LIVEMAP_CH] + 1)) - { - continue; - } - switch (rx.header) - { - case 0x08: // note off - setMapByte(0xFE, true); - break; - case 0x09: // note on - if (ch == (memory[MEM_LIVEMAP_CH] + 1)) - { - setMapByte(128 + rx.byte2, true); - } - else - { - setMapByte(rx.byte2, true); - } - break; - } - } while (rx.header != 0); -#endif + if (channel != memory[MEM_LIVEMAP_CH] && channel != (memory[MEM_LIVEMAP_CH] + 1)){ + return true; + } + + handleLsdjMapMessage(type, channel, data1); + + checkMapQueue(); + return true; } + +void handleLsdjMapMessage(byte type, byte channel, byte data1) { + switch(type) { + case midi::NoteOff: + setMapByte(0xFE, true); + break; + + case midi::NoteOn: + if (channel == (memory[MEM_LIVEMAP_CH] + 1)) { + setMapByte(128 + data1, true); + } else { + setMapByte(data1, true); + } + break; + + // Realtime / clock transport stuff + case midi::Clock: + setMapByte(0xFF, true); + break; + case midi::Start: + case midi::Continue: + resetMapCue(); + sequencerStart(); + break; + case midi::Stop: + sequencerStop(); + setMapByte(0xFE, true); + break; + } +} \ No newline at end of file diff --git a/Arduinoboy/Mode_LSDJ_MasterSync.ino b/Arduinoboy/Mode_LSDJ_MasterSync.ino index fec4a55..01e111a 100644 --- a/Arduinoboy/Mode_LSDJ_MasterSync.ino +++ b/Arduinoboy/Mode_LSDJ_MasterSync.ino @@ -11,16 +11,11 @@ * * ***************************************************************************/ - void modeLSDJMasterSyncSetup() { digitalWrite(pinStatusLed,LOW); pinMode(pinGBClock,INPUT); - #ifdef USE_TEENSY - usbMIDI.setHandleRealTimeSystem(NULL); - #endif - countSyncTime=0; blinkMaxCount=1000; modeLSDJMasterSync(); @@ -28,33 +23,32 @@ void modeLSDJMasterSyncSetup() void modeLSDJMasterSync() { - while(1){ - -#ifdef USE_TEENSY - while(usbMIDI.read()) ; -#endif + while (1) { + // continue to read from MIDI so that the programmer handler is called + #ifdef HAS_USB_MIDI + while (uMIDI.read()) ; + #endif + sMIDI.read(); + + readGbClock(); + sendMidiClockSlaveFromLSDJ(); //send the clock & start offset data to midi + setMode(); + } +} - if (serial->available()) { //If serial data was send to midi input - incomingMidiByte = serial->read(); //Read it - if(!checkForProgrammerSysex(incomingMidiByte) && !usbMode) serial->write(incomingMidiByte); //Send it to the midi output +void readGbClock() { + readgbClockLine = digitalRead(pinGBClock); //Read gameboy's clock line + if(readgbClockLine) { //If Gb's Clock is On + while(readgbClockLine) { //Loop untill its off + readgbClockLine = digitalRead(pinGBClock);//Read the clock again + bit = digitalRead(pinGBSerialIn); //Read the serial input for song position + checkActions(); } - readgbClockLine = digitalRead(pinGBClock); //Read gameboy's clock line - if(readgbClockLine) { //If Gb's Clock is On - while(readgbClockLine) { //Loop untill its off - readgbClockLine = digitalRead(pinGBClock);//Read the clock again - bit = digitalRead(pinGBSerialIn); //Read the serial input for song position - checkActions(); - } - - countClockPause= 0; //Reset our wait timer for detecting a sequencer stop - - readGbSerialIn = readGbSerialIn << 1; //left shift the serial byte by one to append new bit from last loop - readGbSerialIn = readGbSerialIn + bit; //and then add the bit that was read - sendMidiClockSlaveFromLSDJ(); //send the clock & start offset data to midi + countClockPause= 0; //Reset our wait timer for detecting a sequencer stop - } - setMode(); + readGbSerialIn = readGbSerialIn << 1; //left shift the serial byte by one to append new bit from last loop + readGbSerialIn = readGbSerialIn + bit; //and then add the bit that was read } } @@ -76,15 +70,11 @@ boolean checkLSDJStopped() if(sequencerStarted) { readgbClockLine=false; countClockPause = 0; //reset our clock - serial->write(0xFC); //send the transport stop message -#ifdef USE_TEENSY - usbMIDI.sendRealTime(0xFC); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t event = {0x0F, 0xFC}; - MidiUSB.sendMIDI(event); - MidiUSB.flush(); -#endif + sMIDI.sendRealTime(midi::Stop); + #ifdef HAS_USB_MIDI + uMIDI.sendRealTime(midi::Stop); + #endif + sequencerStop(); //call the global sequencer stop function } return true; @@ -92,6 +82,8 @@ boolean checkLSDJStopped() return false; } +#define VELOCITY_MAX 127 + /* sendMidiClockSlaveFromLSDJ waits for 8 clock bits from LSDJ, sends the transport start command if sequencer hasnt started yet, @@ -102,35 +94,22 @@ void sendMidiClockSlaveFromLSDJ() { if(!countGbClockTicks) { //If we hit 8 bits if(!sequencerStarted) { //If the sequencer hasnt started - serial->write((0x90+memory[MEM_LSDJMASTER_MIDI_CH])); //Send the midi channel byte - serial->write(readGbSerialIn); //Send the row value as a note - serial->write(0x7F); //Send a velocity 127 - serial->write(0xFA); //send MIDI transport start message - -#ifdef USE_TEENSY - usbMIDI.sendNoteOn(memory[MEM_LSDJMASTER_MIDI_CH]+1,readGbSerialIn,0x7F); - usbMIDI.sendRealTime(0xFA); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t event = {0x09, 0x90 | memory[MEM_LSDJMASTER_MIDI_CH] + 1, readGbSerialIn, 0x7F}; - MidiUSB.sendMIDI(event); - MidiUSB.flush(); - event = {0x0F, 0xFA}; - MidiUSB.sendMIDI(event); - MidiUSB.flush(); -#endif + //Send the row value as a note + sMIDI.sendNoteOn(readGbSerialIn, VELOCITY_MAX, memory[MEM_LSDJMASTER_MIDI_CH]+1); + sMIDI.sendRealTime(midi::Start); + + #ifdef HAS_USB_MIDI + uMIDI.sendNoteOn(readGbSerialIn, VELOCITY_MAX, memory[MEM_LSDJMASTER_MIDI_CH]+1); + uMIDI.sendRealTime(midi::Start); + #endif + sequencerStart(); //call the global sequencer start function } - serial->write(0xF8); //Send the MIDI Clock Tick - -#ifdef USE_TEENSY - usbMIDI.sendRealTime(0xF8); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t event = {0x0F, 0xF8}; - MidiUSB.sendMIDI(event); - MidiUSB.flush(); -#endif + sMIDI.sendRealTime(midi::Clock); + #ifdef HAS_USB_MIDI + uMIDI.sendRealTime(midi::Clock); + #endif + countGbClockTicks=0; //Reset the bit counter readGbSerialIn = 0x00; //Reset our serial read value diff --git a/Arduinoboy/Mode_LSDJ_Midiout.ino b/Arduinoboy/Mode_LSDJ_Midiout.ino index 47427e7..990da02 100644 --- a/Arduinoboy/Mode_LSDJ_Midiout.ino +++ b/Arduinoboy/Mode_LSDJ_Midiout.ino @@ -17,10 +17,6 @@ void modeLSDJMidioutSetup() pinMode(pinGBClock,OUTPUT); digitalWrite(pinGBClock,HIGH); - #ifdef USE_TEENSY - usbMIDI.setHandleRealTimeSystem(NULL); - #endif - countGbClockTicks=0; lastMidiData[0] = -1; lastMidiData[1] = -1; @@ -31,52 +27,34 @@ void modeLSDJMidioutSetup() void modeLSDJMidiout() { -#ifdef USE_LEONARDO - midiEventPacket_t packet; -#endif - while(1){ + while(1) { if(getIncommingSlaveByte()) { if(incomingMidiByte > 0x6f) { switch(incomingMidiByte) { - case 0x7F: //clock tick - serial->write(0xF8); -#ifdef USE_TEENSY - usbMIDI.sendRealTime((int)0xF8); -#endif -#ifdef USE_LEONARDO - packet = {0x0F, 0xF8}; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif - break; - case 0x7E: //seq stop - serial->write(0xFC); -#ifdef USE_TEENSY - usbMIDI.sendRealTime((int)0xFC); -#endif -#ifdef USE_LEONARDO - packet = {0x0F, 0xFC}; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif - stopAllNotes(); - break; - case 0x7D: //seq start - serial->write(0xFA); -#ifdef USE_TEENSY - usbMIDI.sendRealTime((int)0xFA); -#endif -#ifdef USE_LEONARDO - packet = {0x0F, 0xFA}; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif - break; - default: - midiData[0] = (incomingMidiByte - 0x70); - midiValueMode = true; - break; + case 0x7F: //clock tick + sMIDI.sendRealTime(midi::Clock); + #ifdef HAS_USB_MIDI + uMIDI.sendRealTime(midi::Clock); + #endif + break; + case 0x7E: //seq stop + sMIDI.sendRealTime(midi::Stop); + #ifdef HAS_USB_MIDI + uMIDI.sendRealTime(midi::Stop); + #endif + stopAllNotes(); + break; + case 0x7D: //seq start + sMIDI.sendRealTime(midi::Start); + #ifdef HAS_USB_MIDI + uMIDI.sendRealTime(midi::Start); + #endif + break; + default: + midiData[0] = (incomingMidiByte - 0x70); + midiValueMode = true; + break; } } else if (midiValueMode == true) { midiValueMode = false; @@ -86,15 +64,11 @@ void modeLSDJMidiout() } else { setMode(); // Check if mode button was depressed updateBlinkLights(); -#ifdef USE_TEENSY - while(usbMIDI.read()) ; -#endif -#ifdef USE_LEONARDO - // while (MidiUSB.read()) ; -#endif - if (serial->available()) { //If serial data was send to midi inp - checkForProgrammerSysex(serial->read()); - } + // read from MIDI to detect programmer messages + sMIDI.read(); + #ifdef HAS_USB_MIDI + while(uMIDI.read()) ; + #endif } } } @@ -130,18 +104,10 @@ void checkStopNote(byte m) void stopNote(byte m) { for(int x=0;xwrite(midiData,3); -#ifdef USE_TEENSY - usbMIDI.sendNoteOff(midioutNoteHold[m][x], 0, memory[MEM_MIDIOUT_NOTE_CH+m]+1); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t packet = { 0x08, 0x80 | memory[MEM_MIDIOUT_NOTE_CH + m], midioutNoteHold[m][x], 0 }; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif + sMIDI.sendNoteOff(midioutNoteHold[m][x], 0, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #ifdef HAS_USB_MIDI + uMIDI.sendNoteOff(midioutNoteHold[m][x], 0, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #endif } midiOutLastNote[m] = -1; midioutNoteHoldCounter[m] = 0; @@ -149,18 +115,10 @@ void stopNote(byte m) void playNote(byte m, byte n) { - midiData[0] = (0x90 + (memory[MEM_MIDIOUT_NOTE_CH+m])); - midiData[1] = n; - midiData[2] = 0x7F; - serial->write(midiData,3); -#ifdef USE_TEENSY - usbMIDI.sendNoteOn(n, 127, memory[MEM_MIDIOUT_NOTE_CH+m]+1); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t packet = { 0x09, 0x90 | memory[MEM_MIDIOUT_NOTE_CH + m], n, 127 }; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif + sMIDI.sendNoteOn(n, 127, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #ifdef HAS_USB_MIDI + uMIDI.sendNoteOn(n, 127, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #endif midioutNoteHold[m][midioutNoteHoldCounter[m]] =n; midioutNoteHoldCounter[m]++; @@ -178,18 +136,10 @@ void playCC(byte m, byte n) //if(v) v --; } n=(m*7)+((n>>4) & 0x07); - midiData[0] = (0xB0 + (memory[MEM_MIDIOUT_CC_CH+m])); - midiData[1] = (memory[MEM_MIDIOUT_CC_NUMBERS+n]); - midiData[2] = v; - serial->write(midiData,3); -#ifdef USE_TEENSY - usbMIDI.sendControlChange((memory[MEM_MIDIOUT_CC_NUMBERS+n]), v, memory[MEM_MIDIOUT_NOTE_CH+m]+1); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t packet = {0x0B, 0xB0 | (memory[MEM_MIDIOUT_NOTE_CH + m]+1), (memory[MEM_MIDIOUT_CC_NUMBERS + n]), v}; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif + sMIDI.sendControlChange((memory[MEM_MIDIOUT_CC_NUMBERS+n]), v, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #ifdef HAS_USB_MIDI + uMIDI.sendControlChange((memory[MEM_MIDIOUT_CC_NUMBERS+n]), v, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #endif } else { if(memory[MEM_MIDIOUT_CC_SCALING+m]) { float s; @@ -197,34 +147,20 @@ void playCC(byte m, byte n) v = ((s / 0x6f) * 0x7f); } n=(m*7); - midiData[0] = (0xB0 + (memory[MEM_MIDIOUT_CC_CH+m])); - midiData[1] = (memory[MEM_MIDIOUT_CC_NUMBERS+n]); - midiData[2] = v; - serial->write(midiData,3); -#ifdef USE_TEENSY - usbMIDI.sendControlChange((memory[MEM_MIDIOUT_CC_NUMBERS+n]), v, memory[MEM_MIDIOUT_NOTE_CH+m]+1); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t packet = {0x0B, 0xB0 | (memory[MEM_MIDIOUT_NOTE_CH + m]+1), (memory[MEM_MIDIOUT_CC_NUMBERS + n]), v}; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif + + sMIDI.sendControlChange((memory[MEM_MIDIOUT_CC_NUMBERS+n]), v, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #ifdef HAS_USB_MIDI + uMIDI.sendControlChange((memory[MEM_MIDIOUT_CC_NUMBERS+n]), v, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #endif } } void playPC(byte m, byte n) { - midiData[0] = (0xC0 + (memory[MEM_MIDIOUT_NOTE_CH+m])); - midiData[1] = n; - serial->write(midiData,2); -#ifdef USE_TEENSY - usbMIDI.sendProgramChange(n, memory[MEM_MIDIOUT_NOTE_CH+m]+1); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t packet = {0x0C, 0xC0 | (memory[MEM_MIDIOUT_NOTE_CH + m]+1), n}; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif + sMIDI.sendProgramChange(n, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #ifdef HAS_USB_MIDI + uMIDI.sendProgramChange(n, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #endif } void stopAllNotes() @@ -233,18 +169,10 @@ void stopAllNotes() if(midiOutLastNote[m]>=0) { stopNote(m); } - midiData[0] = (0xB0 + (memory[MEM_MIDIOUT_NOTE_CH+m])); - midiData[1] = 123; - midiData[2] = 0x7F; - serial->write(midiData,3); //Send midi -#ifdef USE_TEENSY - usbMIDI.sendControlChange(123, 127, memory[MEM_MIDIOUT_NOTE_CH+m]+1); -#endif -#ifdef USE_LEONARDO - midiEventPacket_t packet = {0x0B, 0xB0 | memory[MEM_MIDIOUT_NOTE_CH + m], 123, 127}; - MidiUSB.sendMIDI(packet); - MidiUSB.flush(); -#endif + sMIDI.sendControlChange(123, 127, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #ifdef HAS_USB_MIDI + uMIDI.sendControlChange(123, 127, memory[MEM_MIDIOUT_NOTE_CH+m]+1); + #endif } } diff --git a/Arduinoboy/Mode_LSDJ_SlaveSync.ino b/Arduinoboy/Mode_LSDJ_SlaveSync.ino index edebe20..36175d0 100644 --- a/Arduinoboy/Mode_LSDJ_SlaveSync.ino +++ b/Arduinoboy/Mode_LSDJ_SlaveSync.ino @@ -17,67 +17,18 @@ void modeLSDJSlaveSyncSetup() pinMode(pinGBClock,OUTPUT); digitalWrite(pinGBClock,HIGH); -#ifdef USE_TEENSY - usbMIDI.setHandleRealTimeSystem(usbMidiLSDJSlaveRealtimeMessage); -#endif - blinkMaxCount=1000; modeLSDJSlaveSync(); } void modeLSDJSlaveSync() { - while(1){ //Loop forever - modeLSDJSlaveSyncUsbMidiReceive(); - if (serial->available()) { //If MIDI Byte Availaibleleleiel - incomingMidiByte = serial->read(); //Read it - - if(!checkForProgrammerSysex(incomingMidiByte) && !usbMode) serial->write(incomingMidiByte); //Send it back to the Midi out - - if(incomingMidiByte & 0x80) { //If we have received a MIDI Status Byte - switch (incomingMidiByte) { - case 0xF8: //Case: Clock Message Recieved - if((sequencerStarted && midiSyncEffectsTime && !countSyncTime) //If the seq has started and our sync effect is on and at zero - || (sequencerStarted && !midiSyncEffectsTime)) { //or seq is started and there is no sync effects - if(!countSyncPulse && midiDefaultStartOffset) { //if we received a note for start offset - //sendByteToGameboy(midiDefaultStartOffset); //send the offset - } - sendClockTickToLSDJ(); //send the clock tick - updateVisualSync(); - } - if(midiSyncEffectsTime) { //If sync effects are turned on - countSyncTime++; //increment our tick counter - countSyncTime = countSyncTime % countSyncSteps; //and mod it by the number of steps we want for the effect - } - break; - case 0xFA: // Case: Transport Start Message - case 0xFB: // and Case: Transport Continue Message - sequencerStart(); // Start the sequencer - break; - case 0xFC: // Case: Transport Stop Message - sequencerStop(); // Stop the sequencer - break; - default: - if(incomingMidiByte == (0x90+memory[MEM_LSDJSLAVE_MIDI_CH])) { //if a midi note was received and its on the channel of the sync effects channel - midiNoteOnMode = true; //turn on note capture - midiData[0] = false; //and reset the captured note - } else { - midiNoteOnMode = false; //turn off note capture - } - } - } else if(midiNoteOnMode) { //if we've received a message thats not a status and our note capture mode is true - if(!midiData[0]) { //if there is no note number yet - midiData[0] = incomingMidiByte; //then assume the byte is a note and assign it to a place holder - } else { //else assumed velocity - if(incomingMidiByte > 0x00) { - getSlaveSyncEffect(midiData[0]); //then call our sync effects function - } - midiData[0] = false; //and reset the captured note - } - } - } - setMode(); //Check if the mode button was depressed - updateStatusLight(); + while (1) { + modeLSDJSlaveSyncUsbMidiReceive(); + modeLSDJSlaveSyncSerialMidiReceive(); + + setMode(); //Check if the mode button was depressed + updateStatusLight(); } } @@ -130,96 +81,60 @@ void getSlaveSyncEffect(byte note) } } -void usbMidiLSDJSlaveRealtimeMessage(uint8_t message) +void modeLSDJSlaveSyncUsbMidiReceive() { - switch(message) { - case 0xF8: - if((sequencerStarted && midiSyncEffectsTime && !countSyncTime) //If the seq has started and our sync effect is on and at zero - || (sequencerStarted && !midiSyncEffectsTime)) { //or seq is started and there is no sync effects - if(!countSyncPulse && midiDefaultStartOffset) { //if we received a note for start offset - //sendByteToGameboy(midiDefaultStartOffset); //send the offset - } - sendClockTickToLSDJ(); //send the clock tick - updateVisualSync(); - } - if(midiSyncEffectsTime) { //If sync effects are turned on - countSyncTime++; //increment our tick counter - countSyncTime = countSyncTime % countSyncSteps; //and mod it by the number of steps we want for the effect - } - break; - case 0xFA: // Case: Transport Start Message - case 0xFB: // and Case: Transport Continue Message - sequencerStart(); // Start the sequencer - break; - case 0xFC: // Case: Transport Stop Message - sequencerStop(); - break; - } -} +#ifdef HAS_USB_MIDI + while (uMIDI.read()) { + byte type = uMIDI.getType(); + byte channel = uMIDI.getChannel(); + byte data1 = uMIDI.getData1(); + handleLsdjSlaveSyncMessage(type, channel, data1); + } +#endif +} -void modeLSDJSlaveSyncUsbMidiReceive() +void modeLSDJSlaveSyncSerialMidiReceive() { -#ifdef USE_TEENSY + if (!sMIDI.read()) return; - while(usbMIDI.read(memory[MEM_LSDJSLAVE_MIDI_CH]+1)) { - switch(usbMIDI.getType()) { - case 0x90: // note on - getSlaveSyncEffect(usbMIDI.getData1()); - break; - /* - case 0: // note on - break; - case 3: // CC - break; - case 4: // PG - break; - case 5: // AT - break; - case 6: // PB - break; - */ - } - } -#endif -#ifdef USE_LEONARDO + byte type = sMIDI.getType(); + byte channel = sMIDI.getChannel(); + byte data1 = sMIDI.getData1(); + + handleLsdjSlaveSyncMessage(type, channel, data1); +} - midiEventPacket_t rx; - do - { - rx = MidiUSB.read(); - uint8_t ch = rx.byte1 & 0x0F; - if (ch == memory[MEM_LSDJSLAVE_MIDI_CH] && rx.header == 0x09) - { - getSlaveSyncEffect(rx.byte2); +void handleLsdjSlaveSyncMessage(byte type, byte channel, byte data1) { + switch (type) { + case midi::NoteOn: + if (channel == memory[MEM_LSDJSLAVE_MIDI_CH]+1) { + getSlaveSyncEffect(data1); } - switch (rx.byte1) - { - case 0xF8: - if ((sequencerStarted && midiSyncEffectsTime && !countSyncTime) //If the seq has started and our sync effect is on and at zero - || (sequencerStarted && !midiSyncEffectsTime)) - { //or seq is started and there is no sync effects - if (!countSyncPulse && midiDefaultStartOffset) - { //if we received a note for start offset - //sendByteToGameboy(midiDefaultStartOffset); //send the offset - } - sendClockTickToLSDJ(); //send the clock tick - updateVisualSync(); - } - if (midiSyncEffectsTime) - { //If sync effects are turned on - countSyncTime++; //increment our tick counter - countSyncTime = countSyncTime % countSyncSteps; //and mod it by the number of steps we want for the effect + break; + case midi::Clock: + if ((sequencerStarted && midiSyncEffectsTime && !countSyncTime) //If the seq has started and our sync effect is on and at zero + || (sequencerStarted && !midiSyncEffectsTime)) + { //or seq is started and there is no sync effects + if (!countSyncPulse && midiDefaultStartOffset) + { //if we received a note for start offset + //sendByteToGameboy(midiDefaultStartOffset); //send the offset } - break; - case 0xFA: // Case: Transport Start Message - case 0xFB: // and Case: Transport Continue Message - sequencerStart(); // Start the sequencer - break; - case 0xFC: // Case: Transport Stop Message - sequencerStop(); - break; + sendClockTickToLSDJ(); //send the clock tick + updateVisualSync(); } - } while (rx.header != 0); -#endif + if (midiSyncEffectsTime) + { //If sync effects are turned on + countSyncTime++; //increment our tick counter + countSyncTime = countSyncTime % countSyncSteps; //and mod it by the number of steps we want for the effect + } + break; + case midi::Start: + case midi::Continue: + sequencerStart(); + break; + case midi::Stop: + sequencerStop(); + break; + } } diff --git a/Arduinoboy/Mode_MidiGb.ino b/Arduinoboy/Mode_MidiGb.ino index 5df6a7b..4b5e624 100644 --- a/Arduinoboy/Mode_MidiGb.ino +++ b/Arduinoboy/Mode_MidiGb.ino @@ -17,79 +17,19 @@ void modeMidiGbSetup() pinMode(pinGBClock,OUTPUT); digitalWrite(pinGBClock,HIGH); -#ifdef USE_TEENSY - usbMIDI.setHandleRealTimeSystem(NULL); -#endif - blinkMaxCount=1000; modeMidiGb(); } +// Are we capturing SysEx bytes? +bool isSysexMessage = false; + void modeMidiGb() { - boolean sendByte = false; - while(1){ //Loop foreverrrr + while(1) { modeMidiGbUsbMidiReceive(); - if (serial->available()) { //If MIDI is sending - incomingMidiByte = serial->read(); //Get the byte sent from MIDI - - if(!checkForProgrammerSysex(incomingMidiByte) && !usbMode) serial->write(incomingMidiByte); //Echo the Byte to MIDI Output - - if(incomingMidiByte & 0x80) { - switch (incomingMidiByte & 0xF0) { - case 0xF0: - midiValueMode = false; - break; - default: - sendByte = false; - midiStatusChannel = incomingMidiByte&0x0F; - midiStatusType = incomingMidiByte&0xF0; - if(midiStatusChannel == memory[MEM_MGB_CH]) { - midiData[0] = midiStatusType; - sendByte = true; - } else if (midiStatusChannel == memory[MEM_MGB_CH+1]) { - midiData[0] = midiStatusType+1; - sendByte = true; - } else if (midiStatusChannel == memory[MEM_MGB_CH+2]) { - midiData[0] = midiStatusType+2; - sendByte = true; - } else if (midiStatusChannel == memory[MEM_MGB_CH+3]) { - midiData[0] = midiStatusType+3; - sendByte = true; - } else if (midiStatusChannel == memory[MEM_MGB_CH+4]) { - midiData[0] = midiStatusType+4; - sendByte = true; - } else { - midiValueMode =false; - midiAddressMode=false; - } - if(sendByte) { - statusLedOn(); - sendByteToGameboy(midiData[0]); - delayMicroseconds(GB_MIDI_DELAY); - midiValueMode =false; - midiAddressMode=true; - } - break; - } - } else if (midiAddressMode){ - midiAddressMode = false; - midiValueMode = true; - midiData[1] = incomingMidiByte; - sendByteToGameboy(midiData[1]); - delayMicroseconds(GB_MIDI_DELAY); - } else if (midiValueMode) { - midiData[2] = incomingMidiByte; - midiAddressMode = true; - midiValueMode = false; - - sendByteToGameboy(midiData[2]); - delayMicroseconds(GB_MIDI_DELAY); - statusLedOn(); - blinkLight(midiData[0],midiData[2]); - } - } else { + if (!modeMidiGbSerialReceive()) { setMode(); // Check if mode button was depressed updateBlinkLights(); updateStatusLed(); @@ -119,148 +59,145 @@ void sendByteToGameboy(byte send_byte) } } +/** Send multiple raw bytes to GB (e.g. a SysEx payload) */ +void sendBytesToGameboy(const byte *bytes, uint8_t length) { + // Serial.print("Sending bytes: "); + for (uint8_t i = 0; i < length; i++) { + byte b = bytes[i]; + // Serial.print(b, 0xF); + // Serial.print(" "); + sendByteToGameboy(b); + delayMicroseconds(GB_MIDI_DELAY); + } + // Serial.println(""); +} + void modeMidiGbUsbMidiReceive() { -#ifdef USE_TEENSY - - while(usbMIDI.read()) { - uint8_t ch = usbMIDI.getChannel() - 1; - boolean send = false; - if(ch == memory[MEM_MGB_CH]) { - ch = 0; - send = true; - } else if (ch == memory[MEM_MGB_CH+1]) { - ch = 1; - send = true; - } else if (ch == memory[MEM_MGB_CH+2]) { - ch = 2; - send = true; - } else if (ch == memory[MEM_MGB_CH+3]) { - ch = 3; - send = true; - } else if (ch == memory[MEM_MGB_CH+4]) { - ch = 4; - send = true; - } - if(!send) return; - uint8_t s; - switch(usbMIDI.getType()) { - case 0x80: // note off - case 0x90: // note on - s = 0x90 + ch; - if(usbMIDI.getType() == 0x80) { - s = 0x80 + ch; - } - sendByteToGameboy(s); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(usbMIDI.getData1()); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(usbMIDI.getData2()); - delayMicroseconds(GB_MIDI_DELAY); - blinkLight(s, usbMIDI.getData2()); - break; - case 0xB0: // CC - sendByteToGameboy(0xB0+ch); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(usbMIDI.getData1()); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(usbMIDI.getData2()); - delayMicroseconds(GB_MIDI_DELAY); - blinkLight(0xB0+ch, usbMIDI.getData2()); - break; - case 0xC0: // PG - sendByteToGameboy(0xC0+ch); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(usbMIDI.getData1()); - delayMicroseconds(GB_MIDI_DELAY); - blinkLight(0xC0+ch, usbMIDI.getData2()); - break; - case 0xE0: // PB - sendByteToGameboy(0xE0+ch); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(usbMIDI.getData1()); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(usbMIDI.getData2()); - delayMicroseconds(GB_MIDI_DELAY); - break; - } - - statusLedOn(); +#ifdef HAS_USB_MIDI + while (uMIDI.read()) { + byte type = uMIDI.getType(); + byte channel = uMIDI.getChannel() == 0 ? 0 : uMIDI.getChannel() - 1; + byte data1 = uMIDI.getData1(); + byte data2 = uMIDI.getData2(); + + if (type == midi::SystemExclusive) { + sendBytesToGameboy(uMIDI.getSysExArray(), uMIDI.getSysExArrayLength()); + } else { + sendMidiMessageToGameboy(type, channel, data1, data2); } + + statusLedOn(); + } #endif +} -#ifdef USE_LEONARDO +bool modeMidiGbSerialReceive() { + if (!sMIDI.read()) { return false; } - midiEventPacket_t rx; - do - { - rx = MidiUSB.read(); - uint8_t ch = rx.byte1 & 0x0F; - boolean send = false; - if(ch == memory[MEM_MGB_CH]) { - ch = 0; - send = true; - } else if (ch == memory[MEM_MGB_CH+1]) { - ch = 1; - send = true; - } else if (ch == memory[MEM_MGB_CH+2]) { - ch = 2; - send = true; - } else if (ch == memory[MEM_MGB_CH+3]) { - ch = 3; - send = true; - } else if (ch == memory[MEM_MGB_CH+4]) { - ch = 4; - send = true; - } - if (!send) return; - uint8_t s; - switch (rx.header) - { - case 0x08: // note off - case 0x09: // note on - s = 0x90 + ch; - if (rx.header == 0x08) - { - s = 0x80 + ch; - } - sendByteToGameboy(s); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(rx.byte2); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(rx.byte3); - delayMicroseconds(GB_MIDI_DELAY); - blinkLight(s, rx.byte2); - break; - case 0x0B: // CC - sendByteToGameboy(0xB0 + ch); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(rx.byte2); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(rx.byte3); - delayMicroseconds(GB_MIDI_DELAY); - blinkLight(0xB0 + ch, rx.byte2); - break; - case 0x0C: // PG - sendByteToGameboy(0xC0 + ch); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(rx.byte2); - delayMicroseconds(GB_MIDI_DELAY); - blinkLight(0xC0 + ch, rx.byte2); - break; - case 0x0E: // PB - sendByteToGameboy(0xE0 + ch); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(rx.byte2); - delayMicroseconds(GB_MIDI_DELAY); - sendByteToGameboy(rx.byte3); - delayMicroseconds(GB_MIDI_DELAY); - break; - default: - return; - } + byte type = sMIDI.getType(); + byte channel = sMIDI.getChannel() == 0 ? 0 : sMIDI.getChannel() - 1; + byte data1 = sMIDI.getData1(); + byte data2 = sMIDI.getData2(); - statusLedOn(); - } while (rx.header != 0); -#endif + + if (type == midi::SystemExclusive) { + sendBytesToGameboy(sMIDI.getSysExArray(), sMIDI.getSysExArrayLength()); + } else { + sendMidiMessageToGameboy(type, channel, data1, data2); + } + + statusLedOn(); + return true; +} + +/** + * Send a MIDI message to GB + * @param type The type (Status without channel e.g. 0x90), or the status message + * @param channel A 0 indexed channel + * @param data1 The second message byte + * @param data1 The third message byte + */ +void sendMidiMessageToGameboy(byte type, byte channel, byte data1, byte data2) { + byte data0 = type | mappedChannel(channel); + + switch (type) + { + // 1 byte messages + // case midi::Tick: // filtered + // case midi::ActiveSensing: // filtered + case midi::TuneRequest: + case midi::Start: + case midi::Continue: + case midi::Stop: + case midi::Clock: + case midi::SystemReset: + sendByteToGameboy(type); + delayMicroseconds(GB_MIDI_DELAY); + break; + + // 2 byte messages + case midi::ProgramChange: + case midi::SongSelect: + // case midi::AfterTouchChannel: // filtered + // case midi::TimeCodeQuarterFrame: // filtered + sendByteToGameboy(data0); + delayMicroseconds(GB_MIDI_DELAY); + sendByteToGameboy(data1); + delayMicroseconds(GB_MIDI_DELAY); + break; + + // 3 byte messages + case midi::SongPosition: + // case midi::AfterTouchPoly: // filtered + case midi::NoteOn: + case midi::NoteOff: + case midi::ControlChange: + case midi::PitchBend: + sendByteToGameboy(data0); + delayMicroseconds(GB_MIDI_DELAY); + + sendByteToGameboy(data1); + delayMicroseconds(GB_MIDI_DELAY); + + sendByteToGameboy(data2); + delayMicroseconds(GB_MIDI_DELAY); + + blinkLight(data0, data2); + break; + default: + break; + } +} + +#define MGB_PU1 0 +#define MGB_PU2 1 +#define MGB_WAV 2 +#define MGB_NOI 3 +#define MGB_POLY 4 + +/** + * Redirects the configured input midi channel to the correct GB midi channel. e.g. + * Config channel for PU1 (CH1) might be MIDI channel 5, it will redirect input CH5 to + * output CH1 for the GB (Since mGB has fixed channels) + */ +uint8_t mappedChannel(uint8_t inputChannel) { + uint8_t customPU1 = memory[MEM_MGB_CH + MGB_PU1]; + uint8_t customPU2 = memory[MEM_MGB_CH + MGB_PU2]; + uint8_t customWAV = memory[MEM_MGB_CH + MGB_WAV]; + uint8_t customNOI = memory[MEM_MGB_CH + MGB_NOI]; + uint8_t customPOLY = memory[MEM_MGB_CH + MGB_POLY]; + + if (inputChannel == customPU1) + return MGB_PU1; + if (inputChannel == customPU2) + return MGB_PU2; + if (inputChannel == customWAV) + return MGB_WAV; + if (inputChannel == customNOI) + return MGB_NOI; + if (inputChannel == customPOLY) + return MGB_POLY; + + return inputChannel; } diff --git a/Arduinoboy/Mode_Nanoloop.ino b/Arduinoboy/Mode_Nanoloop.ino index 1975d0f..26c6c14 100644 --- a/Arduinoboy/Mode_Nanoloop.ino +++ b/Arduinoboy/Mode_Nanoloop.ino @@ -17,53 +17,18 @@ void modeNanoloopSetup() pinMode(pinGBClock,OUTPUT); digitalWrite(pinGBClock,HIGH); -#ifdef USE_TEENSY - usbMIDI.setHandleRealTimeSystem(usbMidiNanoloopRealtimeMessage); -#endif - blinkMaxCount=1000; modeNanoloopSync(); } void modeNanoloopSync() { - while(1){ //Loop forever - modeNanoloopUsbMidiReceive(); - if (serial->available()) { //If MIDI Byte Availaibleleleiel - incomingMidiByte = serial->read(); //Read it - if(!checkForProgrammerSysex(incomingMidiByte) && !usbMode) serial->write(incomingMidiByte); //Send it back to the Midi out + while (1) { + modeNanoloopUsbMidiReceive(); + modeNanoloopSerialMidiReceive(); - - if(incomingMidiByte & 0x80) { - switch (incomingMidiByte) { - case 0xF8: // Clock Message Recieved - // Send a clock tick out if the sequencer is running - if(sequencerStarted) { - nanoSkipSync = !nanoSkipSync; - if(countSyncTime) { - nanoState = sendTickToNanoloop(nanoState, false); - } else { - nanoState = sendTickToNanoloop(true, true); - } - nanoState = sendTickToNanoloop(nanoState, nanoSkipSync); - updateVisualSync(); - break; - } - break; - case 0xFA: // Transport Start Message - case 0xFB: // Transport Continue Message - sequencerStart(); - break; - case 0xFC: // Transport Stop Message - sequencerStop(); - break; - default: - break; - } - } - } - setMode(); //Check if the mode button was depressed - updateStatusLight(); + setMode(); //Check if the mode button was depressed + updateStatusLight(); } } @@ -85,63 +50,64 @@ boolean sendTickToNanoloop(boolean state, boolean last_state) } } -void usbMidiNanoloopRealtimeMessage(uint8_t message) -{ - switch(message) { - case 0xF8: - if(sequencerStarted) { - nanoSkipSync = !nanoSkipSync; - if(countSyncTime) { - nanoState = sendTickToNanoloop(nanoState, false); - } else { - nanoState = sendTickToNanoloop(true, true); - } - nanoState = sendTickToNanoloop(nanoState, nanoSkipSync); - updateVisualSync(); - } - break; - case 0xFA: // Case: Transport Start Message - case 0xFB: // and Case: Transport Continue Message - sequencerStart(); // Start the sequencer - break; - case 0xFC: // Case: Transport Stop Message - sequencerStop(); - break; - } -} - void modeNanoloopUsbMidiReceive() { -#ifdef USE_TEENSY - while(usbMIDI.read(memory[MEM_LSDJSLAVE_MIDI_CH]+1)) { - switch(usbMIDI.getType()) { - case 0x90: // note on - getSlaveSyncEffect(usbMIDI.getData1()); - break; - /* - case 0: // note on - break; - case 3: // CC - break; - case 4: // PG - break; - case 5: // AT - break; - case 6: // PB - break; - */ - } - } -#endif +#ifdef HAS_USB_MIDI + while (uMIDI.read()) { + // checkForUsbProgrammerSysex(&usbMIDI); + + byte type = uMIDI.getType(); + byte channel = uMIDI.getChannel(); + byte data1 = uMIDI.getData1(); -#ifdef USE_LEONARDO - midiEventPacket_t rx; - do - { - rx = MidiUSB.read(); - usbMidiNanoloopRealtimeMessage(rx.byte1); - } while (rx.header != 0); + handleNanoloopMessage(type, channel, data1); + } #endif +} +void modeNanoloopSerialMidiReceive() +{ + while (sMIDI.read()) { + // checkForSerialProgrammerSysex(&sMIDI); + + byte type = sMIDI.getType(); + byte channel = sMIDI.getChannel(); + byte data1 = sMIDI.getData1(); + + handleNanoloopMessage(type, channel, data1); + } } + +void handleNanoloopMessage(byte type, byte channel, byte data1) { + switch (type) { + // Note handling was in Teensy code, but not in serial midi code. + // assuming it was accidental copy paste from LSDJ Slave code. + // leaving it out + + // case midi::NoteOn: + // if (channel == memory[MEM_LSDJSLAVE_MIDI_CH]+1) { + // getSlaveSyncEffect(data1); + // } + // break; + case midi::Clock: + if(sequencerStarted) { + nanoSkipSync = !nanoSkipSync; + if(countSyncTime) { + nanoState = sendTickToNanoloop(nanoState, false); + } else { + nanoState = sendTickToNanoloop(true, true); + } + nanoState = sendTickToNanoloop(nanoState, nanoSkipSync); + updateVisualSync(); + } + break; + case midi::Start: + case midi::Continue: + sequencerStart(); + break; + case midi::Stop: + sequencerStop(); + break; + } +} \ No newline at end of file diff --git a/Arduinoboy/Mode_Programmer.ino b/Arduinoboy/Mode_Programmer.ino index 823ad7c..f4cabca 100644 --- a/Arduinoboy/Mode_Programmer.ino +++ b/Arduinoboy/Mode_Programmer.ino @@ -1,93 +1,130 @@ +#define MSG_CONNECT 72 +#define MSG_HEARTBEAT 0x7F +#define MSG_CONNECT_REQ 64 +#define MSG_CONNECT_REQ_ACK 65 +#define MSG_CONNECTED 66 + +#define MSG_SETTINGS 0x40 +#define MSG_MODE 0x41 + +#define MSG_SETTNGS_SET 70 +#define MSG_SETTINGS_RESET 71 +#define MSG_SETTNGS_GET 76 +#define MSG_MODE_GET 73 +#define MSG_MODE_SET 74 +#define MSG_MIDI_OUT_DELAY_SET 75 + void modeProgrammer() { + Serial.println("++ Entered programming mode"); + while(sysexProgrammingConnected || sysexProgrammingMode) { checkProgrammerConnected(); - if (serial->available()) checkForProgrammerSysex(serial->read()); + + modeProgrammerSerialMidiReceive(); + modeProgrammerUsbMidiReceive(); + updateProgrammerLeds(); setMode(); - usbMidiUpdate(); } showSelectedMode(); + Serial.println("-- Exiting programming mode"); switchMode(); } +void modeProgrammerSerialMidiReceive() { + // while in programmer mode, we still need to read the MIDI, but the + // programmer handles all of the messages in systemExclusiveHandler + if (!sMIDI.read()) { return; } +} + +void modeProgrammerUsbMidiReceive() { + #ifdef HAS_USB_MIDI + // same here, read the midi data, messages handled in systemExclusiveHandler + while (uMIDI.read()) ; + #endif +} + void setProgrammerConnected() { sysexProgrammerLastResponse = millis(); if(!sysexProgrammingConnected) { + Serial.println("++ Programmer connected!"); programmerSendSettings(); } + Serial.println("++ Bump keep alive"); sysexProgrammingConnected = 1; } void checkProgrammerConnected() { - programmerSendConnectRequest(); + programmerSendHeartbeat(); programmerCheckTimeout(); } void programmerSendSettings() { - sysexData[0] = 0xF0; - sysexData[1] = sysexManufacturerId; - sysexData[2] = 0x40; - memcpy(&sysexData[3], memory, MEM_MAX+1); - sysexData[MEM_MAX+3] = 0xF7; - serial->write(sysexData, MEM_MAX+4); -#ifdef USE_TEENSY - usbMIDI.sendSysEx(MEM_MAX+4, sysexData); -#endif + Serial.println("<< Replying with settings"); + sysexData[0] = midi::SystemExclusive; + sysexData[1] = SYSEX_MFG_ID; + sysexData[2] = MSG_SETTINGS; + memcpy(&sysexData[3], memory, MEM_MAX); + sysexData[MEM_MAX + 3] = midi::SystemExclusiveEnd; + + sMIDI.sendSysEx(MEM_MAX + 4, sysexData, true /* includes headers */); + #ifdef HAS_USB_MIDI + uMIDI.sendSysEx(MEM_MAX + 4, sysexData, true /* includes headers */); + #endif } void setProgrammerRequestConnect() { - uint8_t data[4] = {0xF0,sysexManufacturerId,65,0xF7}; - serial->write(data, 4); -#ifdef USE_TEENSY - usbMIDI.sendSysEx(4, data); -#endif + Serial.println("<< MSG_CONNECT_REQ_ACK"); + uint8_t data[] = {midi::SystemExclusive,SYSEX_MFG_ID,MSG_CONNECT_REQ_ACK,midi::SystemExclusiveEnd}; + sMIDI.sendSysEx(sizeof(data), data, true /* includes headers */); + #ifdef HAS_USB_MIDI + uMIDI.sendSysEx(sizeof(data), data, true /* includes headers */); + #endif } -void setProgrammerMemorySave() +void saveSettings() { - byte offset = 2; - for(byte m=4;m < MEM_MAX;m++) { - memory[m] = sysexData[offset]; - offset++; + Serial.println("Saving sysex bytes into memory"); + byte sysexOffset = 2; + for(byte m = MEM_FORCE_MODE; m < MEM_MAX; m++) { + memory[m] = sysexData[sysexOffset]; + sysexOffset++; } saveMemory(); loadMemory(); programmerSendSettings(); } -void setProgrammerRestoreMemory() +void resetSettings() { - initMemory(1); + initMemory(true /* reinit */); programmerSendSettings(); } void programmerCheckTimeout() { - if(sysexProgrammingConnected && millis() > (sysexProgrammerLastResponse+sysexProgrammerWaitTime)) { - //programmer timeout! - sysexProgrammingConnected = 0; - sysexProgrammingMode = 0; - } - if(sysexProgrammingMode && millis() > (sysexProgrammerLastResponse+sysexProgrammerWaitTime)) { + if((sysexProgrammingMode || sysexProgrammingConnected) && millis() > (sysexProgrammerLastResponse + PROGRAMMER_MAX_WAIT_TIME)) { //programmer timeout! sysexProgrammingConnected = 0; sysexProgrammingMode = 0; + Serial.println("Programmer: timed out (wait)"); } } -void programmerSendConnectRequest() +void programmerSendHeartbeat() { - if(millis() > (sysexProgrammerLastSent+sysexProgrammerCallTime)) { - uint8_t data[6] = {0xF0, sysexManufacturerId, 0x7F, defaultMemoryMap[MEM_VERSION_FIRST], defaultMemoryMap[MEM_VERSION_SECOND], 0xF7}; - serial->write(data, 6); -#ifdef USE_TEENSY - usbMIDI.sendSysEx(6, data); -#endif + if(millis() > (sysexProgrammerLastSent + PROGRAMMER_MAX_CALL_TIME)) { + Serial.println("<< MSG_HEARTBEAT"); + uint8_t data[] = {midi::SystemExclusive, SYSEX_MFG_ID, MSG_HEARTBEAT, defaultMemoryMap[MEM_VERSION_FIRST], defaultMemoryMap[MEM_VERSION_SECOND], midi::SystemExclusiveEnd}; + sMIDI.sendSysEx(sizeof(data), data, true /* includes headers */); + #ifdef HAS_USB_MIDI + uMIDI.sendSysEx(sizeof(data), data, true /* includes headers */); + #endif sysexProgrammerLastSent = millis(); } } @@ -129,11 +166,11 @@ void setMode(byte mode) void sendMode() { - uint8_t data[4] = {0xF0, sysexManufacturerId, memory[MEM_MODE], 0xF7}; - serial->write(data, 4); -#ifdef USE_TEENSY - usbMIDI.sendSysEx(4, data); -#endif + uint8_t data[] = {midi::SystemExclusive, SYSEX_MFG_ID, MSG_MODE, memory[MEM_MODE], midi::SystemExclusiveEnd}; + sMIDI.sendSysEx(sizeof(data), data, true /* includes headers */); + #ifdef HAS_USB_MIDI + uMIDI.sendSysEx(sizeof(data), data, true /* includes headers */); + #endif } void setMidioutDelay(byte a,byte b,byte c,byte d) @@ -146,80 +183,96 @@ void setMidioutDelay(byte a,byte b,byte c,byte d) changeTasks(); } -void getSysexData() +/** Handle programmer messages in the sysexData payload */ +void handleProgrammerMessage() { - if(sysexData[0] == 0x69 && checkSysexChecksum()) { + Serial.println("Parsing sysex"); + if(sysexData[0] == SYSEX_MFG_ID && checkSysexChecksum()) { + const byte message = sysexData[1]; + //sysex good, do stuff sysexPosition = 0; if(sysexProgrammingMode) { - if(sysexData[1] == 64 - && sysexData[2] == defaultMemoryMap[MEM_VERSION_FIRST] - && sysexData[3] == defaultMemoryMap[MEM_VERSION_SECOND]) { - //serial connected to programmer + if(message == MSG_CONNECT_REQ && versionsMatch()) { + Serial.println(">> MSG_CONNECT_REQ"); setProgrammerRequestConnect(); } - if(sysexData[1] == 66 - && sysexData[2] == defaultMemoryMap[MEM_VERSION_FIRST] - && sysexData[3] == defaultMemoryMap[MEM_VERSION_SECOND]) { - //serial connected to programmer + if(message == MSG_CONNECTED && versionsMatch()) { + Serial.println(">> MSG_CONNECTED"); setProgrammerConnected(); } - if(sysexData[1] == 70) { - //save states - setProgrammerMemorySave(); + if(message == MSG_SETTNGS_SET) { + Serial.println(">> MSG_SETTNGS_SET"); + saveSettings(); + } + if(message == MSG_SETTNGS_GET) { + Serial.println(">> MSG_SETTNGS_GET"); + programmerSendSettings(); } - if(sysexData[1] == 71) { - //save states - setProgrammerRestoreMemory(); + if(message == MSG_SETTINGS_RESET) { + Serial.println(">> MSG_SETTINGS_RESET"); + resetSettings(); } } - if(sysexData[1] == 72) { + if(message == MSG_CONNECT) { + Serial.println(">> MSG_CONNECT"); sysexProgrammingMode = true; sysexProgrammerLastResponse = millis(); modeProgrammer(); } - if(sysexData[1] == 73) { + if(message == MSG_MODE_GET) { + Serial.println(">> MSG_MODE_GET"); sendMode(); } - if(sysexData[1] == 74) { + if(message == MSG_MODE_SET) { + Serial.println(">> MSG_MODE_SET"); setMode(sysexData[2]); } - if(sysexData[1] == 75) { + if(message == MSG_MIDI_OUT_DELAY_SET) { + Serial.println(">> MSG_MIDI_OUT_DELAY_SET"); setMidioutDelay(sysexData[2],sysexData[3],sysexData[4],sysexData[5]); } } clearSysexBuffer(); } - - -boolean checkForProgrammerSysex(byte sin) -{ - if(sin == 0xF0) { - sysexReceiveMode = true; - sysexPosition= 0; - return true; - } else if (sin == 0xF7 && sysexReceiveMode) { - sysexReceiveMode = false; - getSysexData(); - sysexPosition= 0; - return true; - } else if (sysexReceiveMode == true) { - sysexData[sysexPosition] = sin; - sysexPosition++; - if(sysexPosition > longestSysexMessage) { - clearSysexBuffer(); - sysexReceiveMode = false; - } - return true; - } - return false; -} - - void blinkSelectedLight(int led) { if(!blinkSwitch[led]) digitalWrite(pinLeds[led],HIGH); blinkSwitch[led]=1; blinkSwitchTime[led]=0; } + +void initProgrammerSysexHandlers() { +#ifdef HAS_USB_MIDI + uMIDI.setHandleSystemExclusive(systemExclusiveHandler); +#endif + sMIDI.setHandleSystemExclusive(systemExclusiveHandler); +} + +/** + * Prepares a SysEx array for the programmer. It expects sysexData to be populated with + * the sysex array, without the header and EOF bytes. + */ +void systemExclusiveHandler(unsigned char *sysexArray, unsigned int sysexLength) { + // handle programmer. Copy payload without SysEx header and EOF + memcpy(&sysexData[0], &sysexArray[1], sysexLength - 2); + handleProgrammerMessage(); +} + +bool versionsMatch() { + if (sysexData[2] == defaultMemoryMap[MEM_VERSION_FIRST] && sysexData[3] == defaultMemoryMap[MEM_VERSION_SECOND]) { + return true; + } + + Serial.print("Version mismatch: received "); + Serial.print(sysexData[2]); + Serial.print("."); + Serial.print(sysexData[3]); + Serial.print(" expected: "); + Serial.print(defaultMemoryMap[MEM_VERSION_FIRST]); + Serial.print("."); + Serial.print(defaultMemoryMap[MEM_VERSION_SECOND]); + Serial.println(""); + return false; +} \ No newline at end of file diff --git a/Arduinoboy/UsbMidi.ino b/Arduinoboy/UsbMidi.ino deleted file mode 100644 index cd7b818..0000000 --- a/Arduinoboy/UsbMidi.ino +++ /dev/null @@ -1,115 +0,0 @@ - -#ifndef USE_TEENSY -void usbMidiSendTwoByteMessage(uint8_t b1, uint8_t b2) {}; -void usbMidiSendThreeByteMessage(uint8_t b1, uint8_t b2, uint8_t b3) {}; -void usbMidiSendRTMessage(uint8_t b) {}; -void usbMidiHandleSysEx(const uint8_t *data, uint16_t length, bool complete) {}; -void usbMidiInit() {}; -void usbMidiUpdate() {}; -#else - -void usbMidiSendTwoByteMessage(uint8_t b1, uint8_t b2) -{ - uint8_t stat = b1 & 0xf0; - uint8_t chan = (b1 & 0x0f)+1; - if(stat == 0xC0) { - usbMIDI.sendProgramChange(b2, chan); - } else if (stat == 0xD0) { - usbMIDI.sendAfterTouch(b2, chan); - } -} - -void usbMidiSendThreeByteMessage(uint8_t b1, uint8_t b2, uint8_t b3) -{ - uint8_t channel = (b1&0x0F)+1; - - switch(midiData[0] & 0xF0) { - case 0x80: - usbMIDI.sendNoteOff(b2, b3, channel); - usbMIDI.send_now(); - break; - case 0x90: - usbMIDI.sendNoteOn(b2, b3, channel); - usbMIDI.send_now(); - break; - case 0xA0: - usbMIDI.sendPolyPressure(b2, b3, channel); - break; - case 0xB0: - usbMIDI.sendControlChange(b2, b3, channel); - usbMIDI.send_now(); - break; - case 0xE0: - unsigned short v = (unsigned short)b3; - v<<=7; - v|=(unsigned short)b2; - usbMIDI.sendPitchBend(v, channel); - break; - } -} - -void usbMidiSendRTMessage(uint8_t b) -{ - usbMIDI.sendRealTime(b); -} - -void usbMidiUpdate() -{ - usbMIDI.read(); -} - -void usbMidiHandleSysEx(const uint8_t *data, uint16_t length, bool complete) -{ - if(sysexPosition + length >= longestSysexMessage || (length < 3 && complete)) { - //wrapped! - sysexPosition = 0; - return ; - } - - if(sysexPosition == 0 && complete) { - memcpy(&sysexData[0], &data[1], length-2); - sysexPosition += length-2; - } else if (sysexPosition == 0 && !complete) { - memcpy(&sysexData[0], &data[1], length-1); - sysexPosition += length-1; - } else if (!complete) { - memcpy(&sysexData[sysexPosition], &data[0], length); - sysexPosition += length; - } else { - memcpy(&sysexData[sysexPosition], &data[0], length-1); - sysexPosition += length-1; - } - - if(complete) { - getSysexData(); - } -} - -void usbMidiInit() -{ - usbMIDI.setHandleSysEx(usbMidiHandleSysEx); -} - -#endif - - - - - - - - - - - - - - - - - - - - - -