Arduino + MIDI Shield+Reason DAW

midi-07

My first effort in interfacing my new Arduino Uno with a MIDI destination. I’ve used the Spark Fun Electronics MIDI Shield attachment and sent the MIDI events to Propellerhead Software’s “Reason.” The MIDI library from FortySevenEffects is required to make this work. (Links were working as of 07/02/2016.)

I have hopes of interfacing one or both of my recently acquired Heathkit ET-3400 Microprocessor Trainers to my synth. The trick will be converting the eight parallel data lines in a D/A converter and send the output as a Control Voltage. The other option would be to “write” the NOTEON and NOTEOFF events on the ET-3400 and send those in binary to a parallel-to-serial shift register, then to a MIDI jack. But that introduces a whole ‘nother level of complexity. (And it has to be done in 512 bytes of RAM.)

The first three sequences were generated in Excel using RANDOM(48,72) to restrict the note range to two octaves. In “Reason” I assigned the note tracks to two instances of the NN-XT sampler using the Old Brass Ensemble preset.

The music is rather monotonous, unfortunately, but … baby steps! Be forewarned: several of the sections are highly dissonant. I love that stuff … at least in small doses. I’ve noted in the code those sections that remind me somewhat of music by Bela Bartok and William Schuman.

Download the file (if you’re into masochism). It’s 5 MB and runs 08:16 minutes.

The code is pretty straightforward, really: just two nested “for” loops for each pass through. There may be a more elegant way to code this, since I’m no C or C++ guru.

Needless to say, I can only send one NOTEON event at a time to my synth … so there’s that.

I’m trying to figure out how one would do polyphony on a large scale. Coding more than a brief passage could be a lot of calculating and debugging.

Here’s the source:

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

#define LED 13
// Uses the FortySevenEffects MIDI library; see link above.

MIDI_CREATE_DEFAULT_INSTANCE();

int listLength = 20;

// Two-dimensional array: four note sequences of twenty notes each

int theNotes[4][20] = { {64, 54, 69, 52, 62, 64, 49, 48, 70, 65, 53, 64, 71, 68, 70, 53, 49, 70, 70, 56},
  {60, 72, 68, 52, 48, 62, 58, 49, 48, 48, 65, 55, 69, 52, 63, 48, 67, 57, 65, 52},
  {71, 58, 65, 59, 62, 53, 60, 57, 71, 50, 59, 60, 50, 54, 69, 51, 59, 68, 67, 51},
  {60, 60, 60, 60, 65, 60, 60, 60, 62, 60, 60, 58, 60, 65, 66, 65, 60, 60, 66, 60}
};

// Same parameters for each sequence (for simplicity)

int velocities[20] = {60, 65, 70, 75, 80, 85, 90, 95, 75, 80, 85, 90, 95, 100, 105, 110, 90, 105, 120, 127};
int durations[20] = {25, 50, 75, 100, 125, 150, 175, 200, 250, 300, 350, 400, 450, 500, 600, 700, 800, 900, 1000, 1500};

void setup()
{
  pinMode(LED, OUTPUT);
  MIDI.begin(1);          // We don't read MIDI input. Channel 1 not actually used)
}

