Frequency Modulated Noise

To be able to sonify dance movements multiple audio sources or virtual instruments need to be combined and influenced by pitch, volume or tone. To be able to do so we use a synthesizer created with the beads project for processing. This part builds on top of the wireless textile stretch sensor with xbee and lilypad and uses again straightforward processing code.

For simple sonification purposes this might be sufficient but we will explore further more advanced synthesizer instead of building them ourselves (Sound Engineering). The reason is that the sounds created by the costume should not only be distinguishable but also have sound aesthetics that are enjoying to listen to. The next steps will be to send MIDI or OSC Data from the Serial Port to a DAW application.


Free Ebook about Additive Synthesis, Frequency Modulation, Sampling, Granular Synthesis, Filters, Compression, Input/Output, MIDI, Analysis with processing:
http://computermusicblog.com/blog/sonifyingprocessing/

Arduino Code for Wireless Analog Communication with Processing

  int a0,a1,a2,a3,a4,a5;
  char c = ',';
  unsigned int t;
  String S = "";
  String E = "";
void setup() {
  Serial.begin(9600);
}
void loop() {
  a0 = analogRead(A0);
  a1 = analogRead(A1);
  a2 = analogRead(A2);
  a3 = analogRead(A3);
  a4 = analogRead(A4); 
  a5 = analogRead(A5);
  t = millis()/100;
  
  S = E+a0+c+a1+c+a2+c+a3+c+a4+c+a5+c+t;
  Serial.println (S);
  if (a1 > 550) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
  delay (100); 
}

Processing Code for Sound Modulation from Analog Sensor Input

import processing.serial.*;
Serial myPort;

int[] lastData = new int[7];
float[] mapdA = new float[6];
int[] maxData = new int[6];
int[] minData = new int[6];
int[][] bufferData = new int[6][20]; 

void setup () {
  size(300, 300);
  printArray(Serial.list());
  myPort = new Serial(this, "/dev/cu.usbserial-DA00T2RW", 9600); //set the serialport of your xbee here
  audioSetup();
}
void draw() {

  drawWave();
  learnMaxMin();

  for (int APort=0; APort <6; APort++) {
    //int valueOld = bufferData[APort][bufferData.length-3];
    int valueCurrent = lastData[APort];
    mapdA[APort] = map((float)valueCurrent, (float)minData[APort], (float)maxData[APort], 0, width);
  }

  carrierFreqA0.setValue((float)mapdA[0] / width * 1000 + 50);
  modFreqRatioA0.setValue((1 - (float)mapdA[1] / height) * 10 + 0.1);
}

int getAverage(int valueArray[]) {
  int i;
  int sum = 0;
  int average;
  for (i=0; i<valueArray.length; i++) {
    sum += valueArray[i];
  }
  average = sum/valueArray.length;
  return average;
}

void addEntry(int value, int valueArray[]) {
  for (int i=0; i<valueArray.length-1; i++) 
  {
    valueArray[i]=valueArray[i+1];
  }
  valueArray[valueArray.length-1] = int(value);
}
void learnMaxMin() {
  for (int i=0; i <6; i++)
  {
    if (lastData[i] > maxData[i]) {
      maxData[i] = lastData[i];
    } else if (lastData[i] < minData[i]) {
      minData[i] = lastData[i];
    }
  }
}

void serialEvent(Serial myPort) {
  String serialString = myPort.readStringUntil('n'); 
  if (serialString != null) { 
    //serialString.trim();
    lastData = int(split(serialString, ","));
    for (int i=0; i <6; i++)
    {
      addEntry(lastData[i], bufferData[i]);
    }
    printArray(lastData);
  }
}

void stop() {
  myPort.clear();
}
//Second Processing Tab
import beads.*;
import java.util.Arrays; 

AudioContext acA0;
Glide carrierFreqA0, modFreqRatioA0;

void audioSetup() {
  acA0 = new AudioContext();

  carrierFreqA0 = new Glide(acA0, 500);
  modFreqRatioA0 = new Glide(acA0, 1);
  Function modFreq = new Function(carrierFreqA0, modFreqRatioA0) {
    public float calculate() {
      return x[0] * x[1];
    }
  };
  WavePlayer freqModulator = new WavePlayer(acA0, modFreq, Buffer.SINE);
  Function carrierMod = new Function(freqModulator, carrierFreqA0) {
    public float calculate() {
      return x[0] * 400.0 + x[1];
    }
  };
  WavePlayer wp = new WavePlayer(acA0, carrierMod, Buffer.SINE);
  Gain g = new Gain(acA0, 1, 0.1);
  g.addInput(wp);
  acA0.out.addInput(g);
  acA0.start();
}

color fore = color(255, 102, 204);
color back = color(0, 0, 0);

void drawWave() {

  loadPixels();
  //set the background
  Arrays.fill(pixels, back);
  //scan across the pixels
  for (int i = 0; i < width; i++) {
    //for each pixel work out where in the current audio buffer we are
    int buffIndex = i * acA0.getBufferSize() / width;
    //then work out the pixel height of the audio data at that point
    int vOffset = (int)((1 + acA0.out.getValue(0, buffIndex)) * height / 2);
    //draw into Processing's convenient 1-D array of pixels
    vOffset = min(vOffset, height);
    pixels[vOffset * height + i] = fore;
  }
  updatePixels();
}