MEMIDION

by HomeMadeGarbage in Circuits > Arduino

663 Views, 1 Favorites, 0 Comments

MEMIDION

IMG_20181019_201327.jpg
IMG_20180926_184951.jpg
スクリーンショット 2018-10-12 18.24.32.png

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

power.png
midiWhistle05_ブレッドボード.png

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

IMG_20180926_185122.jpg
parts.png
parts2.png

Place parts on acrylic case.

DAW Sound Source Mode

soundSourceMode.png
01_VUN4FK21I5.jpeg
"MEMIDION" 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

soundSourceMode.png
playing the MEMIDION

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); }

Operation

playing the MEMIDION 2
Original Instrument Performance &amp;quot;The Fool On The Hill&amp;quot; / The Beatles