Crumar D9U: Electro 2 Sketch (Part 5)

Finally, after all of the testing, the first Crumar D9U Drawbar Controller application sketch! The sketch below changes the drawbar settings for the Nord Electro 2. The Arduino on board the D9U sends a complete snapshot of all nine drawbar settings to the Electro 2 at start-up and whenever the tactile switch is depressed. Thereafter, it sends a MIDI message to the Electro 2 whenever a slider (drawbar) is changed.

The sketch drives only the Electro 2 upper drawbars. If you need the lower drawbars, too, you can follow Crumar’s example sketch and extend my sketch.

The sketch does not use the Arduino MIDI library because we only need to send simple MIDI continuous control (CC) messages. It’s easy enough to write the necessary code ourselves.

I encountered an Arduino compiler toolchain issue while developing the sketch. I wasn’t able to initialize snapCount in the setup() function. I’ll work around this issue in future sketches and you should back-port the fix. It’s not the first time that I’ve run into an Arduino toolchain bug…

The program logic is quite simple. There are three helper functions: sendNoteOn(), sendNoteOff(), and sendMidiCC(). The sketch uses only the third function which sends a MIDI continuous control message through the Serial1 port, i.e., the Arduino Leonardo TX pin.

The setup() function initializes the digital pins and global variables, and calls sendSnapshot() to scan the analog pins, sending a MIDI CC message for each drawbar. The idea is to sync the Electro 2 with the D9U when the D9U is turned on. You should select an organ voice on the Electro 2 before turning on the D9U in order to take advantage of this feature.

The loop() function goes round and round. If the tactile switch is depressed, the sketch takes a snapshot of the analog pins (sliders) and sends a MIDI CC message for each slider (drawbar). The variable snapCount debounces the tactile switch input, preventing a flood of MIDI CC messages to MIDI OUT and the Electro 2.

After checking the tactile switch, the loop() function delays for a short time and then calls checkSliders(). The function checkSliders() keeps a copy of the most recent slider values. When it detects a change, it saves the new slider value and sends a MIDI CC message with the new value. The Electro 2 accepts drawbar values over the range from 0 to 127.

It’s rather gratifying to attach the Crumar D9U to the Electro 2 and watch the Electro’s drawbar status lights change in sync with the D9U drawbars. Cool. Fun to play, too.

If you have a Nord Electro 2 and a D9U, enjoy the sketch!

Copyright © 2018 Paul J. Drongowski

/*
 * Electro2.ino: Crumar D9U sketch for Nord Electro 2
 */

/*
 * Author:  P.J. Drongowski
 * Address: http://sandsoftwaresound.net/
 * Date:    12 December 2018
 * Version: 1.0
 *
 * A simple sketch to control the Nord Electro 2 with the
 * Crumar D9U Drawbar Controller. This sketch controls
 * the upper drawbars, but could be extended to control
 * the lower drawbars. See the Crumar sketch for
 * inspiration!
 *
 * We assume a direct 5-pin MIDI connection from the
 * D9U to the Electro 2. Since direct MIDI is so simple,
 * the sketch does not use the Arduino MIDI library.
 * MIDI bytes are sent using Serial1.write().
 *
 * Send on MIDI CC messages on MIDI channel 0.
 *
 * Electro 2 MIDI continuous controllers (CC) are:
 *    Parameter       Upper CC#  Lower CC#
 *    --------------  ---------  ---------
 *    16' drawbar         16        70
 *    5 1/3' drawbar      17        71
 *    8' drawbar          18        72
 *    4' drawbar          19        73
 *    2 2/3' drawbar      20        74
 *    2' drawbar          21        75
 *    1 3/5' drawbar      22        76
 *    1 1/3' drawbar      23        77
 *    1' drawbar          24        78

 */

// Pin definitions
#define LED_RED    15
#define LED_GREEN  16
#define BUTTON     5

// Analog pin map
#define NUMBER_OF_SLIDERS 9
int AnalogPinMap[NUMBER_OF_SLIDERS] = {
  A0, A1, A2, A3, A6, A7, A8, A9, A10
} ;

// Drawbar to MIDI CC# map
int MidiCCMap[NUMBER_OF_SLIDERS] = {
  16, 17, 18, 19, 20, 21, 22, 23, 24
} ;

// Global variables
int sliders[NUMBER_OF_SLIDERS] ;
#define SNAP_COUNT  (200)
int snapCount = SNAP_COUNT ;

// MIDI channel
#define CHANNEL 0

// Bias offset for incoming slider values [unused]
#define BIAS 32

void sendNoteOn(byte pitch, byte velocity) {
  Serial1.write(0x90 | CHANNEL) ;
  Serial1.write(pitch) ;
  Serial1.write(velocity) ;
}

void sendNoteOff(byte pitch) {
  Serial1.write(0x80 | CHANNEL) ;
  Serial1.write(pitch) ;
  Serial1.write(0) ;
}

void sendMidiCC(byte cc, byte value) {
  Serial1.write(0xB0 | CHANNEL) ;
  Serial1.write(cc) ;
  Serial1.write(value) ;
}

// Take a snapshot of the current slider state and
// send MIDI CC for all sliders. Electro 2 CC value range
// is 0 to 127.
void sendSnapshot() {
  int newValue = 0 ;
  for (int i = 0 ; i < NUMBER_OF_SLIDERS ; i++) {
    newValue = (analogRead(AnalogPinMap[i]) & 0x3FF) / 8 ;
    sliders[i] = newValue ;
    sendMidiCC(MidiCCMap[i], newValue) ;
  }
}

// Check the sliders for movement (changes). When a change
// is detected, send a MIDI CC message. Nord Electro CC
// values range from 0 to 127.
void checkSliders() {
  int newValue = 0 ;
  for (int i = 0 ; i < NUMBER_OF_SLIDERS ; i++) {
    newValue = (analogRead(AnalogPinMap[i]) & 0x3FF) / 8 ;
    if (sliders[i] != newValue) {
      sliders[i] = newValue ;
      // Send MIDI CC message when the value changes
      sendMidiCC(MidiCCMap[i], newValue) ;
    }
  }
}
 
void setup() {
  // Set up pins
  pinMode(BUTTON, INPUT_PULLUP) ;
  pinMode(LED_RED, OUTPUT) ;
  pinMode(LED_GREEN, OUTPUT) ;

  // Set up Serial1 for MIDI via TX and RX (31,250 baud)
  Serial1.begin(31250) ;

  // Initialize the button debounce count
  // Send an initial snapshot. This operation initializes
  // the current slider values, too.
  sendSnapshot() ;
}

void loop() {
  if ((digitalRead(BUTTON) == LOW) && (snapCount <= 0))
  {
    // Take and send a snapshot of the sliders
    sendSnapshot() ;
    snapCount = SNAP_COUNT ;
  } else {
    snapCount-- ;
  }

  delay(1) ;
  checkSliders() ;
}