A Midi Controller

Because my sensor report is on a form of capacitive sensing, I wanted to try to use it to make this second assignment. Based on Disney’s touchè and working from this instructable, the actual “sensing” relies on the generation of multiple frequencies. I  then have to look for points of capacitance in the readings coming back. The layout of the circuit alone looks like so, with the yellow wire going to whatever object you want to take readings from:

But I’d already made stand alone circuit boards for an assignment last semester and was able to use those. At first I had this idea of making my users play in water but I’d forgotten that the readings I get from actually being in the water are all very similar; the better variety came from being outside of it. I’d also originally wanted to do this assignment with the adafruit feather but because all of the resources I had for sweeping capacitive sensing were for the chip on the uno, figuring that out became a task for a different time.

I hooked up a button thinking I might use it as a “key” along with fingers on the class to pick the note. I started by working from the touch sensing code and trying to figure out how the different midi examples worked.


#include <SoftwareSerial.h>

#define SET(x,y) (x |=(1<<y)) //-Bit set/clear macros
#define CLR(x,y) (x &= (~(1<<y))) // |
#define CHK(x,y) (x & (1<<y)) // |
#define TOG(x,y) (x^=(1<<y)) //-+

#define N 100 //How many frequencies

float results[N]; //-Filtered result buffer
float freq[N]; //-Filtered result buffer
int sizeOfArray = N;

const int switchPin = 10;

// Variables:
byte note = 0; // The MIDI note value to be played
int waterSensorValue = 0; // value from the sensor
int lastNotePlayed = 0; // note turned on when you play w water
int lastSwitchState = 0; // state of the switch during previous time through the main loop
int currentSwitchState = 0;

//software serial
SoftwareSerial midiSerial(2, 3); // digital pins for RX & TX

/////////////////////////////SETUP////////////////////////////////

void setup() {

TCCR1A=0b10000010; //-Set up frequency generator
TCCR1B=0b00011001; //-+
ICR1=110;
OCR1A=55;

pinMode(9,OUTPUT); //-Signal generator pin
pinMode(8,OUTPUT); //-Sync (test) pin

// set the states of the I/O pins:
pinMode(switchPin, INPUT);
// Set MIDI baud rate:
Serial.begin(9600);
midiSerial.begin(31250);
}

/////////////////////////LOOP/////////////////////

void loop() {

unsigned int d;

int counter = 0;
for(unsigned int d=0; d<N; d++)
{
int v=analogRead(0); //-Read response signal

CLR(TCCR1B,0); //-Stop generator
TCNT1=0; //-Reload new frequency
ICR1=d; // |
OCR1A=d/2; //-+
SET(TCCR1B,0); //-Restart generator

results[d]=results[d]*0.5+(float)(v)*0.5; //Filter results

freq[d] = d;
}

int max_v = 0;
int max_i = 0;

for (unsigned int m=0; m<N; m++){
if ( results[m] > max_v )
{
max_v = results[m];
max_i = m;
}
}

//Serial.print(“the max value of this array is “);
//Serial.println(max_v);

waterSensorValue = max_v ;
//Serial.println(waterSensorValue);
// convert to a range from 0 to 127:
note = waterSensorValue/3;
//Serial.print(“the note is “);
//Serial.println(note);

//delay(200);

TOG(PORTB,0);

currentSwitchState = digitalRead(switchPin);
if (currentSwitchState == 1) {
if (lastSwitchState == 0) {
noteOn(0x90, note, 0x40);
lastNotePlayed = note;
}
}
else {
if (lastSwitchState == 1) {
noteOn(0x90, lastNotePlayed, 0x00);
}
}

lastSwitchState = currentSwitchState;
}

void noteOn(byte cmd, byte data1, byte data2) {
midiSerial.write(cmd);
midiSerial.write(data1);
midiSerial.write(data2);

Serial.print(“cmd: “);
Serial.print(cmd);
Serial.print(“, data1: “);
Serial.print(data1);
Serial.print(“, data2: “);
Serial.println(data2);
}


This…. worked? But was unintuitive to have to grab the glass and push the button at the same time. So I scrapped the button but then the readings you get from touching can be… unpredictable. They waver a bit so finding a way to work around that waver became my next task.


