Ü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:
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.
|
klanginst001_ketai_beschl.zip - Ausgangspunkt "Accelerometer-Beispiel" der Ketai-Library.
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.