Incom ist die Kommunikations-Plattform der Fachhochschule Potsdam mehr erfahren

SpaceRattle

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

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.

Vorbereitung:

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

Umsetzung

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.

Konstruktion

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.

Finale Version 2

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.

Übersichtsplan - Steuerung SpaceRattle

Video

Eine kleine Vorschau meines Finalen Objekts

und zum Schluss...

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!

Fritzing Schaltplan + Code

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

Ein Projekt von

Art des Projekts

Studienarbeit im Grundstudium

Betreuung

Stefan Hermann

Zugehöriger Workspace

Musical Interfaces 2014

Entstehungszeitraum

Wintersemester 2014 / 2015