#include <SoftwareSerial.h>

#define SET(x,y) (x |=(1<<y)) //-Bit set/clear macros
#define CLR(x,y) (x &= (~(1<<y))) // |
#define CHK(x,y) (x & (1<<y)) // |
#define TOG(x,y) (x^=(1<<y)) //-+

#define N 120 //How many frequencies

float results[N]; //-Filtered result buffer
float freq[N]; //-Filtered result buffer
int sizeOfArray = N;

const int switchPin = 10; // The switch is on Arduino pin 10

// Variables:
byte note = 0; // The MIDI note value to be played
int waterSensorValue = 0; // value from the sensor
int pWaterSensorVal = 0;
int waterSensorMax = 388;
int thresh = 5;
int lastNotePlayed = 0; // note turned on when you play w water
int lastSwitchState = 0; // state of the switch during previous time through the main loop
//int currentSwitchState = 0;
int isPlaying = false;

//software serial
SoftwareSerial midiSerial(2, 3); // digital pins that we’ll use for soft serial RX & TX

/////////////////////////////SETUP////////////////////////////////

void setup() {

TCCR1A=0b10000010; //-Set up frequency generator
TCCR1B=0b00011001; //-+
ICR1=110;
OCR1A=55;

pinMode(9,OUTPUT); //-Signal generator pin
pinMode(8,OUTPUT); //-Sync (test) pin

// set the states of the I/O pins:
pinMode(switchPin, INPUT);
// Set MIDI baud rate:
Serial.begin(9600);
midiSerial.begin(31250);
}

/////////////////////////LOOP/////////////////////

void loop() {

unsigned int d;

int counter = 0;
for(unsigned int d=0; d<N; d++)
{
int v=analogRead(0); //-Read response signal

CLR(TCCR1B,0); //-Stop generator
TCNT1=0; //-Reload new frequency
ICR1=d; // |
OCR1A=d/2; //-+
SET(TCCR1B,0); //-Restart generator

results[d]=results[d]*0.5+(float)(v)*0.5; //Filter results

freq[d] = d;
}

int max_v = 0;
int max_i = 0;

for (unsigned int m=0; m<N; m++){
if ( results[m] > max_v )
{
max_v = results[m];
max_i = m;
}
}

//Serial.print(“the max value of this array is “);
//Serial.println(max_v);

waterSensorValue = max_v ;
Serial.println(waterSensorValue);
//convert to a range from 0 to 127:
note = waterSensorValue/3;

TOG(PORTB,0);
//delay (40);

if (isPlaying == false){
if (waterSensorValue < (waterSensorMax – thresh)){
isPlaying = true;
noteOn(0x90, note, 0x40);
lastNotePlayed = note;

Serial.println(“touched me like the very first time”);
Serial.print(“the note is “);
Serial.println(note);
}

pWaterSensorVal = waterSensorValue;
}

else if (isPlaying == true ){
if (waterSensorValue > (pWaterSensorVal + thresh) || waterSensorValue < (pWaterSensorVal – thresh)){
noteOn(0x90, lastNotePlayed, 0x00);
noteOn(0x90, note, 0x40);
lastNotePlayed = note;
delay(50);

Serial.println(“you changed your fingers, I changed my notes”);
Serial.print(“the note is “);
Serial.println(note);
}
if (waterSensorValue >= waterSensorMax){
isPlaying = false;
noteOn(0x90, lastNotePlayed, 0x00);
Serial.println(“no more feels?”);
Serial.println(“no more notes”);
}
pWaterSensorVal = waterSensorValue;
}

}

// plays a MIDI note. Doesn’t check to see that
// cmd is greater than 127, or that data values are less than 127:
void noteOn(byte cmd, byte data1, byte data2) {
midiSerial.write(cmd);
midiSerial.write(data1);
midiSerial.write(data2);

//prints the values in the serial monitor so we can see what note we’re playing
Serial.print(“cmd: “);
Serial.print(cmd);
Serial.print(“, data1: “);
Serial.print(data1);
Serial.print(“, data2: “);
Serial.println(data2);

}


A very tiny hole in the bottom, a wire, and some hot glue gives this midi controller some form.