Posted by

Controlling External Sound Synthesizer

As we are no sound engineers but want to use promising sounds we will use existing synths whose parameter we will influence by the registered movements.

XBEE communication

MIDI messages are very restrictive and do not allow flexible mapping of the input of the textile to the output. Therefore the values will be remapped, averaged and recalculated within Processing. Multiple MIDI messages will be send to change the volume and pitch of each sensor. The sounds should visualize movements and maybe not the posture, which is why currently the difference between values in time is shown.

UPDATE:

I rewrote the Code for error handling of Serial Port issues furthermore the refresh rate of Arduino and Processing are increased which makes it more likely for them to occur. Moreover I rewrote the Graph so that multiple AnalogReads from the Arduino are visualized. As there were problems with the FTDI driver for the XBEE on Mac the development platform was switched to PC. I use now 18 different Midi signals to send not just volume, but also Low and High Pitch. The configuration to receive these signals in Ableton is cumbersome but allows to control external Plugins such as eightKnobs by yehezkel raz .

sendMidiAnalog.pde

import themidibus.*; //Import the library
import processing.serial.*;
import java.util.Arrays; 

Serial myPort;
PFont f;  
int[] lastData = new int[7];
float[] mapdA = new float[6];
int[] maxData = new int[7];
int[] minData = new int[7];
float[] maxDifference = new float[6];
int[][] bufferData = new int[6][20]; 
boolean[] activeAnalogR = {true, false, true, false, true, false};
boolean[] configPort = {false, false, false, false, false, false, false}; //6 true is sending mode 0-5 are configure Analog for MIDI modes
boolean[] configMode = {false, true, false}; //keys: b(0):negative pitch n(1): volume m(2): positive pitch

MidiBus myBus; // The MidiBus
int initPitch = 0;
int midiMax = 127;
int Port = 7;

void setup() {
  size(400, 400);
  frameRate(1000);
  printArray(Serial.list());
  myPort = new Serial(this, "COM4", 9600); //set the serialport of your xbee here
  background(0);
  MidiBus.list(); // ===List all available Midi devices on STDOUT. This will show each device's index and name.
  myBus = new MidiBus(this, "", "VirtualMIDI"); // Create a new MidiBus with no input device "" output device.
  myBus.sendTimestamps(false);
  f = createFont("Helvetica", 16, true); 
  //Arrays.fill(configPort, Boolean.FALSE);
  Arrays.fill(lastData, 0);
  Arrays.fill(maxData, 0);
  Arrays.fill(minData, 0);
}

void draw() {
  learnMaxMin();

  if (configPort[6] == true) { //7 is send Data mode
    for (int APort=0; APort <6; APort++) {
      if (activeAnalogR[APort]) {
        float valueCurrent = getAverage(bufferData[APort], 2) ;
        float valueOlder = getAverage(bufferData[APort], 15);
        float difference = valueOlder - valueCurrent;
        boolean negative = false;
        if (difference < 0) {
          difference = difference * -1;
          negative = true;
        }
        if (difference > maxDifference[APort]) maxDifference[APort] = difference;

        //mapdA[APort] = map((float)valueCurrent, (float)minData[APort], (float)maxData[APort], 0, midiMax);

        mapdA[APort] = map(difference, 0, maxDifference[APort], 0, midiMax);
        myBus.sendControllerChange(APort, 0, (int)mapdA[APort]);
        if (negative)       myBus.sendControllerChange(APort, 1, (int)mapdA[APort]);
        else       myBus.sendControllerChange(Port, 2, (int)mapdA[APort]);
        println("current:"+valueCurrent+ " older: "+valueOlder +" difference: "+ difference + " mapped: "+ mapdA[APort]+ " negative: "+ negative);
        //println("max" + maxData[APort] + "min"+ minData[APort]);
      }
    }
  } else {
    for (int i = 0; i <configPort.length; i++) {
      if (true == configPort[i]) {
        Port = i;
      }
    }
  }
  drawGraph();
}

