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.
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++; } }