MIDI out from DAW

Status
Not open for further replies.

Maxi_CF

Member
Hey everyone,

I get the feeling this might be an easy one, but haven't been able to figure it out myself :/

I want to get MIDI notes from Ableton and send them through my teensy2, which I use with a MIDI connector out.
This way I can sequence my hardware using Ableton.

I've managed to send notes with the code I have found :
"#include <MIDI.h>

const int channel = 10;

void setup() {
MIDI.begin();
}

void loop() {
int note;
for (note=40; note <= 60; note++) {
MIDI.sendNoteOn(note, 100, channel);
delay(200);
MIDI.sendNoteOff(note, 100, channel);
}
delay(200);
}"


But I'd like to be able to chose which note and channel I am sending to directly on the DAW, not from the code I'm uploading.

Any way I can do that ?

Many thanks :)
 
Assuming you only want to pass note data then you just need to merge the usbMIDI.read and MIDI.send demo code into a single sketch where the usbMIDI.read() data is passed to MIDI.sendNote commands.

I'm not going to cover the 'setHandle' method of reading usbMIDI; please read that section carefully!

(See "Receiving Messages with Read & Callback Functions" section of https://www.pjrc.com/teensy/td_midi.html)

Here is the usbMIDI.read example code with the stuff we won't need in red (which has to do with blinking the LED):
Code:
// USB MIDI receive example, Note on/off -> LED on/off
// contributed by Alessandro Fasan
[COLOR="#FF0000"]
int ledPin = 13;[/COLOR]

void OnNoteOn(byte channel, byte note, byte velocity)
{
[COLOR="#FF0000"]  digitalWrite(ledPin, HIGH);[/COLOR]
}

void OnNoteOff(byte channel, byte note, byte velocity)
{
[COLOR="#FF0000"]  digitalWrite(ledPin, LOW);[/COLOR]
}

void setup()
{
[COLOR="#FF0000"]  pinMode(ledPin, OUTPUT);[/COLOR]
  usbMIDI.setHandleNoteOff(OnNoteOff);
  usbMIDI.setHandleNoteOn(OnNoteOn) ;
[COLOR="#FF0000"]  digitalWrite(ledPin, HIGH);
  delay(1000);
  digitalWrite(ledPin, LOW);
  delay(1000);[/COLOR]
}

void loop()
{
  usbMIDI.read();
}
We just need to replace the digitalWrite() lines that were setting the LED to MIDI.send messages (and add an #includes MIDI.h so the library is there for us)

And here's the MIDI.send example code (with the stuff we will need to copy and adjust in green)
Code:
[COLOR="#009900"]#include <MIDI.h>[/COLOR]

const int channel= 1;

void setup() {
[COLOR="#009900"]  MIDI.begin();[/COLOR]
}

void loop() {
  int note;
  for (note=10; note <= 127; note++) {
[COLOR="#009900"]    MIDI.sendNoteOn(note, 100, channel);[/COLOR]
    delay(200);
[COLOR="#009900"]    MIDI.sendNoteOff(note, 100, channel);[/COLOR]
  }
  delay(2000);
}

So now we can pop these lines into the first code.
After that it's just a matter of replacing the arbitrary velocity values with those the callback functions extract from the data handle from the setup() code.
The channel and note variable names were the same in both examples so can be left as is.
Doing so gives me this UNTESTED code:
Code:
#include <MIDI.h>

void OnNoteOn(byte channel, byte note, byte velocity)
{
  MIDI.sendNoteOn(note, [COLOR="#0000FF"]velocity[/COLOR], channel);
}

void OnNoteOff(byte channel, byte note, byte velocity)
{
  MIDI.sendNoteOff(note, [COLOR="#0000FF"]velocity[/COLOR], channel);
}

void setup()
{
  MIDI.begin();
  usbMIDI.setHandleNoteOff(OnNoteOff);
  usbMIDI.setHandleNoteOn(OnNoteOn) ;
}

void loop()
{
  usbMIDI.read();
}

A delay() and Serial.print() instructions could be added to ensure the code is working before unleashing it on your MIDI hardware.
 
Last edited:
Hi, I also used a Teensy 3.6 before to send a torrent of MIDI data from my laptop to my keyboard, particularly black MIDIs :), to test how well my keyboard responds to a total of about more than 1 million notes.
I also used a similar approach and the code oddson posted will work.

Here's my code as a reference (note it's quite obsolete due to MIDI library update; I haven't tested it again)
Code:
#include <LiquidCrystalFast.h>
LiquidCrystalFast MC2004(2, 3, 4, 5, 6, 7, 8);
#include <MIDI.h>

#include <Audio.h>
AudioInputI2S       INPUT1;
AudioAnalyzePeak    METER_LEFT;
AudioAnalyzePeak    METER_RIGHT;
AudioSynthWaveform  BEEP;
AudioMixer4         LEFTMIX;
AudioMixer4         RIGHTMIX;
AudioOutputI2S      OUTPUT1;
AudioOutputUSB      OUTPUT2;
AudioConnection     A00(INPUT1, 0, METER_LEFT, 0);
AudioConnection     A01(INPUT1, 1, METER_RIGHT, 0);
AudioConnection     A02(INPUT1, 0, LEFTMIX, 0);
AudioConnection     A03(INPUT1, 1, RIGHTMIX, 0);
AudioConnection     A04(BEEP, 0, LEFTMIX, 1);
AudioConnection     A05(BEEP, 0, RIGHTMIX, 1);
AudioConnection     A06(LEFTMIX, 0, OUTPUT1, 0);
AudioConnection     A07(LEFTMIX, 0, OUTPUT2, 0);
AudioConnection     A08(RIGHTMIX, 0, OUTPUT1, 1);
AudioConnection     A09(RIGHTMIX, 0, OUTPUT2, 1);

elapsedMillis LCDt;
const float scale00dBV = 1;
const float scale03dBV = 0.707945784;
const float scale06dBV = 0.501187234;
const float scale09dBV = 0.354813389;
const float scale12dBV = 0.251188643;
const float scale15dBV = 0.177827941;
const float scale18dBV = 0.125892541;
const float scale21dBV = 0.089125094;
const float scale24dBV = 0.063095734;
const float scale27dBV = 0.044668359;
const float scale30dBV = 0.031622777;
const float scale33dBV = 0.022387211;
const float scale36dBV = 0.015848932;
const float scale39dBV = 0.011220185;
const float scale42dBV = 0.007943282;
const float scale45dBV = 0.005623413;
const float scale48dBV = 0.003981072;
const float scale51dBV = 0.002818383;
const float scale54dBV = 0.001995262;
const float scale57dBV = 0.001412538;
const float scale60dBV = 0.001000000;
float peakL = 1, peakR = 1, raw1, raw2;
byte metervalL, metervalR, r1, r2;

void setup() {
  MC2004.begin(20, 4);
  MC2004.clear();
  MC2004.print("DEO POGI ELECTRONICS");
  MC2004.print("Audio ADC/DAC to USB");
  MIDI.begin(MIDI_CHANNEL_OMNI);
  usbMIDI.setHandleNoteOff(OnNoteOff);
  usbMIDI.setHandleNoteOn(OnNoteOn);
  usbMIDI.setHandleControlChange(OnControlChange);
  usbMIDI.setHandleProgramChange(OnProgramChange);
  usbMIDI.setHandlePitchChange(OnPitchChange);
  AudioMemory(128);
  BEEP.begin(0, 1000, WAVEFORM_SQUARE);
}
void loop() {
  if(METER_LEFT.available()) raw1 = METER_LEFT.read();
  if(METER_RIGHT.available()) raw2 = METER_RIGHT.read();
  if(peakL < raw1) peakL = raw1;
  if(peakR < raw2) peakR = raw2;
  if(peakL >= scale00dBV) metervalL = 20;
  if(peakR >= scale00dBV) metervalR = 20;
  if(peakL < scale00dBV && peakL >= scale03dBV) metervalL = 19;
  if(peakR < scale00dBV && peakR >= scale03dBV) metervalR = 19;
  if(peakL < scale03dBV && peakL >= scale06dBV) metervalL = 18;
  if(peakR < scale03dBV && peakR >= scale06dBV) metervalR = 18;
  if(peakL < scale06dBV && peakL >= scale09dBV) metervalL = 17;
  if(peakR < scale06dBV && peakR >= scale09dBV) metervalR = 17;
  if(peakL < scale09dBV && peakL >= scale12dBV) metervalL = 16;
  if(peakR < scale09dBV && peakR >= scale12dBV) metervalR = 16;
  if(peakL < scale12dBV && peakL >= scale15dBV) metervalL = 15;
  if(peakR < scale12dBV && peakR >= scale15dBV) metervalR = 15;
  if(peakL < scale15dBV && peakL >= scale18dBV) metervalL = 14;
  if(peakR < scale15dBV && peakR >= scale18dBV) metervalR = 14;
  if(peakL < scale18dBV && peakL >= scale21dBV) metervalL = 13;
  if(peakR < scale18dBV && peakR >= scale21dBV) metervalR = 13;
  if(peakL < scale21dBV && peakL >= scale24dBV) metervalL = 12;
  if(peakR < scale21dBV && peakR >= scale24dBV) metervalR = 12;
  if(peakL < scale24dBV && peakL >= scale27dBV) metervalL = 11;
  if(peakR < scale24dBV && peakR >= scale27dBV) metervalR = 11;
  if(peakL < scale27dBV && peakL >= scale30dBV) metervalL = 10;
  if(peakR < scale27dBV && peakR >= scale30dBV) metervalR = 10;
  if(peakL < scale30dBV && peakL >= scale33dBV) metervalL = 9;
  if(peakR < scale30dBV && peakR >= scale33dBV) metervalR = 9;
  if(peakL < scale33dBV && peakL >= scale36dBV) metervalL = 8;
  if(peakR < scale33dBV && peakR >= scale36dBV) metervalR = 8;
  if(peakL < scale36dBV && peakL >= scale39dBV) metervalL = 7;
  if(peakR < scale36dBV && peakR >= scale39dBV) metervalR = 7;
  if(peakL < scale39dBV && peakL >= scale42dBV) metervalL = 6;
  if(peakR < scale39dBV && peakR >= scale42dBV) metervalR = 6;
  if(peakL < scale42dBV && peakL >= scale45dBV) metervalL = 5;
  if(peakR < scale42dBV && peakR >= scale45dBV) metervalR = 5;
  if(peakL < scale45dBV && peakL >= scale48dBV) metervalL = 4;
  if(peakR < scale45dBV && peakR >= scale48dBV) metervalR = 4;
  if(peakL < scale48dBV && peakL >= scale51dBV) metervalL = 3;
  if(peakR < scale48dBV && peakR >= scale51dBV) metervalR = 3;
  if(peakL < scale51dBV && peakL >= scale54dBV) metervalL = 2;
  if(peakR < scale51dBV && peakR >= scale54dBV) metervalR = 2;
  if(peakL < scale54dBV && peakL >= scale57dBV) metervalL = 1;
  if(peakR < scale54dBV && peakR >= scale57dBV) metervalR = 1;
  if(peakL < scale57dBV && peakL >= scale60dBV) metervalL = 0;
  if(peakR < scale57dBV && peakR >= scale60dBV) metervalR = 0;
  if(LCDt >= 50) {
    LCDt = 0;
    MC2004.setCursor(0, 2);
    r1 = 20 - metervalL;
    r2 = 20 - metervalR;
    for(byte a = metervalL; a > 0; a--) {
      MC2004.write(0xFF);
    }
    for(byte a = r1; a > 0; a--) {
      MC2004.write(0x20);
    }
    MC2004.setCursor(0, 3);
    for(byte a = metervalR; a > 0; a--) {
      MC2004.write(0xFF);
    }
    for(byte a = r2; a > 0; a--) {
      MC2004.write(0x20);
    }
    peakL *= scale03dBV;
    peakR *= scale03dBV;
  }
  if(MIDI.read()) {
    byte type = MIDI.getType();
    byte note, velocity, channel, control, value, program, d1, d2;
    int d3, pitch;
    switch(type) {
      case NoteOff:
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        usbMIDI.sendNoteOff(note, velocity, channel);
      break;
      case NoteOn:
        note = MIDI.getData1();
        velocity = MIDI.getData2();
        channel = MIDI.getChannel();
        usbMIDI.sendNoteOn(note, velocity, channel);
      break;
      case ControlChange:
        control = MIDI.getData1();
        value = MIDI.getData2();
        channel = MIDI.getChannel();
        usbMIDI.sendControlChange(control, value, channel);
      break;
      case ProgramChange:
        program = MIDI.getData1();
        channel = MIDI.getChannel();
        usbMIDI.sendProgramChange(program, channel);
      break;
      case PitchBend:
        d1 = MIDI.getData1();
        d2 = MIDI.getData2();
        d3 = d2 << 9;
        pitch = (d3 >> 2) + d1;
        channel = MIDI.getChannel();
        usbMIDI.sendPitchBend(pitch, channel);
      break;
      default:
      break;
    }
  }
  usbMIDI.read();
  //noteCopier();
}
void OnNoteOff(byte channel, byte note, byte velocity) {
  MIDI.sendNoteOff(note, velocity, channel);
}
void OnNoteOn(byte channel, byte note, byte velocity) {
  MIDI.sendNoteOn(note, velocity, channel);
}
void OnControlChange(byte channel, byte control, byte value) {
  MIDI.sendControlChange(control, value, channel);
}
void OnProgramChange(byte channel, byte program) {
  MIDI.sendProgramChange(program, channel);
}
void OnPitchChange(byte channel, int pitch) {
  pitch += 8192;
  MIDI.sendPitchBend(pitch, channel);
}
void noteCopier() {
  while(!Serial);
  delay(1000);
  for(byte reps = 0; reps <= 10; reps++) {
    BEEP.amplitude(0.0625);
    delay(50);
    BEEP.amplitude(0);
    delay(50);
  }
  delay(1000);
  for(byte note = 36; note <= 96; note += 3) {
    MIDI.sendNoteOn(note, 127, 1);
    delay(9500);
    MIDI.sendNoteOff(note, 127, 1);
    delay(500);
    MIDI.sendNoteOn(note, 127, 1);
    delay(9500);
    MIDI.sendNoteOff(note, 127, 1);
    delay(500);
    MIDI.sendNoteOn(note, 127, 1);
    delay(9500);
    MIDI.sendNoteOff(note, 127, 1);
    delay(500);
    BEEP.amplitude(0.0625);
    delay(50);
    BEEP.amplitude(0);
    delay(500);
  }
  for(byte reps = 0; reps <= 10; reps++) {
    BEEP.amplitude(0.0625);
    delay(50);
    BEEP.amplitude(0);
    delay(50);
  }
  while(1);
}
 
Code:
#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

void setup(){

  MIDI.begin(MIDI_CHANNEL_OMNI); // read all channels
  usbMIDI.setHandleNoteOff(OnNoteOff);
  usbMIDI.setHandleNoteOn(OnNoteOn) ;
}

void loop()
{
  usbMIDI.read();
}

void OnNoteOn(byte channel, byte note, byte velocity)
{
  MIDI.sendNoteOn(note, velocity, channel);
  serialNotePrint(true, note, velocity, channel);
}

void OnNoteOff(byte channel, byte note, byte velocity)
{
  MIDI.sendNoteOff(note, velocity, channel);
  serialNotePrint(false, note, velocity, channel);
}


void serialNotePrint(boolean On, byte note, byte velocity, byte channel){  
  if (On){
    Serial.print("Note On, ch=");
  }else {
    Serial.print("Note Off, ch="); 
  }
  Serial.print(channel, DEC);
  Serial.print(", note=");
  Serial.print(note, DEC);
  Serial.print(", velocity=");
  Serial.print(velocity, DEC);
  Serial.println();
}
Here's code for the less ancient versions of the MIDI library where you have to initialize the type of MIDI connection you want to make.

And I added a serialNotePrint() function to print to the data to the serial monitor so I can be fairly sure it works without having MIDI hardware set up.
 
Last edited:
Hey everyone ! Thanks a lot for helping me out on this :)

It works perfectly, I've managed to sequence my drum machine using ableton !!

I think I understand how the code works as well so it's great I've learned something haha
 
This only does note on/off.... you can extend to the other main types but sysex and realtime midi are tricky.
I think I understand how the code works as well
Most of the code is simple enough; it's understanding how 'setHandle...' commands make an object that is updated by the usbMIDI.read() command in the main loop.

The alternative is to use getType and getData commands and a generic MIDI.send which would allow handling standard midi types with the same code... but type has to be extracted and bit shifted as the numbering of types is different in the two libraries.
 
Status
Not open for further replies.
Back
Top