kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Ü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:

http://www.kramann.info/78_Processing

Hinweise zu Android-Programmierung mit Processing:

http://www.kramann.info/93_Android_Proc

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.

  1. Vorübung: Schreiben Sie eine App, mit deren Hilfe Gehörbildung - d.h. Bestimmung gehörter Intervalle - möglich ist.
  2. Fassen Sie die obere Stimme aus Beispiel klanginst003_synchron als eine Stimme auf, lassen Sie automatisch eine sich ständig verändernde Unterstimme dazu entstehen (passend zu den duch die Drehbewegungen der Hand hervorgerufenen Tonwechsel der ersten Stimme).
  3. Überlegen Sie sich mit den gegebenen Mitteln eine einfache App für Klangperformances in Gruppen mit vielen Android-Devices und setzen diese um.
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.