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
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() {
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);

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