diff options
Diffstat (limited to 'Midi.h')
| -rw-r--r-- | Midi.h | 191 |
1 files changed, 191 insertions, 0 deletions
@@ -0,0 +1,191 @@ +/* + * Midi.h: Header for MIDI processing library, Arduino version + * + * (c) 2003-2008 Tymm Twillman <tymm@booyaka.com> + * + * This file is part of Tymm's Arduino Midi Library. + * + * Tymm's Arduino Midi Library is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 2.1 + * of the License, or (at your option) any later version. + * + * Tymm's Arduino Midi Library is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Tymm's Arduino Midi Library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef MIDI_H +#define MIDI_H + +#include "HardwareSerial.h" + + +/* + * This is the Midi class. If you are just sending Midi data, you only need to make an + * instance of the class, passing it your serial port -- in most cases it looks like + * + * Midi midi(Serial); + * + * then you don't need to do anything else; you can start using it to send Midi messages, + * e.g. + * + * midi.sendNoteOn(1, note, velocity); + * + * If you are using it to receive Midi data, it's a little more complex & you will need + * to subclass the Midi class. + * + * For people not used to C++ this may look confusing, but it's actually pretty easy. + * Note that you only need to write the functions for event types you want to handle. + * They should match the names & prototypes of the functions in the class; look at + * the functions in the Midi class below that have the keyword "virtual" to see which + * ones you can use. + * + * Here's an example of one that takes NOTE ON, NOTE OFF, and CONTROL CHANGE: + * + * class MyMidi : public Midi { + * public: + * + * // Need this to compile; it just hands things off to the Midi class. + * MyMidi(HardwareSerial &s) : Midi(s) {} + * + * void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) + * { + * if (note == 40) {digitalWrite(13, HIGH); } + * } + * + * void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) + * { + * if (note == 40) { digitalWrite(13, LOW); } + * } + * + * void handleControlChange(unsigned int channel, unsigned int controller, + * unsigned int value) + * { + * analogWrite(6, value * 2); + * } + * + * Then you need to make an instance of this class: + * + * MyMidi midi(Serial); + * + * If receiving Midi data, you also need to call the poll function every time through + * loop(); e.g. + * + * void loop() { + * midi.poll(); + * } + * + * This causes the Midi class to read data from the serial port and process it. + */ + +class Midi { +private: + // The serial port used by this Midi instance (it takes complete control over the port) + HardwareSerial serial_; + + /* Private Receive Parameters */ + + // The channel this Midi instance receives data for (0 means all channels) + int channelIn_; + + // These are for keeping track of partial Midi messages as bytes come in + int recvMode_; + int recvByteCount_; + int recvEvent_; + int recvArg0_; + int recvBytesNeeded_; + int lastStatusSent_; + + /* Private Send Parameters */ + + // This controls whether every Midi message gets a command byte sent with it + // (Midi can just send a single command byte and then stream events without + // sending the command each time) + bool sendFullCommands_; + + /* Internal functions */ + + // Called whenever data is read from the serial port + void recvByte(int byte); + + // This doesn't work -- by making it private, we ensure nobody ever calls it + Midi(); + +public: + // Set this parameter to anything other than 0 to cause every MIDI update to + // include a copy of the current event (e.g. for every note off to include + // the NOTE OFF event) -- by default, if an event is the same type of event as + // the last one sent, the event byte isn't sent; just the new note/velocity + static const unsigned int PARAM_SEND_FULL_COMMANDS = 0x1000; + + // Use this parameter to update the channel the MIDI code is looking for messages + // to. 0 means "all channels". + static const unsigned int PARAM_CHANNEL_IN = 0x1001; + + + // Constructor -- generally just use e.g. "Midi midi(Serial);" + Midi(HardwareSerial &serial); + + // Call to start the serial port, at given baud. For many applications + // the default parameters are just fine (which will cause messages for all + // MIDI channels to be delivered) + void begin(unsigned int channel = 0, unsigned long baud = 31250); + + + // Changes the updateable parameters (params are Midi::PARAM_SEND_FULL_COMMANDS or + // Midi::PARAM_CHANNEL_IN -- see above for what they mean) + void setParam(unsigned int param, unsigned int val); + + // Get current values for the user updateable parameters (params, etc same as above) + unsigned int getParam(unsigned int param); + + + // poll() should be called every time through loop() IF dealing with incoming MIDI + // (if you're only SENDING MIDI events from the Arduino, you don't need to call + // poll); it causes data to be read from the serial port and processed. + void poll(); + + // Call these to send MIDI messages of the given types + void sendNoteOff(unsigned int channel, unsigned int note, unsigned int velocity); + void sendNoteOn(unsigned int channel, unsigned int note, unsigned int velocity); + void sendVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity); + void sendControlChange(unsigned int channel, unsigned int controller, unsigned int value); + void sendProgramChange(unsigned int channel, unsigned int program); + void sendAfterTouch(unsigned int channel, unsigned int velocity); + void sendPitchChange(unsigned int pitch); + void sendSongPosition(unsigned int position); + void sendSongSelect(unsigned int song); + void sendTuneRequest(void); + void sendSync(void); + void sendStart(void); + void sendContinue(void); + void sendStop(void); + void sendActiveSense(void); + void sendReset(void); + + // Overload these in a subclass to get MIDI messages when they come in + virtual void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity); + virtual void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity); + virtual void handleVelocityChange(unsigned int channel, unsigned int note, unsigned int velocity); + virtual void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value); + virtual void handleProgramChange(unsigned int channel, unsigned int program); + virtual void handleAfterTouch(unsigned int channel, unsigned int velocity); + virtual void handlePitchChange(unsigned int pitch); + virtual void handleSongPosition(unsigned int position); + virtual void handleSongSelect(unsigned int song); + virtual void handleTuneRequest(void); + virtual void handleSync(void); + virtual void handleStart(void); + virtual void handleContinue(void); + virtual void handleStop(void); + virtual void handleActiveSense(void); + virtual void handleReset(void); +}; + +#endif /* #ifndef MIDI_H ... */ |
