In seiner Funktionalität auf die Lehre in gestalterischen Studiengängen zugeschnitten... Schnittstelle für die moderne Lehre
In seiner Funktionalität auf die Lehre in gestalterischen Studiengängen zugeschnitten... Schnittstelle für die moderne Lehre
SpaceRattle ist ein MIDI Instrument mit dessen Hilfe sich in kurzer Zeit kleine Beats erstellen lassen. Dabei wurde das einfache Konzept der Rassel genutzt. Das Objekt entstand im Kurs „Musical Interfaces “ bei Stefan Hermann
Mein Ziel war es, ein MIDI Instrument zu bauen, welches einfach, schlicht und unkompliziert sein sollte. Um den Lernfaktor und die damit verbundene Hemmschwelle mein Interface zu benutzen möglichst gering zu halten, orientierte ich mich an einer Rassel. Mein Musical Interface sollte kein professionelles Tool werden, sondern etwas, mit dem man einfach alleine oder mit Freunden zusammen Spaß haben kann. Für die längliche zylindrische Form entschied ich mich aus ästhetischen Gründen.
Zu Beginn habe ich erst einmal versucht, die Teile zu Sammeln, die ich für mein Project benötigen würde. Dabei ging es zuerst einmal um das Innenleben, als das Gehäuse. Als Basis stand uns der Mikrocontroller Teensy zu verfügung, der durch seine MIDI-Schnittstelle bestens geeignet für das Projekt war.
Bei meiner Recherche fand ich folgende Teile:
Tinkersoup:
- Accelerometer ADXL362 (Zum steuern von Effekten durch Neigung)
- Neigungssensor (Shakefunktion, wobei diese letztendlich auch durch das Accelerometer gelöst wurde)
- Vibrationsmotor (dient als Metronom)
exp-tech - Klingelknopf (für Effektsteuerung in Version 1) - 4xLED-Buttons (für Instrumentauswahl in Version 1)
Conrad: - Lötzinn - kabel - Lötkolben Heißkleber
Aus dem Teensy-Kit: - Widerstände - Transistor - Steckkabel - Breadboard
Für die Umsetzung steckte ich erstmal die einzelnen Funktionen auf dem Breadboard fest. Die einzelnen Funktionen „Instrument auswählen“, „Shake“ und Effect wurden zunächst erst einzeln programmiert.
Vibrationsmotor Der Vibrationsmotor funktioniert so, dass beim starten des Tracks die MIDI clock eingelesen wird, und der Vibrationsmotor dementsprechend nach einer Vorlage von Stefan im Takt Vibriert.
Effektsteuerung durch Accelerometer
Um der Rassel eine zusätzliche Besonderheit zu verleihen, wollte ich durch Neigung des Instruments einen Effekt ansteuern können, der den klang des Instruments und des aufgenommenen Loops wiedergeben sollte. Dafür verwendete ich das Accelerometer.
Ich fand heraus, dass sich die x-Werte besonders dafür eigneten, da das Objekt so in liegendem Zustand die Werte x = 0 ausgaben, und in senkrechtem Zustand die maximalwerte für x, die ca bei 1100 liegen. Für das auslesen des Accelerometer wird die annem-ADXL362 Library benötigt.
Shake-Funktion Um den Shake der Rassel umzusetzen verwendete ich den Neigungssenior, der wie ein Button funktionierte. Dazu verwendete ich die Bounce-Library. Später entschied ich mich jedoch dafür, den Neigungssensor durch das Accelerometer zu ersetzen, da dieses genauer war und ich mir erhoffte, dass so weniger Fehler beim Shaken auftreten würden.
Nachdem der Code in den einzelnen Funktionen funktionierte, entwickelte ich einen Schaltplan mit Fritzing. Außerdem schrieb ich die Code-Schnipsel zu einem Code zusammen, was sich als schwieriger herausstellte als gedacht.
Elektronik Die Elektronik wurde komplett auf einer Lochrasterplatine verlötet und gemeinsam mit der Verkabelung in das Gehäuse gesteckt. Danach alles verklebt und geschlossen, die Knöpfe in die zuvor gebohrten Löcher geschraubt.
Gehäuse Für das Gehäuse verwendete ich Acrylrohre im Durchmesser von 60mm und einer länge von 135mm sowie die darauf passenden Deckel. Ich recherchierte sehr lange nach LED-buttons, doch fand leider keine, die mir sonderlich gut gefielen.
Nach der Endpräsentation war ich sehr gefrustet. Mein Interface war mir zu groß. Ausserdem hatte ich es bis zur Präsentation nicht geschafft Ungenauigkeiten aus der Shake-Funktion herauszubekommen. Ich traf kurzerhand den Entschluss, das Objekt in der kommenden Woche erneut zu bauen. Dabei waren mir folgende Dinge besonders wichtig:
function Das Interface sollte einwandfrei funktionieren. Dafür wurde nochmals der komplette Code neu strukturiert und Fehler ausgemerzt. Außerdem verabschiedete ich mich von Final Cut Studio, bei dem es beim einlesen der MIDI-Signale verzögerungen gibt. Ich entschied mich für MainStage zusammen mit Loopback.
simplicity Der Shaker sollte noch einfacher und intuitiver gestaltet sein. Ich Entschied mich, die 5 Buttons durch einen Einzigen zu ersetzen, da ich es als unpraktisch empfand, das Instrument drehen zu müssen, um eine neues Instrument auszuwählen. Die LEDs der Instrumente ersetzte ich durch RGBs, und wies jedem Instrument eine Farbe zu, die aufleuchtet, wenn die Spur aktiv ist. Außerdem war es mir wichtig, dass das Interface ohne Computer bedienbar sein sollte, weshalb ich mich von Spuren verabschiedete und nur einzelne „Töne“ aus einem einzigen Drumkit aussuchte. Jede Taste Bedient nun also ein Teil eines Drumkits (Kick, Snare...), die Drumkits können selbstverständlich ausgetauscht werden.
size Alle Komponenten wurden so eng wie möglich auf einer Platine Verlötet. So konnte ich den ehemaligen Durchmesser des Rohres von 60mm auf 30mm reduzieren.
Insgesamt hat mir der Kurs unglaublich Spaß gemacht. Ich wurde nicht nur vor viele Herausforderungen gestellt sondern hatte auch eine extrem steile Lernkurve, wenn man bedenkt, dass es nahezu mein erster Kontakt mit Code und Physical Computing war. Ich bin immer wieder erstaunt, wenn ich zurückblicke und bemerke, wie wenig ich vor nichteinmal 6 Monaten konnte. Vielen Dank an Stefan Hermann, der uns immer fleißig unterstützt hat, und uns einer super Basis mit sanfter Einführung ins Physical Computing gegeben hat. Es hat sehr viel Spaß gemacht!
#include <SPI.h>
#include <ADXL362.h>
#include <Bounce2.h>
// Accelerometer
ADXL362 xl;
int16_t temp;
int16_t XValue, YValue, ZValue, Temperature;
//produce Sound
int musiccounter = 1;
int sensibility = 1300; //Shake Sensibility
int note1 = 53;
int note2 = 52;
int note3 = 62;
int note4 = 67;
int channel = 1;
int cc_off = 1;
int cc_on = 65;
//RGB Instrument 1
int redPin_1 = 3;
int greenPin_1 = 4;
int bluePin_1 = 5;
int r1 = 0;
int g1 = 255;
int b1 = 0;
//RGB Insturmet 2
int redPin_2 = 20;
int greenPin_2 = 21;
int bluePin_2 = 22;
int r2 = 200;
int g2 = 200;
int b2 = 10;
//RGB Instrument 3
int redPin_3 = 17;
int greenPin_3 = 18;
int bluePin_3 = 19;
int r3 = 255;
int g3 = 20;
int b3 = 20;
//RGB Instrument 4
int redPin_4 = 14;
int greenPin_4 = 15;
int bluePin_4 = 16;
int r4 = 200;
int g4 = 0;
int b4 = 200;
//white
int rw = 0;
int gw = 160;
int bw = 200;
//Instrument Change
int btn_Pin = 23;
Bounce btn = Bounce();
boolean btn_press = false;
int modeCount = 1;
int btnCount = 0;
int btnCountChange = 20000;
//Effect
//Vibration for Midi Clock
int Pin_V = 9;
// Teensyduino MIDI Beat Clock Vibration
byte counter;
byte CLOCK = 248;
byte START = 250;
byte CONTINUE = 251;
byte STOP = 252;
void setup(){
Serial.begin(31250);
usbMIDI.setHandleRealTimeSystem(RealTimeSystem);
//Accelerometer
xl.begin(10); // Starts Accelerometer
xl.beginMeasure(); // Switch Accelerimeter to measure mode
//Outputs
pinMode(redPin_1, OUTPUT);
pinMode(redPin_2, OUTPUT);
pinMode(redPin_3, OUTPUT);
pinMode(redPin_4, OUTPUT);
pinMode(greenPin_1, OUTPUT);
pinMode(greenPin_2, OUTPUT);
pinMode(greenPin_3, OUTPUT);
pinMode(greenPin_4, OUTPUT);
pinMode(bluePin_1, OUTPUT);
pinMode(bluePin_2, OUTPUT);
pinMode(bluePin_3, OUTPUT);
pinMode(bluePin_4, OUTPUT);
pinMode(Pin_V, OUTPUT);
//initialise button
pinMode(btn_Pin, INPUT_PULLUP);
btn.attach(btn_Pin); //attach button to bounce library
btn.interval(5);
//Booting Mode
analogWrite(redPin_1, r1);
analogWrite(greenPin_1, g1);
analogWrite(bluePin_1, b1);
analogWrite(redPin_2, rw);
analogWrite(greenPin_2, gw);
analogWrite(bluePin_2, bw);
analogWrite(redPin_3, rw);
analogWrite(greenPin_3, gw);
analogWrite(bluePin_3, bw);
analogWrite(redPin_4, rw);
analogWrite(greenPin_4, gw);
analogWrite(bluePin_4, bw);
delay(100);
analogWrite(redPin_1, rw);
analogWrite(greenPin_1, gw);
analogWrite(bluePin_1, bw);
analogWrite(redPin_2, r2);
analogWrite(greenPin_2, g2);
analogWrite(bluePin_2, b2);
analogWrite(redPin_3, rw);
analogWrite(greenPin_3, gw);
analogWrite(bluePin_3, bw);
analogWrite(redPin_4, rw);
analogWrite(greenPin_4, gw);
analogWrite(bluePin_4, bw);
delay(100);
analogWrite(redPin_1, rw);
analogWrite(greenPin_1, gw);
analogWrite(bluePin_1, bw);
analogWrite(redPin_2, rw);
analogWrite(greenPin_2, gw);
analogWrite(bluePin_2, bw);
analogWrite(redPin_3, r3);
analogWrite(greenPin_3, g3);
analogWrite(bluePin_3, b3);
analogWrite(redPin_4, rw);
analogWrite(greenPin_4, gw);
analogWrite(bluePin_4, bw);
delay(100);
analogWrite(redPin_1, rw);
analogWrite(greenPin_1, gw);
analogWrite(bluePin_1, bw);
analogWrite(redPin_2, rw);
analogWrite(greenPin_2, gw);
analogWrite(bluePin_2, bw);
analogWrite(redPin_3, rw);
analogWrite(greenPin_3, gw);
analogWrite(bluePin_3, bw);
analogWrite(redPin_4, r4);
analogWrite(greenPin_4, g4);
analogWrite(bluePin_4, b4);
delay(100);
analogWrite(redPin_1, 0);
analogWrite(greenPin_1, 0);
analogWrite(bluePin_1, 0);
analogWrite(redPin_2, 0);
analogWrite(greenPin_2, 0);
analogWrite(bluePin_2, 0);
analogWrite(redPin_3, 0);
analogWrite(greenPin_3, 0);
analogWrite(bluePin_3, 0);
analogWrite(redPin_4, 0);
analogWrite(greenPin_4, 0);
analogWrite(bluePin_4, 0);
delay(100);
analogWrite(redPin_1, r1);
analogWrite(greenPin_1, g1);
analogWrite(bluePin_1, b1);
analogWrite(redPin_2, r2);
analogWrite(greenPin_2, g2);
analogWrite(bluePin_2, b2);
analogWrite(redPin_3, r3);
analogWrite(greenPin_3, g3);
analogWrite(bluePin_3, b3);
analogWrite(redPin_4, r4);
analogWrite(greenPin_4, g4);
analogWrite(bluePin_4, b4);
digitalWrite(Pin_V, HIGH);
delay(200);
analogWrite(redPin_1, 0);
analogWrite(greenPin_1, 0);
analogWrite(bluePin_1, 0);
analogWrite(redPin_2, 0);
analogWrite(greenPin_2, 0);
analogWrite(bluePin_2, 0);
analogWrite(redPin_3, 0);
analogWrite(greenPin_3, 0);
analogWrite(bluePin_3, 0);
analogWrite(redPin_4, 0);
analogWrite(greenPin_4, 0);
analogWrite(bluePin_4, 0);
digitalWrite(Pin_V, LOW);
delay(200);
analogWrite(redPin_1, r1);
analogWrite(greenPin_1, g1);
analogWrite(bluePin_1, b1);
analogWrite(redPin_2, r2);
analogWrite(greenPin_2, g2);
analogWrite(bluePin_2, b2);
analogWrite(redPin_3, r3);
analogWrite(greenPin_3, g3);
analogWrite(bluePin_3, b3);
analogWrite(redPin_4, r4);
analogWrite(greenPin_4, g4);
analogWrite(bluePin_4, b4);
digitalWrite(Pin_V, HIGH);
delay(200);
analogWrite(redPin_1, 0);
analogWrite(greenPin_1, 0);
analogWrite(bluePin_1, 0);
analogWrite(redPin_2, 0);
analogWrite(greenPin_2, 0);
analogWrite(bluePin_2, 0);
analogWrite(redPin_3, 0);
analogWrite(greenPin_3, 0);
analogWrite(bluePin_3, 0);
analogWrite(redPin_4, 0);
analogWrite(greenPin_4, 0);
analogWrite(bluePin_4, 0);
digitalWrite(Pin_V, LOW);
delay(300);
usbMIDI.sendControlChange(51, cc_on, channel);//turns on record mode in Mainstage
usbMIDI.sendControlChange(51, cc_off, channel);//turns on record mode in Mainstage
}
void loop(){
//Accelerometer read
xl.readXYZTData(XValue, YValue, ZValue, Temperature);
btn.update();
if(btn.fell()){
usbMIDI.sendControlChange(51, cc_off, channel);
btn_press = true;
btnCount = 0;
}
if(btn.rose()){
btn_press = false;
if(btnCount<btnCountChange){
usbMIDI.sendControlChange(51, cc_on, channel);//tells Mainstage that new Instrument is about to be recorded
modeCount++; //counts how long button is holded
if(modeCount>4){
modeCount=1;
}
}
}
if(btn_press == true){
btnCount++;
}
if(XValue < sensibility){
musiccounter = 1; //prevents multiple Sends per shake
}
//Instruments
//Instrument 1 active
if((modeCount == 1)&&(btn_press == false)&&(btnCount<btnCountChange)){
analogWrite(redPin_1, r1);
analogWrite(greenPin_1, g1);
analogWrite(bluePin_1, b1);
analogWrite(redPin_2, rw);
analogWrite(greenPin_2, gw);
analogWrite(bluePin_2, bw);
analogWrite(redPin_3, rw);
analogWrite(greenPin_3, gw);
analogWrite(bluePin_3, bw);
analogWrite(redPin_4, rw);
analogWrite(greenPin_4, gw);
analogWrite(bluePin_4, bw);
if((XValue > sensibility)&&(musiccounter == 1)){
usbMIDI.sendNoteOn(note1,70,channel);
musiccounter = 0; //prevents multiple Sends per shake
}
}
//Instrument 2 active
if((modeCount == 2)&&(btn_press == false)&&(btnCount<btnCountChange)){
analogWrite(redPin_1, rw);
analogWrite(greenPin_1, gw);
analogWrite(bluePin_1, bw);
analogWrite(redPin_2, r2);
analogWrite(greenPin_2, g2);
analogWrite(bluePin_2, b2);
analogWrite(redPin_3, rw);
analogWrite(greenPin_3, gw);
analogWrite(bluePin_3, bw);
analogWrite(redPin_4, rw);
analogWrite(greenPin_4, gw);
analogWrite(bluePin_4, bw);
if((XValue > sensibility)&&(musiccounter == 1)){
usbMIDI.sendNoteOn(note2,70,channel);
musiccounter = 0; //prevents multiple Sends per shake
}
}
//Instrument 3 active
if((modeCount == 3)&&(btn_press == false)&&(btnCount<btnCountChange)){
analogWrite(redPin_1, rw);
analogWrite(greenPin_1, gw);
analogWrite(bluePin_1, bw);
analogWrite(redPin_2, rw);
analogWrite(greenPin_2, gw);
analogWrite(bluePin_2, bw);
analogWrite(redPin_3, r3);
analogWrite(greenPin_3, g3);
analogWrite(bluePin_3, b3);
analogWrite(redPin_4, rw);
analogWrite(greenPin_4, gw);
analogWrite(bluePin_4, bw);
if((XValue > sensibility)&&(musiccounter == 1)){
usbMIDI.sendNoteOn(note3,70,channel);
musiccounter = 0;
}
}
//Instrument 4 active
if((modeCount == 4)&&(btn_press == false)&&(btnCount<btnCountChange)){
analogWrite(redPin_1, rw);
analogWrite(greenPin_1, gw);
analogWrite(bluePin_1, bw);
analogWrite(redPin_2, rw);
analogWrite(greenPin_2, gw);
analogWrite(bluePin_2, bw);
analogWrite(redPin_3, rw);
analogWrite(greenPin_3, gw);
analogWrite(bluePin_3, bw);
analogWrite(redPin_4, r4);
analogWrite(greenPin_4, g4);
analogWrite(bluePin_4, b4);
if((XValue > sensibility)&&(musiccounter == 1)){
usbMIDI.sendNoteOn(note4,70,channel);
musiccounter = 0;
}
}
//effect active
if(btnCount>btnCountChange){
int XValueC = constrain(XValue, -100,1100);
int KValue = map(XValueC, 1100, -100, 0, 127);
usbMIDI.sendControlChange(45, KValue, channel);//Changes Effect
delay(5);
analogWrite(redPin_1, rw);
analogWrite(greenPin_1, gw + KValue*0.5);
analogWrite(bluePin_1, bw - KValue);
analogWrite(redPin_2, rw);
analogWrite(greenPin_2, gw + KValue*0.5);
analogWrite(bluePin_2, bw - KValue);
analogWrite(redPin_3, rw);
analogWrite(greenPin_3, gw + KValue*0.5);
analogWrite(bluePin_3, bw - KValue);
analogWrite(redPin_4, rw);
analogWrite(greenPin_4, gw + KValue*0.5);
analogWrite(bluePin_4, bw - KValue);
digitalWrite(Pin_V, LOW); //Vibration shouldnt change results
}
while (usbMIDI.read());
}
//Vibration/Midi Clock (Pin_V)
void RealTimeSystem(byte realtimebyte) {
if(btnCount<btnCountChange){ //Midi Clock is paused in Effect Mode, so that Values dont get Strange
if(realtimebyte == 248) {
counter++;
if(counter == 24) {
counter = 0;
digitalWrite(Pin_V, HIGH);
}
if(counter == 2) {
digitalWrite(Pin_V, LOW);
}
if(realtimebyte == START || realtimebyte == CONTINUE){
counter = 0;
digitalWrite(Pin_V, HIGH);
}}
if(realtimebyte == STOP) {
digitalWrite(Pin_V, LOW);
}
}
}