From 959430bd7611e72d041b98aff0cd9b81326360cc Mon Sep 17 00:00:00 2001 From: timothy lamb Date: Sun, 26 Jul 2015 15:31:07 -0700 Subject: [PATCH] Release 1.1.0 from Google Code. --- Arduinoboy/Arduinoboy.ino | 542 ++++++++++++++-------------- Arduinoboy/Mode.ino | 305 ++++++++-------- Arduinoboy/Mode_LSDJ_Keyboard.ino | 518 +++++++++++++------------- Arduinoboy/Mode_LSDJ_MasterSync.ino | 184 +++++----- Arduinoboy/Mode_LSDJ_SlaveSync.ino | 284 +++++++-------- Arduinoboy/Mode_MidiGb.ino | 355 ++++++++++++------ Arduinoboy/Mode_Nanoloop.ino | 151 ++++---- 7 files changed, 1237 insertions(+), 1102 deletions(-) mode change 100755 => 100644 Arduinoboy/Arduinoboy.ino mode change 100755 => 100644 Arduinoboy/Mode.ino mode change 100755 => 100644 Arduinoboy/Mode_LSDJ_Keyboard.ino mode change 100755 => 100644 Arduinoboy/Mode_LSDJ_MasterSync.ino mode change 100755 => 100644 Arduinoboy/Mode_LSDJ_SlaveSync.ino mode change 100755 => 100644 Arduinoboy/Mode_MidiGb.ino mode change 100755 => 100644 Arduinoboy/Mode_Nanoloop.ino diff --git a/Arduinoboy/Arduinoboy.ino b/Arduinoboy/Arduinoboy.ino old mode 100755 new mode 100644 index af7d265..668f9c1 --- a/Arduinoboy/Arduinoboy.ino +++ b/Arduinoboy/Arduinoboy.ino @@ -1,267 +1,275 @@ -/*************************************************************************** - *************************************************************************** - * __ _ __ * - * ____ __________/ /_ __(_)___ ____ / /_ ____ __ __ * - * / __ `/ ___/ __ / / / / / __ \/ __ \/ __ \/ __ \/ / / / * - * / /_/ / / / /_/ / /_/ / / / / / /_/ / /_/ / /_/ / /_/ / * - * \__,_/_/ \__,_/\__,_/_/_/ /_/\____/_.___/\____/\__, / * - * /____/ * - * * - *************************************************************************** - *************************************************************************** - * * - * Version: 0.9.9.1 * - * Date: Sept 12 2008 * - * Name: Timothy Lamb * - * Email: trash80@gmail.com * - * * - *************************************************************************** - *************************************************************************** - * * - * Notes: * - * Pins have changed from the original diagram, expect build * - * instructions to follow here soon: * - * http://code.google.com/p/arduinoboy/ * - * * - * Arduino pin settings: (Layout is final) * - * - 6 LEDS on pins 8 to 13 * - * - Push button on pin 3 (for selecting mode) * - * - MIDI Opto-isolator power on pin 4 * - * - Gameboy Clock line on pin 5 * - * - Gameboy Serial Data input on 6 * - * - Serial Data from gameboy on pin 7 * - * * - * Program Information: * - * LSDJ Slave Mode Midi Note Effects: * - * 48 - C-2 Sends a Sequencer Start Command * - * 49 - C#2 Sends a Sequencer Stop Command * - * 50 - D-2 Toggles Normal Tempo * - * 51 - D#2 Toggles 1/2 Tempo * - * 52 - E-2 Toggles 1/4 Tempo * - * 53 - F-2 Toggles 1/8 Tempo * - * * - * LSDJ Keyboard Mode: * - * 48 - C-2 Mute Pu1 Off/On * - * 49 - C#2 Mute Pu2 Off/On * - * 50 - D-2 Mute Wav Off/On * - * 51 - D#2 Mute Noi Off/On * - * 52 - E-2 Livemode Cue Sequence * - * 53 - F-2 Livemode Cursor Up * - * 54 - F#2 Livemode Cursor Down * - * 55 - G-2 Livemode Cursor Left * - * 56 - G#2 Livemode Cursor Right * - * 57 - A-2 Table Up * - * 58 - A#2 Table Down * - * 59 - B-2 Cue Table * - * 60 - C-3 to C-8 Notes! * - * Prgram Change to select from instrument table * - * * - ***************************************************************************/ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - #include -/*************************************************************************** -* Simple User Settings -***************************************************************************/ -int syncEffectsMidiChannel = 16; //midi sync effects for lsdj slave mode -int masterNotePositionMidiChannel = 16; //LSDJ in master mode will send its song position on the start button via midi note. -int keyboardInstrumentMidiChannel = 16; //midi channel for keyboard instruments in lsdj. - -boolean keyboardCompatabilityMode = true; //Set to true if you are using LSDJ version lower then 2.6, not working right now -boolean keyboardMidiChannelToInstrument = true; //Set to true if you want to have midi channel set the instrument number - -//Mode 0: Midi Input to LSDJ Sync -//Mode 1: LSDJ MASTER to Midi output -//Mode 2: LSDJ Keyboard -//Mode 3: Midi Input to Nanoloop -int mode = 0; -int numberOfModes = 5; //Right now there are 5 modes, Might be more in the future -boolean usbMode = false; -//Enforces the mode above, without reading from memory, use this to force the mode if you dont have a push button setup. -boolean forceMode = false; - -int gameboyBitPause = 1; //Bit pause for gbmidi mode .... 1 to 20 -int gameboyBytePause= 20; //Byte pause for gbmidi mode ... if having trouble communicating with gb try playing with these values... 20 to 100 - -/*************************************************************************** -* Lets Assign our Arduino Pins ..... -***************************************************************************/ - -int pinGBClock = 5; // clock out to gameboy -int pinGBSerialOut = 6; // serial data to gameboy -int pinGBSerialIn = 7; // serial data from gameboy - -int pinMidiInputPower = 4; // power pin for midi input opto-isolator - -int pinStatusLed = 13; // Status LED -int pinLeds[] = {12,11,10,9,8}; // LED Pins - -int pinButtonMode = 3; //toggle button for selecting the mode - -/*************************************************************************** -* Memory -***************************************************************************/ - -int eepromMemoryByte = 0; //Location of where to store settings from mem - -/*************************************************************************** -* Switches and states -***************************************************************************/ -boolean sequencerStarted = false; //Sequencer has Started -boolean midiSyncEffectsTime = false; -boolean midiNoteOnMode =false; -boolean midiNoteOffMode =false; -boolean midiProgramChange=false; -boolean midiAddressMode =false; -boolean midiValueMode =false; - -boolean statusLedIsOn =false; -boolean statusLedBlink =false; - -boolean nanoState =false; -boolean nanoSkipSync =false; - -/*************************************************************************** -* Counter vars -***************************************************************************/ -int countLSDJTicks = 0; //for loop int (we need to cycle 8 pulses) -int countSyncTime = 0; -int countSyncSteps = 0; -int countSyncPulse = 0; -int countGbClockTicks =0; -int countClockPause =0; -int countIncommingMidiByte =0; -int countStatusLedOn =0; -unsigned int waitClock =0; -/*************************************************************************** -* Inbound Data Placeholders -***************************************************************************/ -byte incomingMidiByte; //incomming midi message -byte readgbClockLine; -byte readGbSerialIn; -byte bit; -int incomingMidiData[] = {0, 0, 0}; -int lastMidiData[] = {0, 0, 0}; - -int incomingMidiNote = 0; -int incomingMidiVel = 0; -byte readToggleMode; -byte serialWriteBuffer[256]; -byte midiDefaultStartOffset; -int writePosition=0; -int readPosition=0; -int lastMode=0; //Stores the last selected mode for leds. -/*************************************************************************** -* LSDJ Keyboard mode settings -***************************************************************************/ -byte keyboardNotes[] = {0x1A,0x1B,0x22,0x23,0x21,0x2A,0x34,0x32,0x33,0x31,0x3B,0x3A, - 0x15,0x1E,0x1D,0x26,0x24,0x2D,0x2E,0x2C,0x36,0x35,0x3D,0x3C}; -byte keyboardOctDn = 0x05; -byte keyboardOctUp = 0x06; - -byte keyboardInsDn = 0x04; -byte keyboardInsUp = 0x0C; - -byte keyboardTblDn = 0x03; -byte keyboardTblUp = 0x0B; - -byte keyboardTblCue= 0x29; - -byte keyboardMut1 = 0x01; -byte keyboardMut2 = 0x09; -byte keyboardMut3 = 0x78; -byte keyboardMut4 = 0x07; - -byte keyboardCurL = 0x6B; -byte keyboardCurR = 0x74; -byte keyboardCurU = 0x75; -byte keyboardCurD = 0x72; -byte keyboardPgUp = 0x7D; -byte keyboardPgDn = 0x7A; -byte keyboardEntr = 0x5A; - -int keyboardCurrentOct = 0; -int keyboardCurrentIns = 0; -int keyboardCurrentTbl = 0; - -int keyboardLastOct = 0; -int keyboardLastIns = 0; -int keyboardLastTbl = 0; - -int keyboardDiff = 0; -int keyboardCount = 0; -byte keyboardStartOctave = 0x24; -byte keyboardNoteStart = 0; -byte keyboardNoteOffset = 0; -byte keyboardCommands[12]; - -void setup() { -/* - Init Pins -*/ - for(int led=0;led<=5;led++) pinMode(pinLeds[led],OUTPUT); - pinMode(pinStatusLed,OUTPUT); - - pinMode(pinButtonMode,INPUT); - - pinMode(pinGBClock,OUTPUT); - pinMode(pinGBSerialOut,OUTPUT); - pinMode(pinGBSerialIn,INPUT); -/* - Set MIDI Serial Rate -*/ - if(usbMode == true) { - Serial.begin(38400); //31250 - } else { - pinMode(pinMidiInputPower,OUTPUT); - digitalWrite(pinMidiInputPower,HIGH); // turn on the optoisolator - Serial.begin(31250); //31250 - } -/* - Set Pin States -*/ - digitalWrite(pinGBClock,HIGH); // gameboy wants a HIGH line - digitalWrite(pinGBSerialOut,LOW); // no data to send -/* - Misc Startup -*/ - syncEffectsMidiChannel = 143 + syncEffectsMidiChannel; //set the midi channel to the real note-on number (144 to 159) - keyboardInstrumentMidiChannel = 143 + keyboardInstrumentMidiChannel; //set the midi channel to the real note-on number (144 to 159) - masterNotePositionMidiChannel = 143 + masterNotePositionMidiChannel; //set the midi channel to the real note-on number (144 to 159) - keyboardNoteStart = keyboardStartOctave + 12; // Set the octave where the actual notes start (the octave below is for the mutes, cursor, etc) -/* - Assign the keyboard mode command array for the first octave -*/ - keyboardCommands[0] = keyboardMut1; - keyboardCommands[1] = keyboardMut2; - keyboardCommands[2] = keyboardMut3; - keyboardCommands[3] = keyboardMut4; - keyboardCommands[4] = keyboardCurL; - keyboardCommands[5] = keyboardCurR; - keyboardCommands[6] = keyboardCurU; - keyboardCommands[7] = keyboardCurD; - keyboardCommands[8] = keyboardEntr; - keyboardCommands[9] = keyboardTblDn; - keyboardCommands[10] = keyboardTblUp; - keyboardCommands[11] = keyboardTblCue; -/* - Load Settings from EEPROM -*/ - if(!forceMode) mode = EEPROM.read(eepromMemoryByte); - lastMode = mode; - showSelectedMode(); //Light up the LED that shows which mode we are in. -} - -/* - Main Loop, which we don't use to be able to isolate each mode into its own setup and loop functions -*/ -void loop () { - setMode(); - switchMode(); -} +/*************************************************************************** + *************************************************************************** + * __ _ __ * + * ____ __________/ /_ __(_)___ ____ / /_ ____ __ __ * + * / __ `/ ___/ __ / / / / / __ \/ __ \/ __ \/ __ \/ / / / * + * / /_/ / / / /_/ / /_/ / / / / / /_/ / /_/ / /_/ / /_/ / * + * \__,_/_/ \__,_/\__,_/_/_/ /_/\____/_.___/\____/\__, / * + * /____/ * + * * + *************************************************************************** + *************************************************************************** + * * + * Version: 1.0.1 * + * Date: Oct 12 2008 * + * Name: Timothy Lamb * + * Email: trash80@gmail.com * + * * + *************************************************************************** + *************************************************************************** + * * + * Notes: * + * Pins have changed from the original diagram, expect build * + * instructions to follow here soon: * + * http://code.google.com/p/arduinoboy/ * + * * + * Arduino pin settings: (Layout is final) * + * - 6 LEDS on pins 8 to 13 * + * - Push button on pin 3 (for selecting mode) * + * - MIDI Opto-isolator power on pin 4 * + * - Gameboy Clock line on pin 5 * + * - Gameboy Serial Data input on 6 * + * - Serial Data from gameboy on pin 7 * + * * + * Program Information: * + * LSDJ Slave Mode Midi Note Effects: * + * 48 - C-2 Sends a Sequencer Start Command * + * 49 - C#2 Sends a Sequencer Stop Command * + * 50 - D-2 Toggles Normal Tempo * + * 51 - D#2 Toggles 1/2 Tempo * + * 52 - E-2 Toggles 1/4 Tempo * + * 53 - F-2 Toggles 1/8 Tempo * + * * + * LSDJ Keyboard Mode: * + * 48 - C-2 Mute Pu1 Off/On * + * 49 - C#2 Mute Pu2 Off/On * + * 50 - D-2 Mute Wav Off/On * + * 51 - D#2 Mute Noi Off/On * + * 52 - E-2 Livemode Cue Sequence * + * 53 - F-2 Livemode Cursor Up * + * 54 - F#2 Livemode Cursor Down * + * 55 - G-2 Livemode Cursor Left * + * 56 - G#2 Livemode Cursor Right * + * 57 - A-2 Table Up * + * 58 - A#2 Table Down * + * 59 - B-2 Cue Table * + * 60 - C-3 to C-8 Notes! * + * Prgram Change to select from instrument table * + * * + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + #include +/*************************************************************************** +* Simple User Settings +***************************************************************************/ +int syncEffectsMidiChannel = 16; //midi sync effects for lsdj slave mode +int masterNotePositionMidiChannel = 16; //LSDJ in master mode will send its song position on the start button via midi note. +int keyboardInstrumentMidiChannel = 16; //midi channel for keyboard instruments in lsdj. + +boolean keyboardCompatabilityMode = true; //Set to true if you are using LSDJ version lower then 2.6, not working right now +boolean keyboardMidiChannelToInstrument = true; //Set to true if you want to have midi channel set the instrument number + +//Mode 0: Midi Input to LSDJ Sync +//Mode 1: LSDJ MASTER to Midi output +//Mode 2: LSDJ Keyboard +//Mode 3: Midi Input to Nanoloop +//Mode 4: Midi Input to mGB cart (available at: code.google.com/p/ardunioboy) + +boolean forceMode = false; //Enforces the mode above, without reading from memory, use this to force the mode if you dont have a push button setup. +int mode = 0; //0 to 4 - default mode for force mode +int numberOfModes = 5; //Right now there are 5 modes, Might be more in the future +boolean usbMode = false; //to use usb for serial communication as oppose to MIDI - sets baud rate to 38400 + +int gameboyBitPauseLOW = 5; //Bit pause for gbmidi mode .... 1 to 10 /// tested working value: 5=GBA/SP/DMG01 --- +int gameboyBitPauseHIGH = 1; //Bit pause for gbmidi mode .... 1 to 10 /// tested working value: 1=GBA/SP/DMG01 --- (note: roughly 4 microseconds off from Low do to code that writes to the serial line) +int gameboyBytePause= 10; //Byte pause for gbmidi mode .... 5 to 20 /// tested working value: 5=GBA/SP/GBC and 10=DMG + +/*************************************************************************** +* Lets Assign our Arduino Pins ..... +***************************************************************************/ + +int pinGBClock = 5; // clock out to gameboy +int pinGBSerialOut = 6; // serial data to gameboy +int pinGBSerialIn = 7; // serial data from gameboy + +int pinMidiInputPower = 4; // power pin for midi input opto-isolator + +int pinStatusLed = 13; // Status LED +int pinLeds[] = {12,11,10,9,8}; // LED Pins + +int pinButtonMode = 3; //toggle button for selecting the mode + +/*************************************************************************** +* Memory +***************************************************************************/ + +int eepromMemoryByte = 0; //Location of where to store settings from mem + +/*************************************************************************** +* Switches and states +***************************************************************************/ +boolean sequencerStarted = false; //Sequencer has Started +boolean midiSyncEffectsTime = false; +boolean midiNoteOnMode =false; +boolean midiNoteOffMode =false; +boolean midiProgramChange=false; +boolean midiAddressMode =false; +boolean midiValueMode =false; + +boolean statusLedIsOn =false; +boolean statusLedBlink =false; + +boolean nanoState =false; +boolean nanoSkipSync =false; + +boolean blinkSwitch[5]; +unsigned long int blinkSwitchTime[5]; +int switchLight = 0; + +/*************************************************************************** +* Counter vars +***************************************************************************/ +int countLSDJTicks = 0; //for loop int (we need to cycle 8 pulses) +int countSyncTime = 0; +int countSyncLightTime=0; +int countSyncSteps = 0; +int countSyncPulse = 0; +int countGbClockTicks =0; +int countClockPause =0; +int countIncommingMidiByte =0; +int countStatusLedOn =0; +unsigned int waitClock =0; + +/*************************************************************************** +* Inbound Data Placeholders +***************************************************************************/ +byte incomingMidiByte; //incomming midi message +byte readgbClockLine; +byte readGbSerialIn; +byte bit; +int incomingMidiData[] = {0, 0, 0}; +int lastMidiData[] = {0, 0, 0}; + +int incomingMidiNote = 0; +int incomingMidiVel = 0; +byte readToggleMode; +byte serialWriteBuffer[256]; +byte midiDefaultStartOffset; +int writePosition=0; +int readPosition=0; +int lastMode=0; //Stores the last selected mode for leds. +/*************************************************************************** +* LSDJ Keyboard mode settings +***************************************************************************/ +byte keyboardNotes[] = {0x1A,0x1B,0x22,0x23,0x21,0x2A,0x34,0x32,0x33,0x31,0x3B,0x3A, + 0x15,0x1E,0x1D,0x26,0x24,0x2D,0x2E,0x2C,0x36,0x35,0x3D,0x3C}; +byte keyboardOctDn = 0x05; +byte keyboardOctUp = 0x06; + +byte keyboardInsDn = 0x04; +byte keyboardInsUp = 0x0C; + +byte keyboardTblDn = 0x03; +byte keyboardTblUp = 0x0B; + +byte keyboardTblCue= 0x29; + +byte keyboardMut1 = 0x01; +byte keyboardMut2 = 0x09; +byte keyboardMut3 = 0x78; +byte keyboardMut4 = 0x07; + +byte keyboardCurL = 0x6B; +byte keyboardCurR = 0x74; +byte keyboardCurU = 0x75; +byte keyboardCurD = 0x72; +byte keyboardPgUp = 0x7D; +byte keyboardPgDn = 0x7A; +byte keyboardEntr = 0x5A; + +int keyboardCurrentOct = 0; +int keyboardCurrentIns = 0; +int keyboardCurrentTbl = 0; + +int keyboardLastOct = 0; +int keyboardLastIns = 0; +int keyboardLastTbl = 0; + +int keyboardDiff = 0; +int keyboardCount = 0; +byte keyboardStartOctave = 0x24; +byte keyboardNoteStart = 0; +byte keyboardNoteOffset = 0; +byte keyboardCommands[12]; + +void setup() { +/* + Init Pins +*/ + for(int led=0;led<=5;led++) pinMode(pinLeds[led],OUTPUT); + pinMode(pinStatusLed,OUTPUT); + + pinMode(pinButtonMode,INPUT); + + pinMode(pinGBClock,OUTPUT); + pinMode(pinGBSerialOut,OUTPUT); + pinMode(pinGBSerialIn,INPUT); +/* + Set MIDI Serial Rate +*/ + if(usbMode == true) { + Serial.begin(38400); //31250 + } else { + pinMode(pinMidiInputPower,OUTPUT); + digitalWrite(pinMidiInputPower,HIGH); // turn on the optoisolator + Serial.begin(31250); //31250 + } +/* + Set Pin States +*/ + digitalWrite(pinGBClock,HIGH); // gameboy wants a HIGH line + digitalWrite(pinGBSerialOut,LOW); // no data to send +/* + Misc Startup +*/ + syncEffectsMidiChannel = 143 + syncEffectsMidiChannel; //set the midi channel to the real note-on number (144 to 159) + keyboardInstrumentMidiChannel = 143 + keyboardInstrumentMidiChannel; //set the midi channel to the real note-on number (144 to 159) + masterNotePositionMidiChannel = 143 + masterNotePositionMidiChannel; //set the midi channel to the real note-on number (144 to 159) + keyboardNoteStart = keyboardStartOctave + 12; // Set the octave where the actual notes start (the octave below is for the mutes, cursor, etc) +/* + Assign the keyboard mode command array for the first octave +*/ + keyboardCommands[0] = keyboardMut1; + keyboardCommands[1] = keyboardMut2; + keyboardCommands[2] = keyboardMut3; + keyboardCommands[3] = keyboardMut4; + keyboardCommands[4] = keyboardCurL; + keyboardCommands[5] = keyboardCurR; + keyboardCommands[6] = keyboardCurU; + keyboardCommands[7] = keyboardCurD; + keyboardCommands[8] = keyboardEntr; + keyboardCommands[9] = keyboardTblDn; + keyboardCommands[10] = keyboardTblUp; + keyboardCommands[11] = keyboardTblCue; +/* + Load Settings from EEPROM +*/ + if(!forceMode) mode = EEPROM.read(eepromMemoryByte); + lastMode = mode; + showSelectedMode(); //Light up the LED that shows which mode we are in. +} + +/* + Main Loop, which we don't use to be able to isolate each mode into its own setup and loop functions +*/ +void loop () { + setMode(); + switchMode(); +} diff --git a/Arduinoboy/Mode.ino b/Arduinoboy/Mode.ino old mode 100755 new mode 100644 index 9605574..f728e1a --- a/Arduinoboy/Mode.ino +++ b/Arduinoboy/Mode.ino @@ -1,147 +1,158 @@ -/************************************************************************** - * Name: Timothy Lamb * - * Email: trash80@gmail.com * - ***************************************************************************/ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -/* ***************************************************************************/ -/* "Mode" Functions. Deals with changing the setup of arduino. */ -/* ***************************************************************************/ - - /* - setMode will check if the push button is depressed, If it is it will - increment the mode number and make sure its in the - range 0 to 4 by mod (%). It will then write the mode to memory, - set the leds to display the mode, and switch the code over to the - right function. - */ -void setMode() -{ - if(!forceMode && digitalRead(pinButtonMode)) { //if the button is pressed - mode++; //increment the mode number - if(mode > (numberOfModes - 1)) mode=0; //if the mode is greater then 4 it will wrap back to 0 - if(!forceMode) EEPROM.write(eepromMemoryByte, mode); //write mode to eeprom if we arnt forcing a mode in the config - showSelectedMode(); //set the LEDS - switchMode(); //switch to the new mode - } -} - - /* - showSelectedMode1 turns off the last mode led, turns on the new mode led - and delays for a period of time to reduce jitter behavior from the mode - changing too fast. - */ -void showSelectedMode() -{ - digitalWrite(pinLeds[lastMode],LOW); - digitalWrite(pinLeds[mode],HIGH); - lastMode = mode; - delay(300); -} - - /* - switchMode is only called from setMode. its responsible for - linking the mode number to its corrisponding function, - and then calling that function. function. function. - */ -void switchMode() -{ - switch(mode) - { - case 0: - modeLSDJSlaveSyncSetup(); - break; - case 1: - modeLSDJMasterSyncSetup(); - break; - case 2: - modeLSDJKeyboardSetup(); - break; - case 3: - modeNanoloopSetup(); - break; - case 4: - modeMidiGbSetup(); - break; - } -} - - -/* ***************************************************************************/ -/* General Global Functions Used in more then one of the modes */ -/* ***************************************************************************/ - - /* - sequencerStart is called when either LSDJ has started to play in master mode, - or when a MIDI Start or continue command is received in lsdj slave mode. - Basically it just resets some counters we use and sets a "start" flag. - */ - -void sequencerStart() -{ - digitalWrite(pinStatusLed,HIGH); - sequencerStarted = true; //Sequencer has started? - countSyncPulse = 0; //Used for status LED, counts 24 ticks (quarter notes) - countSyncTime = 0; //Used to count a custom amount of clock ticks (2/4/8) for sync effects -} - - /* - sequencerStop is called when either LSDJ has stopped sending sync commands for - some time in LSDJ Master mode, or when a MIDI Stop command is received in - lsdj slave mode. - Basically it just resets some counters we use and sets the "start" flag to false. - */ -void sequencerStop() -{ - digitalWrite(pinStatusLed,LOW); - midiSyncEffectsTime = false;//Turn off MIDI sync effects in LSDJ slave mode - sequencerStarted = false; //Sequencer has started? - countSyncPulse = 0; //Used for status LED, counts 24 ticks (quarter notes) - countSyncTime = 0; //Used to count a custom amount of clock ticks (2/4/8) for sync effects -} - - /* - updateStatusLed should be placed inside of the main loop cycle of a mode function. It counts to a - certain number to delay the action of turning off the status led, so the blink is visible to the human eye. ;)> - I guess this could be called the blinking routine. - */ -void updateStatusLed() -{ - if(statusLedIsOn) { //is the led on? - countStatusLedOn++; //then increment the counter by 1 - if(countStatusLedOn > 3000) { //if the counter is pretty high - countStatusLedOn = 0; //then reset it to zero. - digitalWrite(pinStatusLed,LOW); //and turn off the status led - statusLedIsOn = false; //and set our "is it on?" to false, cause its off now. ;p - - } else if (statusLedBlink && countStatusLedOn == 1) { //someone told me to blink, because i was already on - digitalWrite(pinStatusLed,LOW); //so I'll turn off and turn back on later.. - - } else if (statusLedBlink && countStatusLedOn > 1000) {//Now that I've waited long enough I'll finish my blink. - statusLedBlink = false; //Turn off the issued blink - digitalWrite(pinStatusLed,HIGH); //... and finally turn back on. - } - } -} - - /* - statusLedOn is the function to call when we want the status led to blink for us. - all it does is check if its been already asked to turn on, if it has it will set a flag - to make it blink. Either way it will reset the blink timer and turn on the LED - */ -void statusLedOn() -{ - if(statusLedIsOn) { - statusLedBlink = true; //Make it blink even though its already on - } - statusLedIsOn = true; //This is the flag the updator function looks for to know if its ok to increment the timer and wait to turn off the led - countStatusLedOn = 0; //Reset the timer - digitalWrite(pinStatusLed,HIGH); //Turn on the led -} +/************************************************************************** + * Name: Timothy Lamb * + * Email: trash80@gmail.com * + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/* ***************************************************************************/ +/* "Mode" Functions. Deals with changing the setup of arduino. */ +/* ***************************************************************************/ + + /* + setMode will check if the push button is depressed, If it is it will + increment the mode number and make sure its in the + range 0 to 4 by mod (%). It will then write the mode to memory, + set the leds to display the mode, and switch the code over to the + right function. + */ +void setMode() +{ + if(!forceMode && digitalRead(pinButtonMode)) { //if the button is pressed + mode++; //increment the mode number + if(mode > (numberOfModes - 1)) mode=0; //if the mode is greater then 4 it will wrap back to 0 + if(!forceMode) EEPROM.write(eepromMemoryByte, mode); //write mode to eeprom if we arnt forcing a mode in the config + showSelectedMode(); //set the LEDS + switchMode(); //switch to the new mode + } +} + + /* + showSelectedMode1 turns off the last mode led, turns on the new mode led + and delays for a period of time to reduce jitter behavior from the mode + changing too fast. + */ +void showSelectedMode() +{ + digitalWrite(pinLeds[0],LOW); + digitalWrite(pinLeds[1],LOW); + digitalWrite(pinLeds[2],LOW); + digitalWrite(pinLeds[3],LOW); + digitalWrite(pinLeds[4],LOW); + digitalWrite(pinLeds[mode],HIGH); + lastMode = mode; + delay(300); +} + + /* + switchMode is only called from setMode. its responsible for + linking the mode number to its corrisponding function, + and then calling that function. function. function. + */ +void switchMode() +{ + switch(mode) + { + case 0: + modeLSDJSlaveSyncSetup(); + break; + case 1: + modeLSDJMasterSyncSetup(); + break; + case 2: + modeLSDJKeyboardSetup(); + break; + case 3: + modeNanoloopSetup(); + break; + case 4: + modeMidiGbSetup(); + break; + } +} + + +/* ***************************************************************************/ +/* General Global Functions Used in more then one of the modes */ +/* ***************************************************************************/ + + /* + sequencerStart is called when either LSDJ has started to play in master mode, + or when a MIDI Start or continue command is received in lsdj slave mode. + Basically it just resets some counters we use and sets a "start" flag. + */ + +void sequencerStart() +{ + sequencerStarted = true; //Sequencer has started? + countSyncPulse = 0; //Used for status LED, counts 24 ticks (quarter notes) + countSyncTime = 0; //Used to count a custom amount of clock ticks (2/4/8) for sync effects + countSyncLightTime=0; + switchLight=0; +} + + /* + sequencerStop is called when either LSDJ has stopped sending sync commands for + some time in LSDJ Master mode, or when a MIDI Stop command is received in + lsdj slave mode. + Basically it just resets some counters we use and sets the "start" flag to false. + */ +void sequencerStop() +{ + midiSyncEffectsTime = false;//Turn off MIDI sync effects in LSDJ slave mode + sequencerStarted = false; //Sequencer has started? + countSyncPulse = 0; //Used for status LED, counts 24 ticks (quarter notes) + countSyncTime = 0; //Used to count a custom amount of clock ticks (2/4/8) for sync effects + countSyncLightTime=0; + switchLight=0; + digitalWrite(pinLeds[0],LOW); + digitalWrite(pinLeds[1],LOW); + digitalWrite(pinLeds[2],LOW); + digitalWrite(pinLeds[3],LOW); + digitalWrite(pinLeds[mode],HIGH); +} + + /* + updateStatusLed should be placed inside of the main loop cycle of a mode function. It counts to a + certain number to delay the action of turning off the status led, so the blink is visible to the human eye. ;)> + I guess this could be called the blinking routine. + */ +void updateStatusLed() +{ + if(statusLedIsOn) { //is the led on? + countStatusLedOn++; //then increment the counter by 1 + if(countStatusLedOn > 3000) { //if the counter is pretty high + countStatusLedOn = 0; //then reset it to zero. + digitalWrite(pinStatusLed,LOW); //and turn off the status led + statusLedIsOn = false; //and set our "is it on?" to false, cause its off now. ;p + + } else if (statusLedBlink && countStatusLedOn == 1) { //someone told me to blink, because i was already on + digitalWrite(pinStatusLed,LOW); //so I'll turn off and turn back on later.. + + } else if (statusLedBlink && countStatusLedOn > 1000) {//Now that I've waited long enough I'll finish my blink. + statusLedBlink = false; //Turn off the issued blink + digitalWrite(pinStatusLed,HIGH); //... and finally turn back on. + } + } +} + + /* + statusLedOn is the function to call when we want the status led to blink for us. + all it does is check if its been already asked to turn on, if it has it will set a flag + to make it blink. Either way it will reset the blink timer and turn on the LED + */ +void statusLedOn() +{ + if(statusLedIsOn) { + statusLedBlink = true; //Make it blink even though its already on + } + statusLedIsOn = true; //This is the flag the updator function looks for to know if its ok to increment the timer and wait to turn off the led + countStatusLedOn = 0; //Reset the timer + digitalWrite(pinStatusLed,HIGH); //Turn on the led +} diff --git a/Arduinoboy/Mode_LSDJ_Keyboard.ino b/Arduinoboy/Mode_LSDJ_Keyboard.ino old mode 100755 new mode 100644 index 8fa502a..4e87942 --- a/Arduinoboy/Mode_LSDJ_Keyboard.ino +++ b/Arduinoboy/Mode_LSDJ_Keyboard.ino @@ -1,267 +1,251 @@ -/************************************************************************** - * Name: Timothy Lamb * - * Email: trash80@gmail.com * - ***************************************************************************/ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -void modeLSDJKeyboardSetup() -{ - digitalWrite(pinStatusLed,LOW); - pinMode(pinGBClock,OUTPUT); //make sure our gameboy Clock is set for OUTPUT mode - digitalWrite(pinGBClock,LOW); //Generally this should be HIGH ie: 1, on, whatever. but since we are emulating a pc keyboard it should be LOW/0/off - addGameboyByte(0); //Send 8bits of nothing. don't ask I dont know. - - /* The stuff below makes sure the code is in the same state as LSDJ on reset / restart, mode switched, etc. */ - - for(int rst=0;rst<5;rst++) addGameboyByte(keyboardOctDn); //Return lsdj to the first octave - for(int rst=0;rst<41;rst++) addGameboyByte(keyboardInsDn); //Return lsdj to the first instrument - - keyboardCurrentOct = 0; //Set our current octave to 0. - keyboardLastOct = 0; //Set our last octave to 0. - keyboardCurrentIns = 0; //Set out current instrument to 0. - keyboardLastIns = 0; //Set out last used instrument to 0. - - - modeLSDJKeyboard(); //.... And start the fun -} - - -void modeLSDJKeyboard() -{ - while(1){ //Loop foreverrrr - if (Serial.available() > 0) { //If MIDI is sending - incomingMidiByte = Serial.read(); //Get the byte sent from MIDI - Serial.print(incomingMidiByte, BYTE);//Echo the Byte to MIDI Output - - - /*************************************************************************** - * Midi to LSDJ Keyboard Handling * - ***************************************************************************/ - //If the byte is a Status Message - if(incomingMidiByte > 0x7F) { - /* 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 - */ - - //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 - incomingMidiData[0] = incomingMidiByte; //Assign the byte to the first position of a data array. (this is the midi channel) - incomingMidiData[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 - incomingMidiData[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(!incomingMidiData[1]) { - //If we dont have a note number, we assume this byte is the note number, get it... - incomingMidiData[1] = incomingMidiByte; - } else { - //We have our note and channel, so call our note function... - playLSDJNote(incomingMidiData[0], incomingMidiData[1], incomingMidiByte); - incomingMidiData[1] = false; //Set the note to false, forcing to capture the next note - } - } else if (midiProgramChange) { - changeLSDJInstrument(incomingMidiData[0], incomingMidiByte); - midiProgramChange = false; - incomingMidiData[0] = false; - } - } - - updateGameboyByteFrame(); // Send out Bytes to LSDJ - updateStatusLed(); // Update our status blinker - setMode(); // Check if mode button was depressed - } -} - - - /* - changeLSDJInstrument does what it does via magic (rtfm, realize the fucking magic) - */ -void changeLSDJInstrument(byte channel,byte message) -{ - keyboardCurrentIns = message; //set the current instrument number - - if(channel == keyboardInstrumentMidiChannel && keyboardCurrentIns != keyboardLastIns) { - //if its on our midi channel and the instrument isnt the same as our currrent - if(!keyboardCompatabilityMode) { - addGameboyByte(0x80 | 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 - if(keyboardCurrentIns > keyboardLastIns) { - keyboardDiff = keyboardCurrentIns - keyboardLastIns; - for(keyboardCount=0;keyboardCount 0x00) { //If midi channel = ours and the velocity is greater then 0 - if(note >= keyboardNoteStart) { - keyboardNoteOffset = 0; - note = note - keyboardNoteStart; //subtract the octave offset to get a value ranging from 0 to 48 for comparison - - keyboardCurrentOct = note / 0x0C; //get a octave value from 0 to 4 by deviding the current note by 12 - changeLSDJOctave(); - - if(note >= 0x3C) keyboardNoteOffset = 0x0C; //if the note really high we need to use the second row of keyboard keys - note = (note % 12) + keyboardNoteOffset; //get a 0 to 11 range of notes and add the offset - addGameboyByte(keyboardNotes[note]); // and finally send the note - - } else if (note >= keyboardStartOctave) { //If we are at the octave below notes - keyboardDiff = note - keyboardStartOctave; //Get a value between 0 and 11 - if(keyboardDiff < 8 && keyboardDiff > 3) addGameboyByte(0xE0); //if we are sending cursor values we have to send a 0xE0 byte for "extended" pc keyboard mode - addGameboyByte(keyboardCommands[note - keyboardStartOctave]); //send the byte corrisponding to the note number in the keyboard command array - } - } -} - - - /* - changeLSDJOctave compares the last octave with the current one and then sends a byte - to shift the octave to match if need be. its pretty much the same as the changeLSDJInstrument function. - */ -void changeLSDJOctave() -{ - if(keyboardCurrentOct != keyboardLastOct) { - if(!keyboardCompatabilityMode) { // This new mode doesnt work yet. :/ - keyboardCurrentOct = 0xB3 + keyboardCurrentOct; - addGameboyByte(keyboardCurrentOct); - } else { - ///We will find out which is greater, the current octave or the last. then - //cycle up or down to that octave - if(keyboardCurrentOct > keyboardLastOct) { - keyboardDiff = keyboardCurrentOct - keyboardLastOct; - for(keyboardCount=0;keyboardCount 80) { //if we've exceeded our wait time - waitClock=0; //reset the counter - statusLedOn(); //turn on the awesome visuals - sendByteToGameboy(serialWriteBuffer[readPosition]); //send the byte out - readPosition++; //increment our read position - readPosition = readPosition % 256; //wrap our reading range from 0 to 255 - } - } -} - - /* - sendByteToGameboy does what it says. yay magic - */ -void sendByteToGameboy(byte send_byte) -{ - for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { //we are going to send 8 bits, so do a loop 8 times - digitalWrite(pinGBClock,HIGH); //Set our clock output to 1 - if(send_byte & 0x01) { //if the first bit is equal to 1 - digitalWrite(pinGBSerialOut,HIGH); //then send a 1 - } else { - digitalWrite(pinGBSerialOut,LOW); //send a 0 - } - send_byte >>= 1; //bitshift right once for the next bit we are going to send - digitalWrite(pinGBClock,LOW); //send a 0 to the clock, we finished sending the bit - } - digitalWrite(pinGBSerialOut,LOW); //make sure the serial state returns to 0 after its done sending the bits -} - -void sendByteToGameboy__(byte send_byte) //changed by firestARTer: send routine changed MST is send out first!!!!!!! -{ - for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { //we are going to send 8 bits, so do a loop 8 times -// digitalWrite(pinGBClock,HIGH); //Set our clock output to 1 - if(send_byte & 0x80) { //if the first bit is equal to 1 - digitalWrite(pinGBSerialOut,HIGH); //then send a 1 - } else { - digitalWrite(pinGBSerialOut,LOW); //send a 0 - } - send_byte <<= 1; //bitshift right once for the next bit we are going to send - digitalWrite(pinGBClock,LOW); //send a 0 to the clock, we finished sending the bit - - delayMicroseconds(30); // firestARter : play around with this value, sometimes the gameboy needs more time between messages - digitalWrite(pinGBClock,HIGH); //send a 0 to the clock, we finished sending the bit - - } - digitalWrite(pinGBSerialOut,LOW); //make sure the serial state returns to 0 after its done sending the bits - delayMicroseconds(30); // firestARter : play around with this value, sometimes the gameboy needs more time between messages -} +/************************************************************************** + * Name: Timothy Lamb * + * Email: trash80@gmail.com * + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +void modeLSDJKeyboardSetup() +{ + digitalWrite(pinStatusLed,LOW); + pinMode(pinGBClock,OUTPUT); //make sure our gameboy Clock is set for OUTPUT mode + digitalWrite(pinGBClock,LOW); //Generally this should be HIGH ie: 1, on, whatever. but since we are emulating a pc keyboard it should be LOW/0/off + addGameboyByte(0); //Send 8bits of nothing. don't ask I dont know. + + /* The stuff below makes sure the code is in the same state as LSDJ on reset / restart, mode switched, etc. */ + + for(int rst=0;rst<5;rst++) addGameboyByte(keyboardOctDn); //Return lsdj to the first octave + for(int rst=0;rst<41;rst++) addGameboyByte(keyboardInsDn); //Return lsdj to the first instrument + + keyboardCurrentOct = 0; //Set our current octave to 0. + keyboardLastOct = 0; //Set our last octave to 0. + keyboardCurrentIns = 0; //Set out current instrument to 0. + keyboardLastIns = 0; //Set out last used instrument to 0. + + + modeLSDJKeyboard(); //.... And start the fun +} + + +void modeLSDJKeyboard() +{ + while(1){ //Loop foreverrrr + if (Serial.available() > 0) { //If MIDI is sending + incomingMidiByte = Serial.read(); //Get the byte sent from MIDI + Serial.print(incomingMidiByte, BYTE);//Echo the Byte to MIDI Output + + + /*************************************************************************** + * Midi to LSDJ Keyboard Handling * + ***************************************************************************/ + //If the byte is a Status Message + if(incomingMidiByte > 0x7F) { + /* 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 + */ + + //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 + incomingMidiData[0] = incomingMidiByte; //Assign the byte to the first position of a data array. (this is the midi channel) + incomingMidiData[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 + incomingMidiData[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(!incomingMidiData[1]) { + //If we dont have a note number, we assume this byte is the note number, get it... + incomingMidiData[1] = incomingMidiByte; + } else { + //We have our note and channel, so call our note function... + playLSDJNote(incomingMidiData[0], incomingMidiData[1], incomingMidiByte); + incomingMidiData[1] = false; //Set the note to false, forcing to capture the next note + } + } else if (midiProgramChange) { + changeLSDJInstrument(incomingMidiData[0], incomingMidiByte); + midiProgramChange = false; + incomingMidiData[0] = false; + } + } + + updateGameboyByteFrame(); // Send out Bytes to LSDJ + updateStatusLed(); // Update our status blinker + setMode(); // Check if mode button was depressed + } +} + + + /* + changeLSDJInstrument does what it does via magic (rtfm, realize the fucking magic) + */ +void changeLSDJInstrument(byte channel,byte message) +{ + keyboardCurrentIns = message; //set the current instrument number + + if(channel == keyboardInstrumentMidiChannel && keyboardCurrentIns != keyboardLastIns) { + //if its on our midi channel and the instrument isnt the same as our currrent + if(!keyboardCompatabilityMode) { + addGameboyByte(0x80 | 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 + if(keyboardCurrentIns > keyboardLastIns) { + keyboardDiff = keyboardCurrentIns - keyboardLastIns; + for(keyboardCount=0;keyboardCount 0x00) { //If midi channel = ours and the velocity is greater then 0 + if(note >= keyboardNoteStart) { + keyboardNoteOffset = 0; + note = note - keyboardNoteStart; //subtract the octave offset to get a value ranging from 0 to 48 for comparison + + keyboardCurrentOct = note / 0x0C; //get a octave value from 0 to 4 by deviding the current note by 12 + changeLSDJOctave(); + + if(note >= 0x3C) keyboardNoteOffset = 0x0C; //if the note really high we need to use the second row of keyboard keys + note = (note % 12) + keyboardNoteOffset; //get a 0 to 11 range of notes and add the offset + addGameboyByte(keyboardNotes[note]); // and finally send the note + + } else if (note >= keyboardStartOctave) { //If we are at the octave below notes + keyboardDiff = note - keyboardStartOctave; //Get a value between 0 and 11 + if(keyboardDiff < 8 && keyboardDiff > 3) addGameboyByte(0xE0); //if we are sending cursor values we have to send a 0xE0 byte for "extended" pc keyboard mode + addGameboyByte(keyboardCommands[note - keyboardStartOctave]); //send the byte corrisponding to the note number in the keyboard command array + } + } +} + + + /* + changeLSDJOctave compares the last octave with the current one and then sends a byte + to shift the octave to match if need be. its pretty much the same as the changeLSDJInstrument function. + */ +void changeLSDJOctave() +{ + if(keyboardCurrentOct != keyboardLastOct) { + if(!keyboardCompatabilityMode) { // This new mode doesnt work yet. :/ + keyboardCurrentOct = 0xB3 + keyboardCurrentOct; + addGameboyByte(keyboardCurrentOct); + } else { + ///We will find out which is greater, the current octave or the last. then + //cycle up or down to that octave + if(keyboardCurrentOct > keyboardLastOct) { + keyboardDiff = keyboardCurrentOct - keyboardLastOct; + for(keyboardCount=0;keyboardCount 40) { //if we've exceeded our wait time + waitClock=0; //reset the counter + statusLedOn(); //turn on the awesome visuals + sendByteToGameboy(serialWriteBuffer[readPosition]); //send the byte out + readPosition++; //increment our read position + readPosition = readPosition % 256; //wrap our reading range from 0 to 255 + } + } +} + + /* + sendByteToGameboy does what it says. yay magic + */ +void sendByteToGameboy(byte send_byte) +{ + for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { //we are going to send 8 bits, so do a loop 8 times + digitalWrite(pinGBClock,HIGH); //Set our clock output to 1 + if(send_byte & 0x01) { //if the first bit is equal to 1 + digitalWrite(pinGBSerialOut,HIGH); //then send a 1 + } else { + digitalWrite(pinGBSerialOut,LOW); //send a 0 + } + send_byte >>= 1; //bitshift right once for the next bit we are going to send + delayMicroseconds(gameboyBitPauseLOW); // firestARter : play around with this value, sometimes the gameboy needs more time between messages + digitalWrite(pinGBClock,LOW); //send a 0 to the clock, we finished sending the bit + delayMicroseconds(gameboyBitPauseHIGH); // firestARter : play around with this value, sometimes the gameboy needs more time between messages + } + digitalWrite(pinGBSerialOut,LOW); //make sure the serial state returns to 0 after its done sending the bits + delayMicroseconds(gameboyBitPauseLOW); // firestARter : play around with this value, sometimes the gameboy needs more time between messages +} + diff --git a/Arduinoboy/Mode_LSDJ_MasterSync.ino b/Arduinoboy/Mode_LSDJ_MasterSync.ino old mode 100755 new mode 100644 index fd7f4c4..60536f8 --- a/Arduinoboy/Mode_LSDJ_MasterSync.ino +++ b/Arduinoboy/Mode_LSDJ_MasterSync.ino @@ -1,90 +1,94 @@ -/************************************************************************** - * Name: Timothy Lamb * - * Email: trash80@gmail.com * - ***************************************************************************/ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - - -void modeLSDJMasterSyncSetup() -{ - digitalWrite(pinStatusLed,LOW); - pinMode(pinGBClock,INPUT); //Set the gb clock as input, we will be reading from the clock - modeLSDJMasterSync(); -} - -void modeLSDJMasterSync() -{ - while(1){ - readgbClockLine = digitalRead(pinGBClock); //Read gameboy's clock line - - if(readgbClockLine) { //If Gb's Clock is On - while(readgbClockLine) { //Loop untill its off - checkLSDJStopped(); //Check if LSDJ hit Stop - readgbClockLine = digitalRead(pinGBClock); //Read the clock again - bit = digitalRead(pinGBSerialIn); //Read the serial input for song position - setMode(); - } - 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 - } - - if (Serial.available() > 0) { //If serial data was send to midi input - incomingMidiByte = Serial.read(); //Read it - Serial.print(incomingMidiByte, BYTE); //Send it to the midi output - } - } -} - - /* - checkLSDJStopped counts how long the clock was on, if its been on too long we assume - LSDJ has stopped- Send a MIDI transport stop message and return true. - */ -boolean checkLSDJStopped() -{ - countClockPause++; //Increment the counter - if(countClockPause > 16000) { //if we've reached our waiting period - if(sequencerStarted) { - countClockPause = 0; //reset our clock - Serial.print(0xFC, BYTE); //send the transport stop message - sequencerStop(); //call the global sequencer stop function - } - return true; - } - return false; -} - - /* - sendMidiClockSlaveFromLSDJ waits for 8 clock bits from LSDJ, - sends the transport start command if sequencer hasnt started yet, - sends the midi clock tick, and sends a note value that corrisponds to - LSDJ's row number on start (LSDJ only sends this once when it starts) - */ -void sendMidiClockSlaveFromLSDJ() -{ - countGbClockTicks++; //Increment the bit counter - if(countGbClockTicks == 8) { //If we hit 8 bits - if(!sequencerStarted) { //If the sequencer hasnt started - Serial.print(masterNotePositionMidiChannel, BYTE); //Send the midi channel byte - Serial.print(readGbSerialIn, BYTE); //Send the row value as a note - Serial.print(0x7F, BYTE); //Send a velocity 127 - - Serial.print(0xFA, BYTE); //send MIDI transport start message - sequencerStart(); //call the global sequencer start function - } - Serial.print(0xF8, BYTE); //Send the MIDI Clock Tick - - countGbClockTicks=0; //Reset the bit counter - readGbSerialIn = 0x00; //Reset our serial read value - } -} +/************************************************************************** + * Name: Timothy Lamb * + * Email: trash80@gmail.com * + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +void modeLSDJMasterSyncSetup() +{ + digitalWrite(pinStatusLed,LOW); + pinMode(pinGBClock,INPUT); //Set the gb clock as input, we will be reading from the clock + countSyncTime=0; + modeLSDJMasterSync(); +} + +void modeLSDJMasterSync() +{ + while(1){ + readgbClockLine = digitalRead(pinGBClock); //Read gameboy's clock line + if(readgbClockLine) { //If Gb's Clock is On + while(readgbClockLine) { //Loop untill its off + checkLSDJStopped(); //Check if LSDJ hit Stop + readgbClockLine = digitalRead(pinGBClock); //Read the clock again + bit = digitalRead(pinGBSerialIn); //Read the serial input for song position + setMode(); + updateStatusLight(); + } + 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 + } + + if (Serial.available() > 0) { //If serial data was send to midi input + incomingMidiByte = Serial.read(); //Read it + Serial.print(incomingMidiByte, BYTE); //Send it to the midi output + } + } +} + + /* + checkLSDJStopped counts how long the clock was on, if its been on too long we assume + LSDJ has stopped- Send a MIDI transport stop message and return true. + */ +boolean checkLSDJStopped() +{ + countClockPause++; //Increment the counter + if(countClockPause > 16000) { //if we've reached our waiting period + if(sequencerStarted) { + countClockPause = 0; //reset our clock + Serial.print(0xFC, BYTE); //send the transport stop message + sequencerStop(); //call the global sequencer stop function + } + return true; + } + return false; +} + + /* + sendMidiClockSlaveFromLSDJ waits for 8 clock bits from LSDJ, + sends the transport start command if sequencer hasnt started yet, + sends the midi clock tick, and sends a note value that corrisponds to + LSDJ's row number on start (LSDJ only sends this once when it starts) + */ +void sendMidiClockSlaveFromLSDJ() +{ + if(!countGbClockTicks) { //If we hit 8 bits + if(!sequencerStarted) { //If the sequencer hasnt started + Serial.print(masterNotePositionMidiChannel, BYTE); //Send the midi channel byte + Serial.print(readGbSerialIn, BYTE); //Send the row value as a note + Serial.print(0x7F, BYTE); //Send a velocity 127 + + Serial.print(0xFA, BYTE); //send MIDI transport start message + sequencerStart(); //call the global sequencer start function + } + Serial.print(0xF8, BYTE); //Send the MIDI Clock Tick + + countGbClockTicks=0; //Reset the bit counter + readGbSerialIn = 0x00; //Reset our serial read value + + updateVisualSync(); + } + countGbClockTicks++; //Increment the bit counter + if(countGbClockTicks==8) countGbClockTicks=0; +} diff --git a/Arduinoboy/Mode_LSDJ_SlaveSync.ino b/Arduinoboy/Mode_LSDJ_SlaveSync.ino old mode 100755 new mode 100644 index 693575f..7505a17 --- a/Arduinoboy/Mode_LSDJ_SlaveSync.ino +++ b/Arduinoboy/Mode_LSDJ_SlaveSync.ino @@ -1,141 +1,143 @@ -/************************************************************************** - * Name: Timothy Lamb * - * Email: trash80@gmail.com * - ***************************************************************************/ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -void modeLSDJSlaveSyncSetup() -{ - digitalWrite(pinStatusLed,LOW); - pinMode(pinGBClock,OUTPUT); //Set the gb clock as output - digitalWrite(pinGBClock,HIGH); //Gameboy likes to get high - digitalWrite(pinGBSerialOut,LOW);//Nothing to send - - modeLSDJSlaveSync(); -} - -void modeLSDJSlaveSync() -{ - while(1){ //Loop forever - if (Serial.available() > 0) { //If MIDI Byte Availaibleleleiel - incomingMidiByte = Serial.read(); //Read it - Serial.print(incomingMidiByte, BYTE); //Send it back to the Midi out - - if(incomingMidiByte > 0x7F) { //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 - sendByteReversed(midiDefaultStartOffset); //send the offset - } - sendClockTickToLSDJ(); //send the clock tick - } - 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 == syncEffectsMidiChannel) { //if a midi note was received and its on the channel of the sync effects channel - midiNoteOnMode = true; //turn on note capture - incomingMidiData[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(!incomingMidiData[0]) { //if there is no note number yet - incomingMidiData[0] = incomingMidiByte; //then assume the byte is a note and assign it to a place holder - } else { //else assumed velocity - if(incomingMidiByte > 0x00) { - getSlaveSyncEffect(incomingMidiData[0]); //then call our sync effects function - } - incomingMidiData[0] = false; //and reset the captured note - } - } - } - setMode(); //Check if the mode button was depressed - } -} - -/* - Again its magic time, but this time its backweirds - We'll send a byte to the gameboy starting with big endian - From this point on I'm sick of writing comments -*/ -void sendByteReversed(byte send_byte) -{ - for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { //NEWS FLASH: there are 8 bits in a byte - digitalWrite(pinGBClock,LOW); //Set the clock to zero, wes about to send you somethin - if(send_byte & 0x80) { //Magic - digitalWrite(pinGBSerialOut,HIGH); //1 - } else { - digitalWrite(pinGBSerialOut,LOW); //0 - } - send_byte <<= 1; //More magic - digitalWrite(pinGBClock,HIGH); //Make the clock 1, so we can make a funky squarewave - } - digitalWrite(pinGBSerialOut,LOW); //We are done, turn the serial off -} - -/* - sendClockTickToLSDJ is a lovely loving simple function I wish they where all this short - Technicallyly we are sending nothing but a 8bit clock pulse -*/ -void sendClockTickToLSDJ() -{ - for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { - digitalWrite(pinGBClock,LOW);digitalWrite(pinGBClock,HIGH); - } -} - -/* - getSlaveSyncEffect receives a note, and assigns the propper effect of that note -*/ -void getSlaveSyncEffect(byte note) -{ - switch(note) { - case 48: //C-3ish, Transport Start - sequencerStart(); - break; - case 49: //C#3 Transport Stop - sequencerStop(); - break; - case 50: //D-3 Turn off sync effects - midiSyncEffectsTime = false; - break; - case 51: //D#3 Sync effect, 1/2 time - midiSyncEffectsTime = true; - countSyncTime = 0; - countSyncSteps = 2; - break; - case 52: //E-3 Sync Effect, 1/4 time - midiSyncEffectsTime = true; - countSyncTime = 0; - countSyncSteps = 4; - break; - case 53: //F-3 Sync Effect, 1/8 time - midiSyncEffectsTime = true; - countSyncTime = 0; - countSyncSteps = 8; - break; - default: //All other notes will make LSDJ Start at the row number thats the same as the note number. - midiDefaultStartOffset = incomingMidiData[0]; - break; - } -} +/************************************************************************** + * Name: Timothy Lamb * + * Email: trash80@gmail.com * + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +void modeLSDJSlaveSyncSetup() +{ + digitalWrite(pinStatusLed,LOW); + pinMode(pinGBClock,OUTPUT); //Set the gb clock as output + digitalWrite(pinGBClock,HIGH); //Gameboy likes to get high + digitalWrite(pinGBSerialOut,LOW);//Nothing to send + + modeLSDJSlaveSync(); +} + +void modeLSDJSlaveSync() +{ + while(1){ //Loop forever + if (Serial.available() > 0) { //If MIDI Byte Availaibleleleiel + incomingMidiByte = Serial.read(); //Read it + Serial.print(incomingMidiByte, BYTE); //Send it back to the Midi out + + if(incomingMidiByte > 0x7F) { //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 + sendByteReversed(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 == syncEffectsMidiChannel) { //if a midi note was received and its on the channel of the sync effects channel + midiNoteOnMode = true; //turn on note capture + incomingMidiData[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(!incomingMidiData[0]) { //if there is no note number yet + incomingMidiData[0] = incomingMidiByte; //then assume the byte is a note and assign it to a place holder + } else { //else assumed velocity + if(incomingMidiByte > 0x00) { + getSlaveSyncEffect(incomingMidiData[0]); //then call our sync effects function + } + incomingMidiData[0] = false; //and reset the captured note + } + } + } + setMode(); //Check if the mode button was depressed + updateStatusLight(); + } +} + +/* + Again its magic time, but this time its backweirds + We'll send a byte to the gameboy starting with big endian + From this point on I'm sick of writing comments +*/ +void sendByteReversed(byte send_byte) +{ + for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { //NEWS FLASH: there are 8 bits in a byte + digitalWrite(pinGBClock,LOW); //Set the clock to zero, wes about to send you somethin + if(send_byte & 0x80) { //Magic + digitalWrite(pinGBSerialOut,HIGH); //1 + } else { + digitalWrite(pinGBSerialOut,LOW); //0 + } + send_byte <<= 1; //More magic + digitalWrite(pinGBClock,HIGH); //Make the clock 1, so we can make a funky squarewave + } + digitalWrite(pinGBSerialOut,LOW); //We are done, turn the serial off +} + +/* + sendClockTickToLSDJ is a lovely loving simple function I wish they where all this short + Technicallyly we are sending nothing but a 8bit clock pulse +*/ +void sendClockTickToLSDJ() +{ + for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { + digitalWrite(pinGBClock,LOW);digitalWrite(pinGBClock,HIGH); + } +} + +/* + getSlaveSyncEffect receives a note, and assigns the propper effect of that note +*/ +void getSlaveSyncEffect(byte note) +{ + switch(note) { + case 48: //C-3ish, Transport Start + sequencerStart(); + break; + case 49: //C#3 Transport Stop + sequencerStop(); + break; + case 50: //D-3 Turn off sync effects + midiSyncEffectsTime = false; + break; + case 51: //D#3 Sync effect, 1/2 time + midiSyncEffectsTime = true; + countSyncTime = 0; + countSyncSteps = 2; + break; + case 52: //E-3 Sync Effect, 1/4 time + midiSyncEffectsTime = true; + countSyncTime = 0; + countSyncSteps = 4; + break; + case 53: //F-3 Sync Effect, 1/8 time + midiSyncEffectsTime = true; + countSyncTime = 0; + countSyncSteps = 8; + break; + default: //All other notes will make LSDJ Start at the row number thats the same as the note number. + midiDefaultStartOffset = incomingMidiData[0]; + break; + } +} diff --git a/Arduinoboy/Mode_MidiGb.ino b/Arduinoboy/Mode_MidiGb.ino old mode 100755 new mode 100644 index cead34f..0c8d78d --- a/Arduinoboy/Mode_MidiGb.ino +++ b/Arduinoboy/Mode_MidiGb.ino @@ -1,115 +1,240 @@ -void modeMidiGbSetup() -{ - digitalWrite(pinStatusLed,LOW); - pinMode(pinGBClock,OUTPUT); //make sure our gameboy Clock is set for OUTPUT mode - //digitalWrite(pinGBClock,LOW); //Generally this should be HIGH ie: 1, on, whatever. but since we are emulating a pc keyboard it should be LOW/0/off - modeMidiGb(); -} - -void modeMidiGb() -{ - while(1){ //Loop foreverrrr - - if (Serial.available() > 0) { //If MIDI is sending - incomingMidiByte = Serial.read(); //Get the byte sent from MIDI - //addFSGameboyByte(incomingMidiByte); - //if(!usbMode) Serial.print(incomingMidiByte, BYTE); //Echo the Byte to MIDI Output - if(incomingMidiByte > 0x7F) { - switch (incomingMidiByte & 0xF0) { - case 0xF0: - midiValueMode = false; - break; - default: - incomingMidiData[0] = incomingMidiByte; - midiValueMode = false; - midiAddressMode = true; - break; - } - } else if (midiAddressMode){ - midiAddressMode = false; - midiValueMode = true; - incomingMidiData[1] = incomingMidiByte; - } else if (midiValueMode) { - incomingMidiData[2] = incomingMidiByte; - midiAddressMode = true; - midiValueMode = false; - - if(lastMidiData[0] != incomingMidiData[0] || - lastMidiData[1] != incomingMidiData[1] || - lastMidiData[2] != incomingMidiData[2]) { - if(lastMidiData[0] != incomingMidiData[0]) { - addFSGameboyByte(incomingMidiData[0]); - } - - addFSGameboyByte(incomingMidiData[1]); - addFSGameboyByte(incomingMidiData[2]); - - lastMidiData[0] = incomingMidiData[0]; - lastMidiData[1] = incomingMidiData[1]; - lastMidiData[2] = incomingMidiData[2]; - } - } - } - updateFSGameboyByteFrame(); // Send out Bytes to LSDJ - setMode(); // Check if mode button was depressed - } -} - -boolean checkGbSerialStopped() -{ - countClockPause++; //Increment the counter - if(countClockPause > 16000) { //if we've reached our waiting period - countClockPause = 0; //reset our clock - Serial.print(0xFC, BYTE); //send the transport stop message - return true; - } - return false; -} - -void addFSGameboyByte(byte send_byte) -{ - serialWriteBuffer[writePosition] = send_byte; //assign new byte - writePosition++; //increment the write position - writePosition = writePosition % 256; //make sure our write position is between 0 to 255 by using a mod of 256 -} - - /* - updateGameboyByteFrame is responcible responsibel resp.... job is to wait a period of time, - and then send a byte to the gameboy byte output function. - */ -void updateFSGameboyByteFrame() -{ - if(readPosition != writePosition){ //if we have something to read out - waitClock++; //then increment our counter - if(waitClock > gameboyBytePause) { //if we've exceeded our wait time - waitClock=0; //reset the counter - //statusLedOn(); //turn on the awesome visuals - sendFSByteToGameboy(serialWriteBuffer[readPosition]); //send the byte out - readPosition++; //increment our read position - readPosition = readPosition % 256; //wrap our reading range from 0 to 255 - } - } -} - /* - sendByteToGameboy does what it says. yay magic - */ -void sendFSByteToGameboy(byte send_byte) //changed by firestARTer: send routine changed MST is send out first!!!!!!! -{ - for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { //we are going to send 8 bits, so do a loop 8 times -// digitalWrite(pinGBClock,HIGH); //Set our clock output to 1 - if(send_byte & 0x80) { //if the first bit is equal to 1 - digitalWrite(pinGBSerialOut,HIGH); //then send a 1 - } else { - digitalWrite(pinGBSerialOut,LOW); //send a 0 - } - send_byte <<= 1; //bitshift right once for the next bit we are going to send - digitalWrite(pinGBClock,LOW); //send a 0 to the clock, we finished sending the bit - - delayMicroseconds(gameboyBitPause); // firestARter : play around with this value, sometimes the gameboy needs more time between messages - digitalWrite(pinGBClock,HIGH); //send a 0 to the clock, we finished sending the bit - - } - digitalWrite(pinGBSerialOut,LOW); //make sure the serial state returns to 0 after its done sending the bits - delayMicroseconds(gameboyBitPause); // firestARter : play around with this value, sometimes the gameboy needs more time between messages - -} +/************************************************************************** + * Name: Timothy Lamb * + * Email: trash80@gmail.com * + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +void modeMidiGbSetup() +{ + digitalWrite(pinStatusLed,LOW); + pinMode(pinGBClock,OUTPUT); //make sure our gameboy Clock is set for OUTPUT mode + digitalWrite(pinGBClock,LOW); //Generally this should be HIGH ie: 1, on, whatever. but since we are emulating a pc keyboard it should be LOW/0/off + modeMidiGb(); +} + +void modeMidiGb() +{ + while(1){ //Loop foreverrrr + + if (Serial.available() > 0) { //If MIDI is sending + incomingMidiByte = Serial.read(); //Get the byte sent from MIDI + //addFSGameboyByte(incomingMidiByte); + //if(!usbMode) Serial.print(incomingMidiByte, BYTE); //Echo the Byte to MIDI Output + if(incomingMidiByte > 0x7F) { + switch (incomingMidiByte & 0xF0) { + case 0xF0: + midiValueMode = false; + break; + default: + incomingMidiData[0] = incomingMidiByte; + midiValueMode = false; + midiAddressMode = true; + break; + } + } else if (midiAddressMode){ + midiAddressMode = false; + midiValueMode = true; + incomingMidiData[1] = incomingMidiByte; + } else if (midiValueMode) { + incomingMidiData[2] = incomingMidiByte; + midiAddressMode = true; + midiValueMode = false; + + if(lastMidiData[0] != incomingMidiData[0] || + lastMidiData[1] != incomingMidiData[1] || + lastMidiData[2] != incomingMidiData[2]) { + if(lastMidiData[0] != incomingMidiData[0]) { + addFSGameboyByte(incomingMidiData[0]); + } + + addFSGameboyByte(incomingMidiData[1]); + addFSGameboyByte(incomingMidiData[2]); + + lastMidiData[0] = incomingMidiData[0]; + lastMidiData[1] = incomingMidiData[1]; + lastMidiData[2] = incomingMidiData[2]; + blinkLight(incomingMidiData[0],incomingMidiData[2]); + } + } + } + updateFSGameboyByteFrame(); // Send out Bytes to LSDJ + updateBlinkLights(); + setMode(); // Check if mode button was depressed + } +} + +void updateBlinkLights() +{ + updateBlinkLight(0); + updateBlinkLight(1); + updateBlinkLight(2); + updateBlinkLight(3); + updateStatusLight(); +} + +void updateBlinkLight(int light) +{ + if(blinkSwitch[light]) { + blinkSwitchTime[light]++; + if(blinkSwitchTime[light] > 2000) { + blinkSwitch[light]=0; + blinkSwitchTime[light]=0; + digitalWrite(pinLeds[light],LOW); + } + } +} + +void updateStatusLight() +{ + if(blinkSwitch[4]) { + blinkSwitchTime[4]++; + if(blinkSwitchTime[4] > 2000) { + blinkSwitch[4]=0; + blinkSwitchTime[4]=0; + digitalWrite(pinStatusLed,LOW); + } + } +} + +void blinkLight(byte midiMessage, byte midiValue) +{ + if(midiValue) { + switch(midiMessage) { + case 0x90: + if(!blinkSwitch[0]) digitalWrite(pinLeds[0],HIGH); + blinkSwitch[0]=1; + blinkSwitchTime[0]=0; + break; + case 0x91: + if(!blinkSwitch[1]) digitalWrite(pinLeds[1],HIGH); + blinkSwitch[1]=1; + blinkSwitchTime[1]=0; + break; + case 0x92: + if(!blinkSwitch[2]) digitalWrite(pinLeds[2],HIGH); + blinkSwitch[2]=1; + blinkSwitchTime[2]=0; + break; + case 0x93: + if(!blinkSwitch[3]) digitalWrite(pinLeds[3],HIGH); + blinkSwitch[3]=1; + blinkSwitchTime[3]=0; + break; + case 0x94: + if(!blinkSwitch[0]) digitalWrite(pinLeds[0],HIGH); + blinkSwitch[0]=1; + blinkSwitchTime[0]=0; + if(!blinkSwitch[1]) digitalWrite(pinLeds[1],HIGH); + blinkSwitch[1]=1; + blinkSwitchTime[1]=0; + if(!blinkSwitch[2]) digitalWrite(pinLeds[2],HIGH); + blinkSwitch[2]=1; + blinkSwitchTime[2]=0; + break; + } + } + switch(midiMessage) { + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + if(!blinkSwitch[4]) digitalWrite(pinStatusLed,HIGH); + blinkSwitch[4]=1; + blinkSwitchTime[4]=0; + break; + default: + break; + } +} + +void updateVisualSync() +{ + if(!countSyncTime) { + if(!blinkSwitch[4]) digitalWrite(pinStatusLed,HIGH); + digitalWrite(pinLeds[0],LOW); + digitalWrite(pinLeds[1],LOW); + digitalWrite(pinLeds[2],LOW); + digitalWrite(pinLeds[3],LOW); + digitalWrite(pinLeds[switchLight],HIGH); + blinkSwitch[4]=1; + blinkSwitchTime[4]=0; + countSyncLightTime = 0; + switchLight++; + if(switchLight==4) switchLight=0; + } + countSyncTime++; + if(countSyncTime == 24) countSyncTime=0; +} + +boolean checkGbSerialStopped() +{ + countClockPause++; //Increment the counter + if(countClockPause > 16000) { //if we've reached our waiting period + countClockPause = 0; //reset our clock + Serial.print(0xFC, BYTE); //send the transport stop message + return true; + } + return false; +} + +void addFSGameboyByte(byte send_byte) +{ + serialWriteBuffer[writePosition] = send_byte; //assign new byte + writePosition++; //increment the write position + writePosition = writePosition % 256; //make sure our write position is between 0 to 255 by using a mod of 256 +} + + /* + updateGameboyByteFrame is responcible responsibel resp.... job is to wait a period of time, + and then send a byte to the gameboy byte output function. + */ +void updateFSGameboyByteFrame() +{ + if(readPosition != writePosition){ //if we have something to read out + waitClock++; //then increment our counter + if(waitClock > gameboyBytePause) { //if we've exceeded our wait time + waitClock=0; //reset the counter + //statusLedOn(); //turn on the awesome visuals + sendFSByteToGameboy(serialWriteBuffer[readPosition]); //send the byte out + readPosition++; //increment our read position + readPosition = readPosition % 256; //wrap our reading range from 0 to 255 + } + } +} + /* + sendByteToGameboy does what it says. yay magic + */ +void sendFSByteToGameboy(byte send_byte) //changed by firestARTer: send routine changed MST is send out first!!!!!!! +{ + for(countLSDJTicks=0;countLSDJTicks<8;countLSDJTicks++) { //we are going to send 8 bits, so do a loop 8 times +// digitalWrite(pinGBClock,HIGH); //Set our clock output to 1 + if(send_byte & 0x80) { //if the first bit is equal to 1 + digitalWrite(pinGBSerialOut,HIGH); //then send a 1 + } else { + digitalWrite(pinGBSerialOut,LOW); //send a 0 + } + send_byte <<= 1; //bitshift right once for the next bit we are going to send + digitalWrite(pinGBClock,LOW); //send a 0 to the clock, we finished sending the bit + + delayMicroseconds(gameboyBitPauseLOW); // firestARter : play around with this value, sometimes the gameboy needs more time between messages + digitalWrite(pinGBClock,HIGH); //send a 0 to the clock, we finished sending the bit + delayMicroseconds(gameboyBitPauseHIGH); // firestARter : play around with this value, sometimes the gameboy needs more time between messages + + } + digitalWrite(pinGBSerialOut,LOW); //make sure the serial state returns to 0 after its done sending the bits +// delayMicroseconds(gameboyBitPauseLOW); // firestARter : play around with this value, sometimes the gameboy needs more time between messages + +} diff --git a/Arduinoboy/Mode_Nanoloop.ino b/Arduinoboy/Mode_Nanoloop.ino old mode 100755 new mode 100644 index 293c8c3..bcc459a --- a/Arduinoboy/Mode_Nanoloop.ino +++ b/Arduinoboy/Mode_Nanoloop.ino @@ -1,75 +1,76 @@ -/************************************************************************** - * Name: Timothy Lamb * - * Email: trash80@gmail.com * - ***************************************************************************/ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -void modeNanoloopSetup() -{ - digitalWrite(pinStatusLed,LOW); - pinMode(pinGBClock,OUTPUT); //Set the gb clock as output - digitalWrite(pinGBClock,LOW); //Gameboy likes to get low - - modeNanoloopSync(); -} - -void modeNanoloopSync() -{ - while(1){ //Loop forever - if (Serial.available() > 0) { //If MIDI Byte Availaibleleleiel - incomingMidiByte = Serial.read(); //Read it - Serial.print(incomingMidiByte, BYTE); //Send it back to the Midi out - - if(incomingMidiByte > 0x7F) { //If we have received a MIDI Status Byte - 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); - - 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 - } -} - -boolean sendTickToNanoloop(boolean state, boolean last_state) -{ - if(!state) { - if(last_state) { - digitalWrite(pinGBSerialOut,HIGH); - } else { - digitalWrite(pinGBSerialOut,LOW); - } - return true; - } else { - digitalWrite(pinGBSerialOut,HIGH); - return false; - } -} +/************************************************************************** + * Name: Timothy Lamb * + * Email: trash80@gmail.com * + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +void modeNanoloopSetup() +{ + digitalWrite(pinStatusLed,LOW); + pinMode(pinGBClock,OUTPUT); //Set the gb clock as output + digitalWrite(pinGBClock,LOW); //Gameboy likes to get low + + modeNanoloopSync(); +} + +void modeNanoloopSync() +{ + while(1){ //Loop forever + if (Serial.available() > 0) { //If MIDI Byte Availaibleleleiel + incomingMidiByte = Serial.read(); //Read it + Serial.print(incomingMidiByte, BYTE); //Send it back to the Midi out + + if(incomingMidiByte > 0x7F) { //If we have received a MIDI Status Byte + 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(); + } +} + +boolean sendTickToNanoloop(boolean state, boolean last_state) +{ + if(!state) { + if(last_state) { + digitalWrite(pinGBSerialOut,HIGH); + } else { + digitalWrite(pinGBSerialOut,LOW); + } + return true; + } else { + digitalWrite(pinGBSerialOut,HIGH); + return false; + } +}