void loop() {

  int whichNotes = 0;
  int dex = 0;
  int note = 0;
  int velo = 0;
  int duration = 0;

  // INTRO

  for (dex = 0; dex < listLength; dex++) {
    note =  theNotes[3][dex];
    velo = velocities[dex];
    duration = durations[dex];

    MIDI.sendNoteOn(note - 5, velo, 1);
    MIDI.sendNoteOn(note, velo, 1);
    MIDI.sendNoteOn(note + 7, velo, 1);
    MIDI.sendNoteOn(note + 16, velo, 1);
    delay(duration);
    MIDI.sendNoteOff(note - 5, 0, 1);
    MIDI.sendNoteOff(note, 0, 1);
    MIDI.sendNoteOff(note + 7, 0, 1);
    MIDI.sendNoteOff(note + 16, 0, 1);
    delay(duration * 2 / 3);
  }
  delay(500);

  MIDI.sendNoteOn(48, 127, 1);
  MIDI.sendNoteOn(55, 127, 1);
  MIDI.sendNoteOn(64, 127, 1);
  MIDI.sendNoteOn(60, 127, 1);
  delay(2000);
  MIDI.sendNoteOff(48, 0, 1);
  MIDI.sendNoteOff(55, 0, 1);
  MIDI.sendNoteOff(64, 0, 1);
  MIDI.sendNoteOff(60, 0, 1);
  delay(1000);

  // Octaves

  for (whichNotes = 0; whichNotes < 4; whichNotes++) {
    for (dex = 0; dex < listLength; dex++) {

      note =  theNotes[whichNotes][dex];
      velo = velocities[dex];
      duration = durations[dex];

      MIDI.sendNoteOn(note - 12, velo, 1);
      MIDI.sendNoteOn(note, velo, 1);
      delay(duration);
      MIDI.sendNoteOff(note - 12, 0, 1);
      MIDI.sendNoteOff(note, 0, 1);
      delay(duration * 2 / 3);
    }
  }
  delay(1000);

  // Bartok-ian stacked fourths, one below root, one above.

  for (whichNotes = 0; whichNotes < 4; whichNotes++) {
    for (dex = 0; dex < listLength; dex++) {

      note =  theNotes[whichNotes][dex];
      velo = velocities[dex];
      duration = durations[dex];

      MIDI.sendNoteOn(note - 5, velo, 1);
      MIDI.sendNoteOn(note, velo, 1);
      MIDI.sendNoteOn(note + 5, velo, 1);
      delay(duration);
      MIDI.sendNoteOff(note - 5, 0, 1);
      MIDI.sendNoteOff(note, 0, 1);
      MIDI.sendNoteOff(note + 5, 0, 1);
      delay(duration * 2 / 3);
    }
  }
  delay(1000);

  // Bartok-ian stacked fifths, one below root, one above.

  for (whichNotes = 0; whichNotes < 4; whichNotes++) {
    for (dex = 0; dex < listLength; dex++) {

      note =  theNotes[whichNotes][dex];
      velo = velocities[dex];
      duration = durations[dex];

      MIDI.sendNoteOn(note - 7, velo, 1);
      MIDI.sendNoteOn(note, velo, 1);
      MIDI.sendNoteOn(note + 7, velo, 1);
      delay(duration);
      MIDI.sendNoteOff(note - 7, 0, 1);
      MIDI.sendNoteOff(note, 0, 1);
      MIDI.sendNoteOff(note + 7, 0, 1);
      delay(duration * 2 / 3);
    }
  }
  delay(1000);

  // Diminished fith + minor seventh (pretty nasty!)

  for (whichNotes = 0; whichNotes < 4; whichNotes++) {
    for (dex = 0; dex < listLength; dex++) {

      note =  theNotes[whichNotes][dex];
      velo = velocities[dex];
      duration = durations[dex];

      MIDI.sendNoteOn(note, velo, 1);
      MIDI.sendNoteOn(note + 6, velo, 1);
      MIDI.sendNoteOn(note + 10, velo, 1);
      MIDI.sendNoteOn(note + 12, velo, 1);
      delay(duration);
      MIDI.sendNoteOff(note, 0, 1);
      MIDI.sendNoteOff(note + 6, 0, 1);
      MIDI.sendNoteOff(note + 10, 0, 1);
      MIDI.sendNoteOff(note + 12, 0, 1);
      delay(duration * 2 / 3);
    }
  }
  delay(1000);

  // Root plus major seventh (sardonic).

  for (whichNotes = 0; whichNotes < 4; whichNotes++) {
    for (dex = 0; dex < listLength; dex++) {

      note =  theNotes[whichNotes][dex];
      velo = velocities[dex];
      duration = durations[dex];

      MIDI.sendNoteOn(note, velo, 1);
      MIDI.sendNoteOn(note + 11, velo, 1);
      delay(duration);
      MIDI.sendNoteOff(note, 0, 1);
      MIDI.sendNoteOff(note + 11, 0, 1);
      delay(duration * 2 / 3);
    }
  }
  delay(1000);

  // suggests William Schuman's Eighth Symphony, 1962
  // minor chord + major tenth (pretty aggressive)

  for (whichNotes = 0; whichNotes < 4; whichNotes++) {
    for (dex = 0; dex < listLength; dex++) {

      note =  theNotes[whichNotes][dex];
      velo = velocities[dex];
      duration = durations[dex];

      MIDI.sendNoteOn(note, velo, 1);
      MIDI.sendNoteOn(note + 3, velo, 1);
      MIDI.sendNoteOn(note + 7, velo, 1);
      MIDI.sendNoteOn(note + 16, velo, 1);
      delay(duration);
      MIDI.sendNoteOff(note, 0, 1);
      MIDI.sendNoteOff(note + 3, 0, 1);
      MIDI.sendNoteOff(note + 7, 0, 1);
      MIDI.sendNoteOff(note + 16, 0, 1);
      delay(duration * 2 / 3);
    }
  }
  delay(1000);

  // suggests William Schuman's Third Symphony, 1941
  // major chord, second inversion, plus the fifth

  for (whichNotes = 0; whichNotes < 4; whichNotes++) {
    for (dex = 0; dex < listLength; dex++) {

      note =  theNotes[whichNotes][dex];
      velo = velocities[dex];
      duration = durations[dex];

      MIDI.sendNoteOn(note - 5, velo, 1);
      MIDI.sendNoteOn(note, velo, 1);
      MIDI.sendNoteOn(note + 4, velo, 1);
      MIDI.sendNoteOn(note + 7, velo, 1);
      delay(duration);
      MIDI.sendNoteOff(note - 5, 0, 1);
      MIDI.sendNoteOff(note, 0, 1);
      MIDI.sendNoteOff(note + 4, 0, 1);
      MIDI.sendNoteOff(note + 7, 0, 1);
      delay(duration * 2 / 3);
    }
  }
  delay(1000);

  // second inversion, no third, plus fifth & tenth
  // the tenth kinda screams, depending on how you orchestrate it)

  for (whichNotes = 0; whichNotes < 4; whichNotes++) {
    for (dex = 0; dex < listLength; dex++) {

      note =  theNotes[whichNotes][dex];
      velo = velocities[dex];
      duration = durations[dex];

      MIDI.sendNoteOn(note - 5, velo, 1);
      MIDI.sendNoteOn(note, velo, 1);
      MIDI.sendNoteOn(note + 7, velo, 1);
      MIDI.sendNoteOn(note + 16, velo, 1);
      delay(duration);
      MIDI.sendNoteOff(note - 5, 0, 1);
      MIDI.sendNoteOff(note, 0, 1);
      MIDI.sendNoteOff(note + 7, 0, 1);
      MIDI.sendNoteOff(note + 16, 0, 1);
      delay(duration * 2 / 3);
    }
  }
  delay(1000);

  MIDI.sendNoteOn(48, 127, 1);
  MIDI.sendNoteOn(55, 127, 1);
  MIDI.sendNoteOn(64, 127, 1);
  MIDI.sendNoteOn(60, 127, 1);
  // you'd use a dimenuendo here in a DAW
  delay(10000);
  MIDI.sendNoteOff(48, 0, 1);
  MIDI.sendNoteOff(55, 0, 1);
  MIDI.sendNoteOff(64, 0, 1);
  MIDI.sendNoteOff(60, 0, 1);
  delay(1000);

}

  // and we're outta here (finally)

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.