MIDI lib code help

I’ve got an IR distance sensor and a female MIDI port on my Arduino. A MIDI cable connects my Arduino to my Nord3. I’ve been able to play notes via data coming from the IR sensor (waving my hand in front of it) without a problem, but I can’t figure out how to, instead, make it control my synth’s filter (MIDI CC 74).

I have the MIDI library installed, but can’t quite figure out the code for what I want to do. I think I have to incorporate something like this:

void MIDI_Class::sendControlChange (byte ControlNumber, byte ControlValue, byte Channel)

…but I don’t know how to do it. (don’t quite understand the library/class syntax yet).

Here’s what I’ve got so far. Any help would be appreciated!

#include <MIDI.h>

/*
Take IR distance sensor input and send MIDI CC data out to synth
*/

int sensorPin = 2; // IR sensor
int sensorValue = 0;

void setup() {
Serial.begin(31250);
}
void loop()
{
sensorValue = analogRead(sensorPin);
sensorValue = map(sensorValue, 0, 600, 0, 127);

// code here to send sensorValue data out MIDI port,
// assigned to MIDI CC 74 (to control filter on synth)

delay(100);
}

I'm assuming you're using the library from the playground.

That MIDI library sets the serial rate so replace Serial.begin with

MIDI.begin();
MIDI.setInputChannel(OMNI);//set input if used

The MIDI.send function is the only one you need to use.

To send CC 74 data

MIDI.send(CC,74,VALUE,CHANNEL);

Look in the MIDI.h for other defined data types because the data type is offset from 0x80 and not the actual standard MIDI value.

Beyond that it would help to refine the code to thin the data and not flood the port. The delay works fine for now but it's still sending an enormous amount of data if it will be recorded with a sequencer.

Thank you. It works! ;D

Look in the MIDI.h for other defined data types because the data type is offset from 0x80 and not the actual standard MIDI value.

I am having trouble figuring out this MIDI documentation though. I don't know how I would have derived the MIDI.send code if you didn't tell me. I only know csound and MATLAB... :P Is there a better reference doc that explains how to use the MIDI functions?

Usually there is some basic example library code if you goto the file->examples-> from the Arduino IDE. Then the .h file will give an overview of the functions and you go through the .cpp file to figure out exactly what they do.

When you write in the Arduino language you are actually programming in C++, an object oriented language.
Its syntax can be quite quirky compared to Basic for example, but the developers of the Arduino system needed a down-to-the-iron compiled language to fit in such a tight environment (16000 bytes).
They made however also a valuable effort to simplify the life in the building process, hiding some tedious details in the IDE.
OOP is built on the definition of classes and instances of classes.
You can think of a class as a cookie mould, and the instances (objects) as just the cookies.
Classes define properties (variables) and methods (functions) that you can access via the “.” operator on the objects originated from the classes.
For example: you could create an instance of the cookie_class (a class name) called cocoa_cookie (a variable name for an object) and then operate on that object thru the properties and methods which were defined in the originating class.

// an instance, object creation
cookies_class cocoa_cookie;

// access to a string property
cocoa_cookie.special_ingredient=“Cocoa”;

// access to a boolean property
cocoa_cookie.powdered_sugar_topping=true;

// access to the method cook (minutes, celsius)
cocoa_cookie.cook(20, 180);

// access to the method eatme(who)
cocoa_cookie.eatme(“Cookie Monster”);

Actually, much of the code you see in examples uses already existing instances and almost never creates classes, but you could do it in the .pde if you liked.
Libraries use much more OOP to “wrap” methods around specialized themes.
As how the libraries in Arduino are made, usually the library’s developer has already created an instance of the object you need to cope with. In case of the midi library you have the instance “MIDI”, so you can invoke MIDI.sendNoteOn(note, vel, chan); method to send a noteon message.
Strangely enough that library lacks a method to wrap the pitch_bend message, which with Arduino would be very appropriate if you want to thereminize a synth.
I made this little program to implement it, if you want to check it out then:

  • set your pitch bend limits on the synth to -24/+24 (you’ll have 4 octaves)
  • adjust if necessary the MAX_SENSOR_VALUE const
  • adjust the smooth factor OVERSAMPLE (to reduce sensor noise and micro movements)

Regards

PS: while testing, if you ever notice squeals, sparks, smoke or bad smell coming from the synth, then leave the room really really fast!

//////////////////////////////////////////////
// a midi pitch bend implementation
// with noise smoothing
//////////////////////////////////////////////

#include "MIDI.h"

const byte MIDI_CH = 1;      

// how many sensor samples are taken to compute the average
// the accelerometer is quite noisy
const byte OVERSAMPLE = 50;
const byte PITCH_BEND = 6;      

// the max value you can expect from the sensor you are using
// it depends on many factors, which sensor, which tension applied, 
// which reference configuration on Arduino, etc..
const int MAX_SENSOR_VALUE = 600;      

// mobile average samples array 
int values[OVERSAMPLE];
int last_average=0;

// the missing function in midi library
void midi_pitch_bend(int value, byte channel) {
    byte lsb;
    byte msb;
    
    lsb = value & 0x7f; 
    msb = value >> 7; 
    MIDI.send(PITCH_BEND, lsb, msb, channel);
}

void setup()
{
    const int n=41;

    // If you wanted a slightly better resolution from the sensor, you might connect
    // the 3.3v pin to aref pin and uncomment the following instruction. 
    // but read the warning here before hacking: arduino.cc/en/Reference/AnalogReference
    // analogReference(EXTERNAL);
    
    MIDI.begin();

    // a wannabe..
    MIDI.sendNoteOn(n, 127, MIDI_CH);  
    MIDI.sendNoteOn(n + 7, 127, MIDI_CH);  
    MIDI.sendNoteOn(n + 12, 127, MIDI_CH);  
    MIDI.sendNoteOn(n + 16, 127, MIDI_CH);
    MIDI.sendNoteOn(n + 19, 127, MIDI_CH);
    MIDI.sendNoteOn(n + 24, 127, MIDI_CH);
    delay(2500);            
    MIDI.sendNoteOff(n, 0, MIDI_CH); 
    MIDI.sendNoteOff(n + 7, 0, MIDI_CH);
    MIDI.sendNoteOff(n + 12, 0, MIDI_CH);   
    MIDI.sendNoteOff(n + 16, 0, MIDI_CH);   
    MIDI.sendNoteOff(n + 19, 0, MIDI_CH);   
    MIDI.sendNoteOff(n + 24, 0, MIDI_CH);   
}

void loop()
{
    int value;
    int i;
    long sum;
    int average;
    int delta;
 
    sum=0;
    // this array works as FIFO 
    // shift all values one position to the left, making room for the new reading,
    // in the meanwhile it sums for the average
    for (i=0; i < OVERSAMPLE-1; i++) {
        values[i]=values[i+1];
        sum+=values[i];
    }
    values[OVERSAMPLE-1]=analogRead(0);
    sum+=values[OVERSAMPLE-1];
    average=sum / OVERSAMPLE;

    // compute a trend compared to the previous
    delta=average - last_average;

    // save the current for the next iteration
    last_average=average;

    // try to limit flooding the midi channel
    if (abs(delta) > 0) {
        // note: you have to scale to 16384 because pitch bend messages
        // have 14 bits of data instead of 7 like most midi messages
        value=map(average, 0, MAX_SENSOR_VALUE, 0, 16384);
        midi_pitch_bend(value, MIDI_CH);
        // too much messages worsen things, 
        // it depends also on the midi implementation on the synth 
        delay(1);
    }
}