Monday, January 25, 2010

Marmonizer, v2

Tonight I coded the Marmonizer v2. For those of you with some music theory background, this harmonizer adds notes below the played pitch that spell a major triad in second inversion (a "6/4" chord). The algorithm just takes the input MIDI note, and outputs on the MIDI out connector the original note plus two other notes; one 4 semitones down, and another 5 semitones down.

In the examples below, I am playing (in a very hacky fashion, since I have no sax chops) a Yamaha WX-7 wind controller.

When you play a scale with this harmonization, it sounds like this:








And when you fiddle with the slide potentiometer we built for transposition in Marmonizer v1, you get something like this:








Here's the sketch:



/**

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 2:

Version 2 builds on version 1, which was a simple MIDI transposer, and
implements a simple MIDI harmonizer. The harmonizarion ia simple; the
input note is the top voice of a triad in second inversion (e.g. if the
input note is E4, then the voices below are G3 and C4. For discussion of
what those note names mean, see http://en.wikipedia.org/wiki/C_%28musical_note%29
The transposition pot is retained.

Limitations: the algorithm always "maps down" so we may roll notes off the
deep end of the MIDI spec.

Gordon Good (velo27 yahoo com)
Jan 25, 2010
*/

#include <midiuart.h>
#include <midi.h>
MidiClass Midi;

#define HARM_NOTE_1_OFFSET -4
#define HARM_NOTE_2_OFFSET -9

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]);
MidiUart.sendNoteOn(MIDI_VOICE_CHANNEL(msg[0]), msg[1] + transposition + HARM_NOTE_1_OFFSET, msg[2]);
MidiUart.sendNoteOn(MIDI_VOICE_CHANNEL(msg[0]), msg[1] + transposition + HARM_NOTE_2_OFFSET, msg[2]);
}

void noteOffCallback(byte *msg) {
digitalWrite(ledPin, LOW);
MidiUart.sendNoteOff(MIDI_VOICE_CHANNEL(msg[0]), msg[1] + transposition, msg[2]);
MidiUart.sendNoteOff(MIDI_VOICE_CHANNEL(msg[0]), msg[1] + transposition + HARM_NOTE_1_OFFSET, msg[2]);
MidiUart.sendNoteOff(MIDI_VOICE_CHANNEL(msg[0]), msg[1] + transposition + HARM_NOTE_2_OFFSET, 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);
analogWrite(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());
}
}



In the spirit of Agile, I'm doing the minimal coding necessary to achieve a goal, so some of this might seem a bit silly to experienced programmers.

No comments:

Post a Comment