Have followed Gordophone's lead again but instead of using the Ruin + Wesen MIDI library, I've used the library from fortyseveneffects. The class library description is here. I liked this library as it's only a set of midi.cpp and midi.h files that are quite well laid out and described and pretty easy to follow. Certainly gives me some comfort that if I need to jump in there and start twiddling with the code I've got a good basis to step on from.
BTW, for those of you on a Mac, adding libraries to Arduino installs requires finding the Arduino app, showing the package contents (in Finder click the cog wheel, select Show Package Contents) and then navigate to Contents/Resources/Java/libraries. I put the midi.cpp and midi.h into a new folder called Midi.
Here's the code... basically a reworking of Marmonizer v1 to read the MIDI input and transpose the note up or down an octave. The pot input is read with an analogRead, mapped to +/-12 and then the variable transposition is added to the incoming midiOn messages.
Note - ref to the MIDI numbers, note names and frequencies for me to find when I read this again. One octave is mapped to 12 semitones. In MIDI Middle C (C4 = 60).
/////////////////////////////////////////////////////////////////////// // // HondrouMidifier // // Initial testing using Gordon Good's Marmonizer as a base // http://gordophone.blogspot.co.uk/2010/01/marmonizer-v1.html // Gordon Good (velo27 <at> yahoo <dot> com) // // Have used the MIDI library from FortySevenEffects instead of the Ruin+Wesen // library. // http://fortyseveneffects.github.io/arduino_midi_library/ // To prove some basic assumptions, the very first version is a simple MIDI // transposer. The input note is transposed up or down, and the amount of // transposition is controlled by a voltage applied to analog input 0, // e.g. with a potentiometer. // // This proves: // - That we can do the transposition with reasonable latency // - That we've got the Midi library working properly // // Note: this will probably leave dangling notes if the transposition is // changed between a note on and the corresponding note off. The final // code will have to account for user knob-twisting while playing, and // make sure it turns off the right notes. Probably some sort of a map // that relates a received note to all the note on messages it spawned. // #include <SoftwareSerial.h> #include <Midi.h> SoftwareSerial MusicSerial(2, 3); //Soft TX on 3, we don't use RX in this code // defines for MIDI Shield components only #define KNOB1 0 #define KNOB2 1 #define STAT1 7 #define STAT2 6 // Music shield pins - both digital #define MUSIC_PIN_MIDI_IN 3 // soft serial TX -> VS1053 RX #define MUSIC_PIN_RESET 4 // VS1053 RESET int trPotPin = KNOB1; // Analog pin for reading the transposition potentiometer int ledPin = STAT1; // LED pin to blink for debugging int transposition = 0; // number of semitones to transpose (negative = transpose down) void noteOnCallback(byte channel, byte pitch, byte velocity) { digitalWrite(ledPin, HIGH); noteOn(channel, pitch + transposition, velocity); } void noteOffCallback(byte channel, byte pitch, byte velocity) { digitalWrite(ledPin, LOW); noteOff(channel, pitch + transposition, velocity); } ///////////////////////////////////////////////////////////////////////////// // Setup routine ///////////////////////////////////////////////////////////////////////////// void setup() { pinMode(STAT1,OUTPUT); pinMode(STAT2,OUTPUT); // Initiate MIDI communications, listen to all channels MIDI.begin(MIDI_CHANNEL_OMNI); // Connect the HandleNoteOn function to the library, so it is called upon reception of // a NoteOn. MIDI.setHandleNoteOn(noteOnCallback); MIDI.setHandleNoteOff(noteOffCallback); pinMode(trPotPin, INPUT); digitalWrite(trPotPin, HIGH); // VS1053 //start serial with midi baudrate 31250 MusicSerial.begin(31250); // Reset the VS1053 pinMode(MUSIC_PIN_RESET, OUTPUT); digitalWrite(MUSIC_PIN_RESET, LOW); delay(100); digitalWrite(MUSIC_PIN_RESET, HIGH); delay(100); talkMIDI(0xB0, 0x07, 120); //0xB0 is channel message, set channel volume to near max (127) digitalWrite(STAT1,LOW); digitalWrite(STAT2,LOW); } ///////////////////////////////////////////////////////////////////////////// // Main loop ///////////////////////////////////////////////////////////////////////////// void loop() { // Read the transposition pot, and map the value to a + or - one octave transposition transposition = map(analogRead(trPotPin), 0, 1023, -12, 12); // Call MIDI.read the fastest you can for real-time performance. MIDI.read(); // There is no need to check if there are messages incoming if they are bound to a Callback // function. } ///////////////////////////////////////////////////////////////////////////// // Functions ///////////////////////////////////////////////////////////////////////////// //Send a MIDI note-on message. Like pressing a piano key //channel ranges from 0-15 void noteOn(byte channel, byte note, byte attack_velocity) { talkMIDI( (0x90 | channel), note, attack_velocity); } //Send a MIDI note-off message. Like releasing a piano key void noteOff(byte channel, byte note, byte release_velocity) { talkMIDI( (0x80 | channel), note, release_velocity); } //Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127 void talkMIDI(byte cmd, byte data1, byte data2) { digitalWrite(STAT1,HIGH); MusicSerial.write(cmd); MusicSerial.write(data1); //Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes //(sort of: http://253.ccarh.org/handout/midiprotocol/) if( (cmd & 0xF0) <= 0xB0) { MusicSerial.write(data2); } digitalWrite(STAT1,LOW); }
No comments:
Post a Comment