A peek into MidiDuino
A peek into MidiDuino02.01.2009 18:39:52
Manufacturing is taking off in the Ruin & Wesen factory, after having finally sorted out the issue of solid, good-looking but inexpensive metal casings that can fit USB and 4 midi ports. But in between mill runs and soldering, I managed to squeeze a few hours into something that quite frankly has blown my mind. I have adapted the arduino environment to run with the MidiCommand and MonoJoystick. What this allows you to do is to use the Arduino editor and environment to write new firmwares for the MidiCommand. You plug the device in using USB or MIDI, and you can reflash it by just pressing a single button. Also, I wrote a host of libraries supporting the GUI (encoders, buttons, display), the MIDI stack (to receive or send MIDI messages), the MIDI clock (have sequencers running on the MidiCommand with internal or external sync), and of course EEPROM, USB, flash storage, graphical display, LEDs. So once you get your MidiCommand or MonoJoystick, you will be able to open the port of arduino, and be able to program away.
In order not to announce too much because the API is still evolving, let me just show you two example patches. The first one is a very simple patch that just sends CC messages when you turn the encoders:
CCEncoder encoders[NUM_ENCODERS] = { 2, 3, 4, 5, 6 };
EncoderPage page;
void handleGui() {
page.update();
}
void setup() {
INIT_PAGE(page, encoders, NUM_ENCODERS);
LCD.puts("P1 P2 P3 P4 ");
GUI.setLine(GUI.LINE2);
}
uint8_t cnt = 0;
void loop() {
page.handle();
for (uint8_t i; i < 4; i++) {
GUI.put_value(i, encoders[i].getValue());
}
}
and the second one is a more complicated 4-track polyrhythmic drum machine. You get 4 tracks that are set using the euclidean algorithm I documented a few weeks back: you input the number of pulses, the number of steps, and the offset from the start of the pattern, as well as the midi pitch to be output. Press the macro button, and it will start/stop. Turn the macro knob, and it will change the tempo:
TempoEncoder tempoEncoder;
class EuclidPage {
public:
EuclidDrumTrack track;
EncoderPage page;
RangeEncoder pulseEncoder;
RangeEncoder lengthEncoder;
RangeEncoder offsetEncoder;
RangeEncoder pitchEncoder;
EuclidPage() : track(0, 8), pulseEncoder(0, 32), lengthEncoder(1, 32),
offsetEncoder(0, 32), pitchEncoder(60, 100) {
page.encoders[0] = &pulseEncoder;
page.encoders[1] = &lengthEncoder;
page.encoders[2] = &offsetEncoder;
page.encoders[3] = &pitchEncoder;
lengthEncoder.setValue(8);
}
};
EuclidPage euclids[4];
EuclidPage *currentEuclid = &euclids[0];
void switchPage(uint8_t i) {
currentEuclid = &euclids[i];
GUI.setLine(GUI.LINE1);
GUI.put_value(0, i);
GUI.setLine(GUI.LINE2);
}
void handleGui() {
if (BUTTON_PRESSED(4))
MidiClock.pause();
tempoEncoder.update(&GUI.Encoders.encoders[4]);
currentEuclid->page.update();
for (uint8_t i = 0; i < 4; i++) {
if (BUTTON_DOWN(GUI.Buttons.SHIFT) && BUTTON_PRESSED(i)) {
switchPage(i);
}
}
}
uint8_t cnt = 0;
void on16Callback() {
for (uint8_t i = 0; i < 4; i++) {
euclids[i].track.playHit(MidiClock.div16th_counter,
euclids[i].pitchEncoder.getValue() + (random() % 16));
}
}
/* check encoder and real interrupt load */
void setup() {
MidiClock.mode = MidiClock.INTERNAL;
MidiClock.setTempo(130);
tempoEncoder.setValue(MidiClock.tempo);
MidiClock.transmit = true;
MidiClock.setOn16Callback(on16Callback);
MidiClock.start();
}
void loop() {
if (currentEuclid->pulseEncoder.hasChanged() ||
currentEuclid->lengthEncoder.hasChanged() ||
currentEuclid->offsetEncoder.hasChanged()) {
currentEuclid->track.setEuclid(
currentEuclid->pulseEncoder.getCurValue(),
currentEuclid->lengthEncoder.getCurValue(),
currentEuclid->offsetEncoder.getCurValue());
}
currentEuclid->page.handle();
tempoEncoder.checkHandle();
GUI.setLine(GUI.LINE1);
GUI.put_value(1, tempoEncoder.getValue());
GUI.put_value16(2, currentEuclid->track.pattern);
GUI.setLine(GUI.LINE2);
currentEuclid->page.display();
}
I have to say this is tremendous fun, and quite honestly I believe it will change the way we think about midi controllers.