float getAverage(int valueArray[], int length) {
  int i;
  float sum = 0;
  float average;
  for (i=valueArray.length-length; i<valueArray.length; i++) {
    sum += valueArray[i];
  }
  average = sum/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() {
  try {
    for (int i=0; i <maxData.length; i++)
    {
      if (lastData[i] > maxData[i]|| maxData[i]==0) {
        maxData[i] = lastData[i];
      } else if (lastData[i] < minData[i]|| minData[i]==0) {
        minData[i] = lastData[i];
      }
    }
  }
  catch(Exception e) {
    println("learnMaxMin exception");
  }
}

void serialEvent(Serial myPort) {
  try {
    String serialString = myPort.readStringUntil('n'); 
    if (serialString != null) { 
      serialString = serialString.substring(0, serialString.length()-1);
      // println(serialString);

      lastData = int(split(serialString, ","));
      if (lastData[6]>maxData[6]) {
        for (int i=0; i <lastData.length-1; i++)
        {
          addEntry(lastData[i], bufferData[i]);
          printArray(lastData);
        }
      } else println("old data");
    }
  }
  catch (Exception e) {
    println("serialEvent exception");
  }
  //printArray(lastData);
}
void printArray(int[][] anArray) {
  System.out.println(Arrays.deepToString(anArray));
}
void stop() {
  myPort.clear();
}

config.pde

void keyPressed() {
  int i = java.lang.Character.getNumericValue(key);
  if (i<= 6&&i >=0) {
    Arrays.fill(configPort, Boolean.FALSE);
    configPort[i] = true;
  }

  if (key == '+'&& initPitch < midiMax) {
    initPitch = initPitch + 1;
    if (configMode[1]) {
      println("Port: " +Port +" Pitch: "  + initPitch + " Volume");
      myBus.sendControllerChange(Port, 0, initPitch);
    } else if (configMode[0]) {    
      println("Port: " +Port +" Pitch: "  + initPitch + " Negative Pitch");
      myBus.sendControllerChange(Port, 1, initPitch);
    } else if (configMode[2]) {    
      println("Port: " +Port +" Pitch: "  + initPitch + " Positive Pitch");
      myBus.sendControllerChange(Port, 2, initPitch);
    }
  } else if (key == '-' && initPitch > 0) {
    initPitch = initPitch - 1;
    if (configMode[1]) {
      println("Port: " +Port +" Pitch: "  + initPitch + " Volume");
      myBus.sendControllerChange(Port, 0, initPitch);
    } else if (configMode[0]) {    
      println("Port: " +Port +" Pitch: "  + initPitch + " Negative Pitch");
      myBus.sendControllerChange(Port, 1, initPitch);
    } else if (configMode[2]) {    
      println("Port: " +Port +" Pitch: "  + initPitch + " Positive Pitch");
      myBus.sendControllerChange(Port, 2, initPitch);
     }
  } else if (initPitch == 0 || initPitch == midiMax) {
    println("Reached value end: " +initPitch );
  }
  if (key=='r') { //empty max min
    Arrays.fill(maxData, 0);
    Arrays.fill(minData, 0);
    Arrays.fill(maxDifference, 0);
  } 
  //set the midi ports
  else if (key=='b') { //b(0):negative pitch 
    Arrays.fill(configMode, Boolean.FALSE);
    configMode[0] = true;
  } else if (key=='n') {//n(1): volume 
    Arrays.fill(configMode, Boolean.FALSE);
    configMode[1] = true;
  } else if (key=='m') {//m(2): positive pitch
    Arrays.fill(configMode, Boolean.FALSE);
    configMode[2] = true;
  }
}

drawGraph.pde

int lastxPos= 1;
int[] lastheight= new int[6];
int xPos = 1;         // horizontal position of the graph 

void drawGraph() {

  for (int APort=0; APort <6; APort++) {
    float inByte = map(lastData[APort], 0, 1023, 0, height); //map to the screen height.
    //Drawing a line from Last inByte to the new one.
    stroke(APort*42, 255-APort*42, 150+APort*20);     //stroke color
    strokeWeight(2);        //stroke wider
    line(lastxPos, lastheight[APort], xPos, height - inByte); 

    lastxPos= xPos;
    lastheight[APort]= int(height-inByte);
  }
  // at the edge of the window, go back to the beginning:
  if (xPos >= width) {
    xPos = 0;
    lastxPos= 0;
    background(0);  //Clear the screen.
    textFont(f, 16);
    for (int APort=0; APort <6; APort++) {
      fill(APort*42, 255-APort*42, 150+APort*20);
      
        text("APort "+ APort, APort * 60, lastheight[APort]);
      
    }
  } else {
    // increment the horizontal position:
    xPos++;
  }
}



Comments are closed.