Sunday, January 24, 2010

Marmonizer, v1

One of the things I've wanted to build for a long time is, for lack of a better term, a MIDI harmonizer. It would have:
  • A MIDI in
  • A MIDI out
  • Some number of controls, e.g. knobs, sliders, control surfaces, and inputs for foot controls
The idea is that any MIDI data presented to the input would be transformed by algorithms running on the box, producing some other set of MIDI output. A performer would be able to control the parameters of these transformations using the controls. Also, it would be possible to configure the box so that input parameters also affect the output in non-obvious ways.

The simplest application I can think of for such a device is a simple MIDI transposer, which is what I put together tonight. The breadboard for this experiment has a single slide potentiometer which controls the amount of transposition. If the pot is centered, no transposition is performed. At full travel one direction, the pitch is transposed up 12 semitones (one octave), and at the other end, the pitch is transposed down 12 semitones. Here's the sketch. It's based on the very excellent MidiDuino Library from Ruin & Wesen.

/**

The Marmonizer

The Marmonizer is a MIDI harmonizer. It takes MIDI data on its input port and
sends harmonized data on its output port. The types of harmonizations will
eventually be user-programmable and extremely flexible.

Version 1:

To prove some basic assumptions, the very first version is a simple MIDI transposer.
The input note is transposed up or down, and the amount of transposition is
controlled by a voltage applied to analog input 0, e.g. with a potentiometer.

This proves:
- That we can do the transposition with reasonable latency
- That we've got the Miduino library working properly

Note: this will probably leave dangling notes if the transposition is
changed between a note on and the corresponding note off. The final
code will have to account for user knob-twisting while playing, and
make sure it turns off the right notes. Probably some sort of a map
that relates a received note to all the note on messages it spawned.

Gordon Good (velo27 <at> yahoo <dot> com)
Jan 24, 2010
*/

#include <MidiUart.h>
#include <Midi.h>
MidiClass Midi;

int trPotPin = 0; // Analog pin for reading the transposition potentiometer
int ledPin = 13; // LED pin to blink for debugging

int transposition = 0; // number of semitones to transpose (negative = transpose down)

void noteOnCallback(byte *msg) { // or is it uint8_t?
digitalWrite(ledPin, HIGH);
MidiUart.sendNoteOn(MIDI_VOICE_CHANNEL(msg[0]), msg[1] + transposition, msg[2]);
}

void noteOffCallback(byte *msg) {
digitalWrite(ledPin, LOW);
MidiUart.sendNoteOff(MIDI_VOICE_CHANNEL(msg[0]), msg[1] + transposition, msg[2]);
}

void continuousControllerCallback(byte *msg) {

}

void afterTouchCallback(byte *msg) {

}

void channelPressureCallback(byte *msg) {

}

void programChangeCallback(byte *msg) {

}

void pitchWheelCallback(byte *msg) {

}

void setup() {
MidiUart.init();
Midi.setOnNoteOnCallback(noteOnCallback);
Midi.setOnNoteOffCallback(noteOffCallback);
Midi.setOnControlChangeCallback(continuousControllerCallback);
Midi.setOnAfterTouchCallback(afterTouchCallback);
Midi.setOnChannelPressureCallback(channelPressureCallback);
Midi.setOnProgramChangeCallback(programChangeCallback);
Midi.setOnPitchWheelCallback(pitchWheelCallback);
pinMode(trPotPin, INPUT);
digitalWrite(trPotPin, HIGH);
}

void loop() {
while (MidiUart.avail()) {
// Read the transposition pot, and map the value to a + or - one octave transposition
transposition = map(analogRead(trPotPin), 0, 1023, -12, 12);
Midi.handleByte(MidiUart.getc());
}
}


There are some stubs in there for passing through or acting on most of the other MIDI data types. They're not ever executed in this sketch.

Also, I built the MIDI interface detailed here: MIDI Shield. For now, I've got everything on a breadboard, but I will eventually make a real Arduino shield for it, maybe using one of the Adafruit Protoshields I have on order.

In the future, I'm planning to:
  • Write more interesting transformation algorithms, including complex harmonizations.
  • Allow the parameters of the harmonization to be controlled by the performer using knobs, sliders, foot pedals, randomness, etc.
  • Allow the parameters of the harmonization to be controlled by input parameters, e.g. note on velocity can select a different chord voicing.
  • Allow users to create new combinations of controller/input assignments, and save those as patches that can be recalled easily.
Any other ideas out there?

No comments:

Post a Comment