Introduction: Retro Controller

Wij zijn eerste jaar studenten uit de opleiding Multimedia & Communicatietechnologie (Multec) aan de Erasmushogeschool Brussel.

Samen hebben we een muziek controller gemaakt dat muziek kan starten/stoppen, de pitch kan verhogen, kan terugspoelen en nog meer.

Ons idee kwam van van een cassette, ons doel was om een controller te maken dat lijkt op een cassette.

Step 1: Wat Heb Je Nodig?

Componenten

- 2 Buttons;

- 2 Potentio meters;

- 2 weerstanden (1K elk);

- Arduino uno/nano

- Draadjes (zie elektronisch schema)

- Soldeerplaat

- MDF plaat

Tools

- Lasercutter

- Kniptang

- Striptang

- Soldeerbout (met tin)


Programma's

- Ilustrator/indesign (Tekenprogramma)

- Reaper

- Processing

- Arduino

Step 2: Code Processing

/**

* Basic sketch to receive Serial messages from Arduino * and translates those to OSC-messages for Reaper * * You will need to adapt the USER PARAMETERS * and you will need to install a Library: oscP5 * * made for werkcollege AV&IT * by annoo bob eddi * oct 2017 * */ ///////////////////// USER PARAMETERS ////////////////////////////

/ make sure you use the same baud rate in your Arduino sketch final int baudRate = 115200;

// Go and look for the IP-address in Reaper when using OSC // This is the address Processing sends to and Reaper listens to. // Put this string in remoteIP, here.

//final String remoteIP = "192.168.1.43"; //eg. "127.0.0.1";

final String remoteIP = "vul hier ip in gevonden in reaper";

// Take note of the sendPort and fill this in in Reaper. // This is the port Processing sends to and Reaper listens to.

final int listenPort = 11000, sendPort = 12000;

// The listenPort here is to actively debug.

// the portNames are here to debug as well.

final String portName = "vul hier de portname in gevonden in Arduino";

// final String portName = "COM6"; // "/dev/ttyUSB0";

///////////////////// END of USER PARAMETERS /////////////////////////////

import processing.serial.*; import java.util.*;

import oscP5.*; import netP5.*;

OscP5 oscP5; NetAddress myRemoteLocation;

Serial commsPort; // The serial port boolean messageArrived = false;

String incoming = "", IncomingOSCMessage = "";

final char startChar = '*', endChar = '#'; final char contactCharacter = '|';

// To make sure we only send the parameters (values) that change // these global variabls are delcared here but should // not be initialized here! HashMap oldParams, newParams, toSendParams;

// We need to split the message at every comma void processIncoming () { String resVec[] = incoming.split(","); // we get name + value pairs // so for every name (+2)... try{ for (int i = 0; i< resVec.length; i+=2) { float value = Float.parseFloat(resVec[i+1]); // put them in the new Hashtable newParams.put(resVec[i], value); } } // if an error occurs, let's catch it display and exit. catch(Exception ex){ println("Exception Message: " + ex); printArray(resVec); exit(); } }

// To filter our messages /* We make sure there is only an OSC-out message when * the input message (Serial) changes * That is: if we turn/push the button and it changes value. * So we filter out the incoming values that actually change * note: we won't avoid jumping values * as come from eg accelerometers or distance sensors * you will need to smooth those yourself in Arduino */ void filterParams () { toSendParams = new HashMap(); for (String key : newParams.keySet()) { // if the key is already present if (oldParams.containsKey(key)) { // key present and value not the same, then update if (!oldParams.get(key).equals(newParams.get(key))) { toSendParams.put(key, newParams.get(key)); } } else{ // key is not present in old params, so put it! toSendParams.put(key, newParams.get(key)); } oldParams.put(key, newParams.get(key)); } }

void makeOSC() { for (String key : toSendParams.keySet()) { OscMessage myMessage = new OscMessage("/"+ key); myMessage.add(toSendParams.get(key)); /* send the message */ oscP5.send(myMessage, myRemoteLocation); } }

void translateMessage() { processIncoming(); filterParams(); makeOSC(); } // When we want to print to the window void ShowIncoming() { // to see incoming message, as set in the HashMap text("Incoming from Arduino", 20, 20); int y = 20; for (String key : newParams.keySet()) { y = y+20; text(key, 20, y); text(newParams.get(key), 300, y); } }

void showOsc() { text(IncomingOSCMessage, 300, 200); IncomingOSCMessage =""; }

void setup() { size(1000, 800); // Stage size fill(255); background(0); oldParams = new HashMap(); newParams = new HashMap(); //printArray(Serial.list()); commsPort = new Serial(this, portName, baudRate);

/* start oscP5, listening for incoming messages */ oscP5 = new OscP5(this, listenPort);

/* myRemoteLocation is a NetAddress. a NetAddress takes 2 parameters, * an ip address and a port number. myRemoteLocation is used as parameter in * oscP5.send() when sending osc packets to another computer, device, * application. usage see below. for testing purposes the listening port * and the port of the remote location address are the same, hence you will * send messages back to this sketch. */ myRemoteLocation = new NetAddress(remoteIP, sendPort); }

void draw() { if (messageArrived) { background(0); translateMessage(); ShowIncoming(); messageArrived= false; } showOsc(); }

