midicontroller

hi,
i am very new to arduino. sort of experienced in builiding of analog curcuitry and own musicinstruments.
what i want to do is the following:
the arduino shall read a lightresistor and send pitchbend for a finegrained midicontroller. while searching i found a piece of code which does this.

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

#include “MIDI.h”
int sensorPin = 0; /i added this for my sensor
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 = 880;

// 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*=values[i+1];*
_ sum+=values*;_
_
}_
_
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, 8192);
midi_pitch_bend(value, MIDI_CH);
_
// too much messages worsen things,_
_
// it depends also on the midi implementation on the synth*_
* delay(1);*
* }*
}
however this code reads only one sensor and is not yet full understandable for me. by trial and error i managed to add the information about which input and learned about the right mapping for my device.
it is from the bottom of this page
arduino.cc/cgi-bin/yabb2/YaBB.pl?action=print;num=1265084001
i need now to learn how to integrate more sensors/functions.
the second one shall be read another fotoresistor that is next to the tempo led of a digital audiodelay. calculate the tempo and send midiclock. maybe that is going to be a very complicated thing so an alternaternive would just add another input which sends a given controller besides pitchbend.
what would be the best way to get on the right track?
i tried to analyse the code but at this point my knowledge is not enough.
so i would be thankful for some help.

Hi, reading a second sensor would basically consist in replicating all the global data structures and instructions included in the loop() function, specifying a different analog input port and a different midi message. You could go with some like a copy and paste way, but it would be better reorganizing the code in a more organic way, for example with parametrized functions. That's missing from my code because it is an example, not a complete program.

int sensorPin = 0;

is pointless unless you use that variable elsewhere in the code.

Maybe you wanted to add something like

values[OVERSAMPLE-1]=analogRead(sensorPin);

the program behavior wouldn't change however, only a readability thing.

I think the led/fotoresistor idea is a bit awkward for several reasons, you could check if there is some alternative way to do it. Is your digital delay capable of midi in or out? If so you could try to see if it's capable of syncing some midi clock in or out with the rest of the gear. Which specific model of delay are you using?

hi, thanks for the reply. it is some boss delay and a very old boomerang loopsampler. they have no midiout. i read about the thing with the led in some posting on the pd list i think. actually right there must be a more direct way. i could find the leds on the printboard an built some dc output from that and connect some relay or stuff to it. or...can the arduino work with an external current? the ground is connected via dc supply. in pd i would know how to generate the patch for it but it should work independent from the computer. i tried to "merge" the code with some other example in which the arduino reads 6 sensors to midiout. as is say at this point it is still confusing. in the second example it worked without #include "MIDI.h" so i understand that pitchbend is a different type of message. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1165833586 what is "i" in the loopfunction? where is the midichannel set? where would pitchbend message and send its value go in?

it is some boss delay and a very old boomerang loopsampler. they have no midiout.

Sorry, I don't get what is hooked to what. May you explain better how things should be connected via MIDI?

i could find the leds on the printboard an built some dc output from that and connect some relay or stuff to it

Yes, using the led power would be a little more responsive and robust than an opto solution, assuming that you'll have to drill the delay box. You'll have to connect the led power to an analog input of Arduino. I think you should use both poles, and check before hooking not to trespass 5V. Anyway I'm not that expert in hw, better you ask around.

i tried to "merge" the code with some other example in which the arduino reads 6 sensors to midiout. as is say at this point it is still confusing. in the second example it worked without #include "MIDI.h" so i understand that pitchbend is a different type of message. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1165833586

I think you should make a clear statement about your project requirements. Then you could ask for how to implement the functions you need.

what is "i" in the loopfunction?

It's a variable used as an index to access each element of the last read values array.

where is the midichannel set?

const byte MIDI_CH = 1;

where would pitchbend message and send its value go in?

Now, that's exactly what I'd like to know..

both devices, delay or/and loop sampler should send their tempo (loopstart) through the arduino as midiclock note 248 to f.e a drum synthesizer. i built anyhow other cases than the factory ones. so is no problem to access the print board. sorry if i make myself not clear enough. the idea of the project is to have this three functions in one sketch: analog input 0-5, midiout 1. send pitchbend 2. send other midicontrollers cc 3. get the tempo of one of the devices above one at a time and generate midiclock. possibly switchable between both sources.

Here, this is the code to get midiclock from hardware.

From http://www.midi.org/techspecs/midimessages.php 11111000: Timing Clock. Sent 24 times per quarter note when synchronization is required (see text).

That means - sampling the blinking led - compute an interval with the previous sample - update the frequency of a simulated timer (you cannot use the internal watchdog because of its insufficient resolution) - fire a timing clock event each time the internal clock hits the bpm/24

The loop must be kept tight to get a good precision. I didn't tested it with a true led, I don't know if there will be the need of a resistor or capacitor because the analog inputs are high impedance and noisy.

You must configure the maximum voltage you'll read from wires (likely 2V). You can change a divider factor which defaults to one blink per bar.

//////////////////////////////////////////////
// hw synced midi clock generator
//////////////////////////////////////////////

// which input port is connected to the led power supply
const int ANALOG_INPUT_PIN = 0;      

// tension used to power the led
const double NOMINAL_VOLTAGE = 2;      
const int FULL_SCALE_VALUE = 1023 * NOMINAL_VOLTAGE / 5;      

// threshold, half the voltage
const int HALF_SCALE_VALUE = FULL_SCALE_VALUE / 2;      

// assuming the led will flash on the stomp-box on every bar at 4/4
// i.e. at 120bpm will flash every 2 seconds
// if you wanna change the unit of measure then change LOOP_QUARTERS accordingly
const int LOOP_QUARTERS = 4;      

// the midi clock message
const byte MIDI_CLOCK = 0xf8;      

// previous state of input led
boolean last_state;

// time stamp of the last detected beat
unsigned long last_beat;

// µs to wait before next midiclock
unsigned long interval;

// event to check for
unsigned long next_midiclock;

void setup()
{
    Serial.begin(31250);
    last_state=false;
    last_beat=micros();
    next_midiclock=0;
}

// if you need to add stuff inside the cycle you'll have to make sure to keep its duration 
// as short as possible to get a reasonable steadiness
// example: at 120bpm = 48ticks/s = one tick every 20.83ms
// if you want a 5% of precision you must stay within 1.04ms
void loop()
{
    int value;
    boolean led_state;
    unsigned long time_stamp;
    unsigned long beat_duration;
    double bpm;
  
    // needed in several computations
    // (every 70 minutes a hiccup, read specs)
    time_stamp = micros();

    // read tension
    value = analogRead(ANALOG_INPUT_PIN);

    // this threshold will discrminate the on/off state
    led_state = value > HALF_SCALE_VALUE;
    
    // if a beat is detected
    if (led_state && !last_state) {
        // in µs
        beat_duration = (time_stamp - last_beat);
        last_beat = time_stamp;        

        // from µs to bpm
        bpm = LOOP_QUARTERS * 1000000 * 60 / beat_duration; 

        // computes next frame in µs
        interval = 1000000 / (bpm / 60 * 24);
        
        // force a fire on beat detection
        // cures also micros() wrap-arounds 
        next_midiclock = time_stamp;
    }
    
    last_state = led_state;

    // if limit is reached
    if (time_stamp >= next_midiclock) {
        // fire the midi clock
        Serial.print(MIDI_CLOCK, BYTE);
        
        // recomputes next frame
        next_midiclock = time_stamp + interval;
    } 
}