MEMIDION
I made the "MEMIDION" MIDI slide whistle.
MEMIDION can be operated as a musical instrument by MIDI keyboard, and it can be used as a MIDI sound source by moving with DAW. But no sound unless you breathe in....
Structure
MEMIDION is a slide whistle that controlled by the micro-controller. The motor with the caterpillar slides the slide whistle. The slide amount is controlled by ToF range finder sensor VL6180. LED Tape NeoPixel emit light following the amount of slide.
Assembly
Place parts on acrylic case.
DAW Sound Source Mode
The MEMIDION works in two modes, DAW Sound Source Mode and Instrument Mode.
When PC (DAW) is connected to Arduino UNO, it switches to DAW Sound Source Mode. Send a MIDI signal from the DAW and move MEMIDION.
Arduino USB-MIDI Device Conversion
Write Moco for LUFA firmware to Arduino and let Arduino recognize it as a MIDI device.
The detail is right below.
https://github.com/kuwatay/mocolufa
Arduino UNO receives MIDI signals and sends them to Arduino Pro Mini with SoftwareSerial to control the motor and NeoPixels.
Setting of DAW Software Reason
Anything is OK if DAW can output MIDI, I used Reason this time.
Place the external MIDI instrument and select "MocoLUFA" for the device.
Instrument Mode
When MEMIDION is not connected to the PC (DAW), it operates as a single musical instrument.
It receives MIDI signal from MIDIController via USB Host Shield and controls the motor and NeoPixels with Arduino Pro Mini.
Arduino Code
I used the following as a USB MIDI library
https://github.com/felis/USB_Host_Shield_2.0
I programmed with reference to the following
https://github.com/felis/USB_Host_Shield_2.0/tree/master/examples/USBH_MIDI/USBH_MIDI_dump
The library for distance sensor VL6180X is below.
https://github.com/pololu/vl6180x-arduino
The library for NeoPixel is below.
https://github.com/adafruit/Adafruit_NeoPixel
#include <usbh_midi.h>
#include <usbhub.h>
#include <SPI.h>
#include <Wire.h>
#include <VL6180X.h>
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7, 9); // RX, TX
USB Usb; USBH_MIDI Midi(&Usb);
uint8_t Note, oldNote;
VL6180X sensor;
int meas; int aim = 50; int diff = 6;
#define PIN A3 #define NUM_LEDS 24 #define BRIGHTNESS 30 int num;
int modeState = 0;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);
void setup() { Serial.begin(115200); mySerial.begin(9600);
pinMode(8, INPUT);
Wire.begin();
pinMode(2, OUTPUT); pinMode(3, OUTPUT); digitalWrite(2, LOW); digitalWrite(3, LOW); sensor.init(); sensor.configureDefault(); sensor.setTimeout(500);
strip.setBrightness(BRIGHTNESS); strip.begin(); strip.show();
if (Usb.Init() == -1) { while (1); //halt } delay( 200 ); }
void loop() { if(modeState != digitalRead(8)){ modeState = digitalRead(8); Serial.print("Mode : "); Serial.println(modeState); }
//Instrument Mode Usb.Task(); if (Usb.getUsbTaskState() == USB_STATE_RUNNING && modeState == 0) { char buf[20]; uint8_t bufMidi[64]; uint16_t rcvd;
if (Midi.RecvData( &rcvd, bufMidi) == 0 && bufMidi[0] == 9) { Note = bufMidi[2]; Serial.print("Instrument Mode : "); Serial.println(Note); MotorInitialMove(); } }
//Sound Source Mode if (mySerial.available() && modeState == 1){ Note = mySerial.read(); Serial.print("Sound Source Mode : "); Serial.println(Note); MotorInitialMove(); }
//Slide distance setting if(Note == 57) aim = 16; //A if(Note == 58) aim = 23; //A# if(Note == 59) aim = 35; //B if(Note == 60) aim = 49; //C if(Note == 61) aim = 57; //C# if(Note == 62) aim = 64; //D if(Note == 63) aim = 75; //D# if(Note == 64) aim = 83; //E if(Note == 65) aim = 91; //F if(Note == 66) aim = 100; //F# if(Note == 67) aim = 106; //G if(Note == 68) aim = 111; //G# if(Note == 69) aim = 119; //A if(Note == 70) aim = 124; //A# if(Note == 71) aim = 129; //B if(Note == 72) aim = 132; //C
//Distance sensor measurement meas = sensor.readRangeSingleMillimeters(); Serial.print("Range Sensor : "); Serial.println(meas);
//Motor operation if(meas > (aim - diff) && meas < (aim + diff)){ digitalWrite(2, LOW); digitalWrite(3, LOW); }else if(meas > aim){ digitalWrite(2, LOW); digitalWrite(3, HIGH); }else if(meas < aim){ digitalWrite(2, HIGH); digitalWrite(3, LOW); }
//LED On num = map(meas, 16, 132, 3, 20); for(int i=num; i
oldNote = Note; }
//Initial operation of the motor void MotorInitialMove() { if(Note > oldNote){ digitalWrite(2, HIGH); digitalWrite(3, LOW); }else{ digitalWrite(2, LOW); digitalWrite(3, HIGH); } delay(50); digitalWrite(2, LOW); digitalWrite(3, LOW); }
// Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if(WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3,0); } if(WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3,0); } WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0,0); }