1 / 43

MIDI Manipulation

Learn about MIDI manipulation techniques like double and triple tracking, chord generation, arpeggiator, delays, and more. Explore MIDI setups, Arduino integration, and analog tracking methods.

shannonv
Download Presentation

MIDI Manipulation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. MIDI Manipulation Dr. Veton Kepuska

  2. MIDI Manipulation • MIDI Manipulation • Double and Triple Tracking • Automatic Generation of triad Chords • A MIDI arpegiator • Delays and Echos • A MIDI Lopper Pedal

  3. The Midi Setup • The projects discussed in this chapter related to intercepting MIDI data from a keyboard or other MIDI instruments and manipulating those intercepted data to achieve desired effect. • Two Basic Setups are displayed in the next figure.

  4. MIDI Setup #1 Keyboard MIDI OUT MIDI IN Arduino & Shield MIDI OUT MIDI IN Audio Amplifier Sound Module Audio Speaker

  5. MIDI Setup #2 Keyboard MIDI OUT MIDI IN Arduino & Shield MIDI OUT Laptop MIDI IN USB/MIDI Lead

  6. The Midi Setup • Arduino can be used to act as a USB HID MIDI device. • USB Interfaces can be of 2 kids: • Client • Server • While the Client USB interface is simple, Server is significantly more complicated.

  7. Double Tracking

  8. Double Tracking • Basic Double Tracking • Multiple Tracking

  9. Basic Double Tracking • Double Tracking occurs anytime when an input ‘note on’ or ‘note off’ message is repeated on another channel.

  10. /* MIDI Double Track * Listen for MIDI note on/off * data, and play it back on the * next track */ booleannoteDown = LOW; byte channel = 0; // MIDI Channel responds to this // change the channel number // MIDI channel = the value in ‘channel’ +1 void setup() { // start serial with MIDI bound rate Serial.begin(31250); } void loop () { chekIn(); } void checkIn() { #A static byte note = 60; static byte state = 0; // command waiting = 0 // note waiting = 1 // velocity waiting = 2 if (Serial.available() > 0) { byte incomingByte = Serial.read(); Serial.write(incomingByte); switch (state) { case 0: #B if (incomingByte == (0x90 | channel) { noteDown = HIGH; state = 1; } if (incomingByte == (0x80 | channel) { noteDown = LOW; state = 1; } if ((incomingByte & 0xE0) == 0xC0) { state = 4; } if ((incomingByte & 0xE0) == 0xA0) { state = 3; } break; case 1: #C if (incomingByte < 128) { note = incomingByte; state 2; } else { state = 0; } break; case 2: #D if (incomingByte < 128) { doNote(note, incomingByte, noteDown); } state = 0; break;

  11. case 3: #B state = 4 break; case 4: #E state = 4 break; } } } void doNote(byte note, byte velocity, int down) { if ((down == HIGH) && (velocity == 0)) { down = LOW; } if (down == LOW) { noteSend(0x80, note, velocity); } else { noteSend(0x90, note, velocity); } } void noteSend(byte cmd, byte data1, byte data2) { cmd = cmd | byte((channel+1) & 0xf); Serial.write(cmd); Serial.write(data1); Serial.write(data2); } #A The state machine for reading in a MIDI message over several bytes #B This is the first byte so look and see what sort of message it might be #C The second byte in a note message will be the note number #D The third byte is the velocity – note message is complete #E A multi byte message that we are not interested in so we just let the data pass

  12. MIDI Manipulation • checkIn() is the key function in the previous slide. • It reads each byte in turn, and latches onto the “note On” and “note Off” messages for our channel.

  13. Analog Double Tracking

  14. Analogue Double Tracking (ADT) • It is know as a ADT • Sound is generated normally at or close to the center of the stereo stage. • Then the sound is doubled by sending one note to the left and the other to the right side.

  15. void setup() { Serial.begin(31250); //start serial with MIDI bound rate //set pan for the two channels controlSend(10, 0, channel); // MSB #A controlSend(42, 0, channel); // LSB #A controlSend(10, 127, (channel+1) & 0xf); // MSB#A controlSend(42, 127, (channel+1) & 0xf); // LSB #A }

  16. void controlSend( byte CCnumber, byte CCdata, byte CCchannel) { #B CCchannel |= 0xB0; //convert to Control message Serial.write(CCchannel); Serial.write(CCnumber); Serial.write(CCdata); } #A Set up the stereo position of each channel #B Function to send out a controller change message to the specific channel

  17. Analog triple Tracking

  18. Variation of the double tracking by adding one more note: • Left, • Right, • Center.

  19. void setup() { Serial.begin(31250); //start serial with MIDI bound rate //set pan for the two channels controlSend(10, 0, channel); // MSB #A controlSend(42, 0, channel); // LSB #A controlSend(10, 127, (channel+1) & 0xf); // MSB#A controlSend(42, 127, (channel+1) & 0xf); // LSB #A controlSend(10, 127, (channel+2) & 0xf); // MSB #A controlSend(42, 127, (channel+2) & 0xf); // LSB #A }

  20. void doNote(byte note, byte velocity, int down) { // ifvelcotiy = 0 on a ‘Note ON’ command, treat it as a note off if ((down == HIGH) && (velocity == 0)) { down = LOW; } // send out this note mesage if (down == LOW) { // note off noteSend(0x80, note, velocity, 0x1); noteSend(0x80, note-12, velocity, 0x2); #B } else { // note on noteSend(0x90, note, velocity, 0x1); float v = (float) velocity * 0.75; #C noteSend(0x90, note-12, (byte)v, 0x2); // send third note } }

  21. void controlSend( byte CCnumber, byte CCdata, byte CCchannel) { CCchannel |= 0xB0; //convert to Control message Serial.write(CCchannel); Serial.write(CCnumber); Serial.write(CCdata); } #A Set up the stereo position of each channel #B Note an octave or 12 semitones lower #C Reduce the volume by %75

  22. Analog triple Tracking • As can be seen from the code of controlSend function is similar to the previous (double tracking) example and the setup function has additional channel in it. • The main change is in replacement of the doNote function with the one listed and the noteSend function so that it accepts a channel offset parameter. float v = (float) velocity * 0.75; noteSend(0x90, note – 12, (byte) v, 0x2); // send third note

  23. Analog triple Tracking • Modifies the note by moving it down an octave; this is accomplished by subtracting 12 from the note number. • Reduction of the velocity and hence the value of it is being multiplied by 0.75 (quarter off its value). Because 0.75 is a fraction it needs to be computed using floating point multiplication instead of int.

  24. Doubling a note with Triple tracking

  25. Problem: How to modify the program so that a note is repeated or doubled on channel 9?

  26. Doubling a note with Triple Tracking // variables setup constint led = 13; long time; booleannoteDonw = LOW; // MIDI channel to respond to (in this case channel 1) const byte ourChannel = 1; // setup: declaring inputs and outputs void setup() { pinMode(led, LOW); time = millis() + 2000; // setup call back channels #A usbMIDI.setHandleNoteOff(doNoteOff); usbMIDI.setHandleNoteOn(doNoteOn); usbMIDI.setHandleVelocityChange(doVelocityChange); usbMIDI.setHandleControlChange(doControlChange); usbMIDI.setHandleProgramChange(doProgramChange); usbMIDI.setHandleAfterTouch(doAfterTouch); usbMIDI.setHandlePitchChange(doPitchChange);

  27. Doubling a note with Triple Tracking // setpan fro the three channels #B usbMIDI.sendControlChange(10, 0, outChannel); // MSB usbMIDI.sendControlChange(42, 0, outChannel); // LSB usbMIDI.sendControlChange(10, 127, (outChannel+1) & 0xf); // MSB usbMIDI.sendControlChange(42, 127, (outChannel+1) & 0xf); // LSB usbMIDI.sendControlChange(10, 64, (outChannel+2) & 0xf); // MSB usbMIDI.sendControlChange(42, 64, (outChannel+2) & 0xf); // LSB } // loop: wait for serial data, and interpret the message void loop () { usbMIDI.read(); #C } // call back functions basically echo most staff void doVecolcityChange(byte channel, byte note, byte velocity) { #D usbMIDI.sendPolyPressure(note, velocity, channel); } Void doControlChange(byte channel, byte control, byte value) { #D usbMIDI.sendControlChange(control, value, channel); }

  28. Doubling a note with Triple Tracking void doProgramChange(byte channel, byte program) { #D usbMIDI.sendProgramChange(program, channel); } void doAfterTouchChange(byte channel, byte pressure) { #D usbMIDI.sendAfterTouchPressure(preassure, channel); } void doPitchChange(byte channel, int pitch) { #D usbMIDI.sendPitcChange(pitch, channel); } void doNoteOn(byte channel, byte note, byte velocity) { digitalWrite(led, HIGH); usbMIDI.sendNoteOn(note, velocity, channel); if (channel == ourChannel) { // pick out the note we are looking for doNote(note, velocity, false); } }

  29. Doubling a note with Triple Tracking void doNote(byte note, byte velocity, int down) { // if velocity = 0 on a ‘Note ON’ command, treat it as a note off if ((down == HIGH) && (velocity == 0)) { down = LOW; } // send out this note message if (down == LOW) { // note off usbMIDI.sendNoteOff(note, velocity, (ourChannel + 1) & 0xf); usbMIDI.sendNoteOff(note, velocity, (ourChannel+ 2) & 0xf); } else { usbMIDI.sendNoteOn(note, velocity, (ourChannel+ 1) & 0xf); float v = (float)velocity * 0.75; usbMIDI.sendNoteOff(note - 12, (byte) v, (ourChannel+ 2) & 0xf); } }

  30. Doubling a note with Triple Tracking #A Tell the built in MIDI library what function to call when each MIDI event happens #B Send stereo position information to your sound module #C Checks for any MIDI message and calls the previously declared function if one has arrived #D We don’t want to do anything about these messages just pass them through #E This is a message we want to do something with

  31. The one finger wonder

  32. Triad Chord Basics • Imagine that you had a limited keyboard skills. • If you are able to pick one note and as a result a hole cord was played! • That is what we have described earlier – generation of a triad of sounds. • Triad is set of three notes – a root node is played as additional tow other notes spaced 1/3 and 1/5 from the root note.

  33. Triad Chord Basics • The four types of a Triad Chord

  34. Triad Chord Basics

  35. Creating a Triad Chord with Arduino

  36. Creating a Triad Chord with Arduino Bass Triad on/off Triad on/off Chord Type Select

  37. The “One Finger Wonder” // variables set up booleannoteDown = LOW; byte channel = 0; // MIDI channel to respnd to // MIDI channel = the value in ‘channel’ +1 boolean bass = true, enableTriad = true; constintbassPin = 12, triadPin = 10; constint tiradPin1 = 8, triadPin2 = 6; // Major, minor, diminished, augmented byte thirds [] = {4, 3, 3, 4}; byte fifths [] = {7, 7, 6, 8}; // setup: declaring input and outputs and begin serial void setup() { pinMode(bassPin, INPUT_PULLUP); #A pinMode(triadPin, INPUT_PULLUP); #A pinMode((triadPin1, INPUT_PULLUP); #A pinMode((triadPin2, INPUT_PULLUP); #A Serial.begin(31250); // start serial with MIDI baud rate }

  38. The “One Finger Wonder” // loop: wait for serial data, and interpret the message void loop() { chekIn(); // see if anything has arrived at the input getControls(); // get switch values } Void getControls() { #B bass = digitalRead(bassPin); triad = (digitalRead(triadPin1) & 0x1) | ((digitalRead(triadPin2) & 0x1) << 1) enableTriad = digitalRead(traidPin); } void doNote(byte note, byte velocity, int down) { // if velocity = 0 ona ‘Note ON’ command, treat it as a note OFF if ((down == HIGH) && (velocity == 1)) { down = LOW; }

  39. The “One Finger Wonder” // send the other notes of the triad if (down == LOW) { // note off if enableTriad) { noteSend(0x80, note+thirds[triad], velocity); noteSend(0x80, note+fifths[triad], velocity); if (bass) noteSend(0x80, note-12, velocity); } } else { // note on if (enableTriad) { noteSend(0x90, note+thirds[triad], velocity); noteSend(0x90, note+fifths[triad], velocity); if (bass) noteSend(0x90, note-12, velocity); } } }

  40. The “One Finger Wonder” void noteSend(char cmd, char data1, cahr data2) { cmd = cmd | char(channel); // next channel number up Serial.write(cmd); Serial.write(data1); Serial.write(data2); } void checkIn() { static byte note = 60; static byte state = 0; // state machine variable if (Serial.available() > 0) { // read incoming byte byte incomingByte = Serial.read(); Serial.write(incomingByte); }

  41. The “One Finger Wonder” switch (state) { case 0; // look for as status-byte, our channel, note on if (incomingByte == (0x90 | channel)) { noteDown = HIGH; state = 1; } //look for as status-byte, our channel , note off if (incomingByte == (0x80 | channel)) { noteDown = LOW; state = 1; } break;

  42. The “One Finger Wonder” case 1; // get the note to play or stop if (incomingByte < 128) { note = inomingByte; state = 2; } else { state = 0; // reset state machine as this // be a note number } break; case 2; // Get the velocity if (incomingByte < 128) { // do something with the note on message doNote(note, incommingByte, noteDown); } state = 0; // reset state machine to start } } } #A Tell the Arduino to enable the internal pull up resistors so the inputs don’t float #B Loot at the state of the switches incase they have changed #C Send three notes all relative to the original note #D We have seen this before in the other listing – tease the MIDI message from the input stream

More Related