void serialEvent(Serial commsPort) { // read a byte from the serial port: char inChar = commsPort.readChar(); switch (inChar) { case contactCharacter: commsPort.write(contactCharacter); // ask for more println("starting..."); break; case startChar: incoming= ""; break; case endChar: messageArrived = true; //println("end of msg"); break; default: incoming += inChar; break; } }

/* incoming osc message are forwarded to the oscEvent method. */ void oscEvent(OscMessage theOscMessage) { float value = theOscMessage.get(0).floatValue(); // get the 1st osc argument

IncomingOSCMessage += "\n" + String.format("### received an osc message: " + " addrpattern: " + theOscMessage.addrPattern() + " : %f", value); println(IncomingOSCMessage); }

Step 3: Code Arduino

/* This code is a basic sketch to communicate with Processing through Serial.

It is a blueprint in which you can put your own code specified for your own buttons, potentiometers or sensors.

It has a handshake to make sure we have contact and the format in which we are communicating is decided

It is important to construct the message this same way, so that Processing knows how to deconstruct it and send correct OSC-messages to our DAW

made for werkcollege AV&IT oct 2017

code smooothing created 22 Apr 2007 by David A. Mellis modified 9 Apr 2012 by Tom Igoe

*/

/ baud rate const long baudRate = 115200;

// time to wait in ms between polls to the pins const int loopPauseTime = 200; // milli seconds

// start and end values for the message sent on Serial const String startString = "*", endString = "#";

const char contactCharacter = '|';

// pin id's const int buttonPin1 = 2; const int buttonPin2 = 5; const int numReadings = 5; //rate van smoothing

int pitchReading = A1; int speedReading = A2; int infraReading = A3;

// other global variables int buttonState1 = 0; int buttonState2 = 0; // variable for reading the pushbutton status float sensorValue1 = 0; float sensorValue2 = 0; float sensorValue3 = 0;

//smoothing int readings[numReadings]; // the readings from the analog input int readIndex3 = 0; // the index of the current reading int total3 = 0; // the running total float average3 = 0; // the average

// We need this function to establish contact with the Processing sketch // Keep it here void establishContact() { while (Serial.available() <= 0) { Serial.print(contactCharacter); // send a char and wait for a response... delay(loopPauseTime); } Serial.read(); }

void setup() { // set the pinModes for all the pins pinMode(buttonPin1, INPUT); pinMode(buttonPin2, INPUT); pinMode(pitchReading, INPUT); pinMode(speedReading, INPUT); pinMode(infraReading, INPUT);

// initialize Serial comms Serial.begin(baudRate); while (!Serial); //smoothing for (int thisReading = 0; thisReading < numReadings; thisReading++) { readings[thisReading] = 0; }

// wait for handshake establishContact(); }

void loop() { // poll all the pins and map the reading to the appropriate range buttonState1 = digitalRead(buttonPin1); buttonState2 = digitalRead(buttonPin2); sensorValue1 = analogRead (pitchReading); sensorValue2 = analogRead (speedReading); sensorValue3 = analogRead (infraReading);

//maping the incoming values to necessary values sensorValue1 = map(sensorValue1,0,1023,0,100.0)/-100.0; sensorValue2 = map(sensorValue2,0,1023,0.0,100)/100.0; sensorValue3 = map(sensorValue3,0,700,50,100);

// smoothing sensor: total3 = total3 - readings[readIndex3]; // read from the sensor: readings[readIndex3] = sensorValue3; // add the reading to the total: total3 = total3 + readings[readIndex3]; // advance to the next position in the array: readIndex3 = readIndex3 + 1;

// if we're at the end of the array... if (readIndex3 >= numReadings) { // ...wrap around to the beginning: readIndex3 = 0; } // calculate the average: average3 = (total3 / numReadings); // smoothing sensor

Serial.print(startString); // start a message sequence // wirte all the name,value pairs, separated by commas Serial.print("potentio1"); Serial.print(","); Serial.print(sensorValue1); Serial.print(",");

Serial.print("potentio2"); Serial.print(","); Serial.print(sensorValue2); Serial.print(",");

Serial.print("infra-sensor"); Serial.print(","); Serial.print(average3/100); Serial.print(",");

Serial.print("knop 1 in2 wit"); Serial.print(","); Serial.print(buttonState1); Serial.print(","); Serial.print("knop2 in5 geel"); Serial.print(","); Serial.print(buttonState2);

// write the end of message Serial.print(endString);

// wait for a while..

delay(loopPauseTime); }

Step 4: Reaper

Stap 1: Ga bovenaan naar Options>Prefrences

Stap 2: Ga in prefrences naar Control/OSC/web en druk op Add

Stap 3: Kies bij Control surface mode voor OSC (Open Sound Control)

Stap 4: Vul je device name in, vink Recieve on port aan en vul in wat er in processing bij Sendport staat

Stap 5: Kopieer de Host IP die je hier ziet en vul deze in in Processing

Stap 6: Druk op ok en de controller is nu verbonden met Reaper

Step 5: Behuizing

Breedte: 170 mm

Lengte: 90 mm

Hoogte 30 mm

Knoppen: 16 mm (diameter

Potentio meters: 3 mm (diameter)

Afstand sensor: Breedte 2.9 mm

Lengte 0.8 mm

Materiaal: MDF (3mm)

Step 6: Elektronica

Stap 1:

Verbind de ground en 5 volt van Arduino met het breadboard

Stap 2:

Verbind pin A0 met potentio 1

Verbind pin A1 met potentio 2

Verbind pin A3 met infrarood sensor.

Verbind pin A2 met de niet sticky button.

Verbind pin A5 met de sticky button.

Step 7: Medewerkers

- Mayes El Baba

- Arno Gorissen

- Michiel De Wandelaer