Wednesday, December 23, 2009

Experiment 2 - Reading/Sending Expression Data

For my next experiment, I wanted to try reading some sort of analog device and using that value to control a MIDI expression paramter. None of my more interesting sensors have arrived yet (I ordered an Adafruit Sensor Pack), so I opted to just read the value of a potentiometer and use that to send MIDI volume controller information. This is a common way to get a standard synth patch to work with a wind controller like the Yamaha WX-7.

The circuit builds on the one in my previous post in which a pushbutton causes a MIDI note on value to be sent. To this I added a potentiometer. One side goes to +5V, the other side to ground, and the wiper to analog input #2 on the Arduino. In the photo, the pot is on the small breadboard to the right.

The code is below. There are two slightly interesting things:
  1. The analogRead() method will report values in the range 0-1023, but MIDI continuous controller values must be in the range 0 to 127. The Arduino library has a convenient map() method which handles this.
  2. If you simply read the pot and send a volume change message every time through the loop() method, you'll produce a lot of data. The code includes a check so that we only send a volume control message every VOLUME_SEND_INTERVAL milliseconds. I experimented a bit with the value, and 100 milliseconds is too coarse - on fast volume control changes you can hear "graininess."
Code:

#include "MIDI.h"

/*
Demonstrate how to read an analog input (a potentiometer in this case) and
use that data to send MIDI volume controller information.

Every time the pushbotton is pressed, a MIDI note on will be sent with
a noteOn velocity of 127, Then, as long as the button is held, volume
controller information will be sent - the value depends on the value
read from the pot.

As a visual aid, an LED connected to digital port 13 will light whenever
the pushbutton is pressed.

Circuit:

MIDI OUT to Arduino Serial pin 1
MIDI IN from Arduino Serial pin 0
Potentiometer: Vin, gnd to each side, wiper to analog pin 2

Digital pin 2 to a pushbutton switch, and to 5v through a 10k resistor
other leg of switch to 5v

*/

#define LED 13
#define BUTTON 2
#define VOLUME_POT 2 // Analog input 2 for volume pot
int MIDI_VOLUME_CONTROLLER = 7; // MIDI controller 7 = Volume
int VOLUME_SEND_INTERVAL = 10; // Only send volume data this often (in ms).

int buttonState = LOW;
int prevButtonState = LOW;
int note = 55;
int potVal = 0;

int lastVolumeSendTime = 0; // Last time we sent volume data

void setup() {
MIDI.begin(1);
pinMode(LED, OUTPUT);
pinMode(BUTTON, INPUT);
}

void loop() {
buttonState = digitalRead(BUTTON);
if (buttonState == HIGH) {
if (prevButtonState == LOW) {
prevButtonState = HIGH;
digitalWrite(LED, HIGH);
MIDI.sendNoteOn(note, 127, 1);
} else {
// Button still pressed - send volume controller info, but
// only sample it every VOLUME_SEND_INTERVAL milliseconds so
// we don't flood the MIDI bus.
if (millis() - lastVolumeSendTime > VOLUME_SEND_INTERVAL) {
lastVolumeSendTime = millis();
potVal = map(analogRead(VOLUME_POT), 0, 1023, 0, 127);
MIDI.sendControlChange(MIDI_VOLUME_CONTROLLER, potVal, 1);
}
}
} else if (buttonState == LOW) {
if (prevButtonState == HIGH) {
prevButtonState = LOW;
MIDI.sendNoteOff(note, 0, 1);
}
digitalWrite(LED, LOW);
}
}

No comments:

Post a Comment