Übung zur Verwendung von Android-Smartphones als Grundlage für Klanginstallationen
(EN google-translate)
(PL google-translate)
Android-Smartphones oder -Tablets sollen mit Hilfe von Processing 3.0a5 so programmiert werden, dass Geräte entstehen, mit denen in Gruppen interaktive Klang-Performances realisiert werden können.
Beispiele dazu finden sich im Projekt CoSiMa (Collaborative Situated Media) am IRCAM:
Siehe die eingebetteten Flash-Filme hier: http://cosima.ircam.fr/
Beispiel zu Projekt CoSiMa - Video-URL direkt auf youtube.
Sehr kurze Einführung in Processing allgemein:
Hinweise zu Android-Programmierung mit Processing:
Literaturhinweise:
Sauter, Daniel: Rapid Android Development: Build Rich, Sensor-Based Applications with Processing. O'Reilly, Köln, 2013. Bartmann, Erik: Processing. O'Reilly, Köln, 2010. Reas, C., Fry, B.: Getting Started with Processing. O'Reilly, Köln, 2010.
Code 0-1: Literaturhinweise zu Processing und Android-Programmierung mit Processing.
Aufgabenstellung
Ausgangspunkt für die Übung soll die Library Ketai bilden, die es insbesondere auf einfache Weise erlaubt, Sensoren von Android-Devices mit Processing im Android-Mode zu programmieren.
Zwei weiter entwickelte Varianten zeigen, wie man einen Ton bei einem Schlag auslöst und wie gespielte Tonhöhen durch die Device-Lage gesteuert werden können und mehrere Devices synchronisiert werden können.
|
klanginst002_ton.zip - Erste Variante - Ton spielen bei Stößen.
klanginst003_synchron.zip - Zweite Variante - kontinuierlich synchron gespielte Wechselnoten, Tonhöhen abhängig von Lage des Devices im Raum.
import ketai.sensors.*; KetaiSensor sensor; float accelerometerX, accelerometerY, accelerometerZ; void setup() { sensor = new KetaiSensor(this); sensor.start(); orientation(LANDSCAPE); textAlign(CENTER, CENTER); textSize(36); } void draw() { background(78, 93, 75); //Gesamtvektor abzüglich Erdbeschleunigung: double x = accelerometerX; double y = accelerometerY; double z = accelerometerZ; double gesamt = Math.sqrt(x*x+y*y+z*z) - 9.81; text("Accelerometer: " + "x: " + nfp(accelerometerX, 1, 3) + " " + "y: " + nfp(accelerometerY, 1, 3) + " " + "z: " + nfp(accelerometerZ, 1, 3) + " " + "ges: " + gesamt , 0, 0, width, height); } void onAccelerometerEvent(float x, float y, float z) { accelerometerX = x; accelerometerY = y; accelerometerZ = z; }
Code 0-2: klanginst001_ketai_beschl - Accelerometer-Beispiel aus der Ketai-Library (etwas verkürzt).
import java.util.*; import info.kramann.crossplattform.system.Sequenzer; import info.kramann.crossplattform.system.Audioout; import info.kramann.crossplattform.mathematik.Zufall; import ketai.sensors.*; Audioout audioout; MeinSequenzer meinsequenzer; boolean PLAY = false; int TONINDEX = 0; KetaiSensor sensor; float accelerometerX, accelerometerY, accelerometerZ; double gesamt = 0.0; void setup() { meinsequenzer = new MeinSequenzer(this,480); audioout = new Audioout(meinsequenzer); sensor = new KetaiSensor(this); sensor.start(); orientation(LANDSCAPE); textAlign(CENTER, CENTER); textSize(36); } void draw() { background(78, 93, 75); text("Accelerometer: " + "x: " + nfp(accelerometerX, 1, 3) + " " + "y: " + nfp(accelerometerY, 1, 3) + " " + "z: " + nfp(accelerometerZ, 1, 3) + " " + "ges: " + gesamt , 0, 0, width, height); } void onAccelerometerEvent(float x, float y, float z) { accelerometerX = x; accelerometerY = y; accelerometerZ = z; //Gesamtvektor abzüglich Erdbeschleunigung: gesamt = Math.sqrt(x*x+y*y+z*z) - 9.81; if(gesamt>3.0 && PLAY==false) { PLAY=true; TONINDEX = 0; if(x>5.0) TONINDEX=0; else if(x<-5.0) TONINDEX=1; else if(y>5.0) TONINDEX=2; else if(y<-5.0) TONINDEX=3; else if(z>5.0) TONINDEX=4; else if(z<-5.0) TONINDEX=5; } }
Code 0-3: klanginst002_ton - Erfassung von Stößen und Spiel eines Tones bei Schlägen.
//ACHTUNG: //W-Lan aktivieren und dann //prüfen, wie gut die interne Uhr gestellt ist, mit der APP "ClockSync" //Bei Nexus7 wird angezeigt als "local offset": -104,994 //D.h. das gerät geht 104994 Millisekunden nach. //Darum muß als Wert für OFFSET_MILLIS in der datei Interner Speicher/Download/OFFSET_MILLIS.txt //der Wert 104994 eingetragen werden. // //Kontrollrechnung: Atomzeit: 18:45:55 Nexus7: 18:44:10 => Differenz von 60+45==105 Sekunden import java.util.*; import info.kramann.crossplattform.system.Sequenzer; import info.kramann.crossplattform.system.Audioout; import info.kramann.crossplattform.mathematik.Zufall; import info.kramann.crossplattform.system.Datei; import ketai.sensors.*; Audioout audioout; MeinSequenzer meinsequenzer; Datei datei; int TONINDEX = 0; KetaiSensor sensor; float accelerometerX, accelerometerY, accelerometerZ; double gesamt = 0.0; long OFFSET_MILLIS=0; boolean GESTARTET = false; void setup() { datei = new Datei(this); try { String offset = datei.ladeString("OFFSET_MILLIS.txt"); OFFSET_MILLIS = (long)Double.parseDouble(offset); } catch(Exception e) { } meinsequenzer = new MeinSequenzer(this,240); sensor = new KetaiSensor(this); sensor.start(); orientation(LANDSCAPE); textAlign(CENTER, CENTER); textSize(36); System.out.println("Warte auf Synchronität."); //Ist schon eingebaut!!!! while((System.currentTimeMillis()+OFFSET_MILLIS)%5000!=0); audioout = new Audioout(meinsequenzer); System.out.println("GESTARTET!"); } void draw() { background(78, 93, 75); text("Accelerometer: " + "x: " + nfp(accelerometerX, 1, 3) + " " + "y: " + nfp(accelerometerY, 1, 3) + " " + "z: " + nfp(accelerometerZ, 1, 3) + " " + "ges: " + gesamt + " " + "OFFSET_MILLIS = " + OFFSET_MILLIS , 0, 0, width, height); } void onAccelerometerEvent(float x, float y, float z) { accelerometerX = x; accelerometerY = y; accelerometerZ = z; //Gesamtvektor abzüglich Erdbeschleunigung: gesamt = Math.sqrt(x*x+y*y+z*z) - 9.81; TONINDEX = 0; if(x>5.0) TONINDEX=0; else if(x<-5.0) TONINDEX=1; else if(y>5.0) TONINDEX=2; else if(y<-5.0) TONINDEX=3; else if(z>5.0) TONINDEX=4; else if(z<-5.0) TONINDEX=5; }
Code 0-4: klanginst003_synchron
import info.kramann.crossplattform.system.Sequenzer; public class MeinSequenzer extends Sequenzer { public MeinSequenzer(PApplet pap, int BPM_TICK) { super(pap,BPM_TICK); for(int n=0;n<midinamen.length;n++) { for(int i=0;i<miditonh[n].length;i++) { addSample(midinamen[n]+miditonh[n][i]); } } } public void zeitschritt() //wird von Sequenzer aufgerufen und das wiederum von Audioout getriggert. { playSample(TONINDEX,0); } }
Code 0-5: Zusatzklasse (innere Klasse) MeinSequenzer.
String[] midinamen = {"vib/vib"}; int[][] miditonh = { { 53,55,57,59,60,62,64,65,67,69,71,72 } };
Code 0-6: Zusatz-tab Parameter.