Day 48 @ ITP: Phys Comp

Week 8
Midterm project w/ Jim Schmitz: 

 
midimeditation.jpg
 

Yesterday we soldered the buttons to the cardboard box that we are using as an enclosure, and today we finished putting it together. We also designed a label prototype, printed it on the ITP printer and glued it on. We braided a longer cord for the pulse rate sensor, so it can now be held as far as around 4 feet away from the instrument. I was thinking then it could also potentially be used on different parts of the body or pressure points. The enclosure has 3 toggle buttons and one switch that all trigger different MIDI commands to change: the key (button #1), instrument (button #2), add sustain (the switch), or to turn off all sounds (button #3 at the top right). Everything works through the "MIDI Hairless" software which was recommended in the book we are reading for this project, but is not working entirely yet using Omnisphere on my laptop, which is where we want to play the sounds from...we are having issues particularly with the program change or "voice" button to change the instrument, but I think if we redo the code in some way we can get it to work to toggle through different sounds...it just isn't working the way we currently have it coded. So tomorrow we will look at that before the presentations on Wednesday. We also plan to look into getting it working for at least both mine and Jim's heart rates (my heart rate graph comes out low, his is higher) and will also experiment meditating with it! And go over explaining the code and how it works so that I can explain that part on Wednesday. I actually think that Jim did a really good job explaining it and hope I remember it correctly. At the beginning he explained a lot and and towards the end of programming the buttons I was adding them myself, adding the variables and sending the MIDI commands and telling it which pins to communicate with for each button. I think before it was kind of seeping it but it took working on something like this to get some things to stick. And I soldered for the first time this weekend. I'm quite happy with the concept of our project and hope we can get it to work the way we intended. I also would like to record some audio and/or video from the MIDI Meditation device to share here...

 
 

Current code: 

// define user constants
#define midiChannel (byte)0  // Channel 1
#define SPAN 300
#define VOLUME 127

// declare variables
float valEMA;
float alpha;
boolean beat;
boolean sustainOn;
boolean noteOn;
boolean voiceButtonOn;
boolean noteButtonOn;
boolean offButtonOn;
long noteOffTime;
const int sustainPin = 13;
const int voicePin = 9;
const int notePin = 12;
const int offPin = 10;
int voiceNumber;
int noteNumber;
int voiceList[] = {1, 2, 3};

void setup() {
  Serial.begin(115200);

  pinMode(sustainPin, INPUT); // configure sustain for reading later
  pinMode(voicePin, INPUT); // configure voice for reading later
  pinMode(notePin, INPUT); // configure note for reading later
  pinMode(offPin, INPUT); // configure off button for reading later

  // initialize variables
  valEMA = 512;
  alpha = 2.0 / (SPAN + 1);
  beat = false;
  noteOn = false;
  noteOffTime = 0;
  sustainOn = false;
  voiceNumber = 0;
  voiceButtonOn = false;
  noteNumber = 50;
  noteButtonOn = false;
  offButtonOn = false;
}

void loop() {
  // read heartbeat monitor
  int val = analogRead(A0);

  // update moving average
  valEMA = alpha * val + (1 - alpha) * valEMA;

  // is the new reading significantly above the moving average?
  // if so, this spike means the heart is beating
  if (val > valEMA + 75) {
    // have we not already detected this beat?
    if (!beat) {
      // note on
      commandSend(0x90, noteNumber, VOLUME);
      // schedule time to turn off note
      noteOffTime = millis() + 200;
      // update state variables
      noteOn = true;
      beat = true;
    }
    // has the current reading dropped down below the moving average?
    // if so, this beat has ended
  } else if (val < valEMA) {
    beat = false;
  }

  // if the note is playing and the clock time is after the scheduled time
  // for turning off the note, turn it off
  if (noteOn && millis() > noteOffTime) {
    // note off
    commandSend(0x80, noteNumber, VOLUME);
    // update state variables
    noteOn = false;
  }

  // TODO: read other buttons and compare to state. send MIDI messages where necessary
  int sustainRead = digitalRead(sustainPin);
  if (sustainOn == false && sustainRead == HIGH) {
    commandSend(0xB0, 64, 127);
    sustainOn = true;
  } else if (sustainOn == true && sustainRead == LOW) {
    commandSend(0xB0, 64, 0);
    sustainOn = false;
  }

  int voicePress = digitalRead(voicePin);
  if (voiceButtonOn == false && voicePress == HIGH) {
    voiceNumber++;
    if (voiceNumber >= sizeof(voiceList) / 2) {
      voiceNumber = 0;
    }
    commandSend(0xC0, voiceList[voiceNumber]);
    voiceButtonOn = true;
  } else if (voiceButtonOn == true && voicePress == LOW) {
    voiceButtonOn = false;
  }

  int notePress = digitalRead(notePin);
  if (noteButtonOn == false && notePress == HIGH) {
    noteNumber++;
    if (noteNumber > 62) {
      noteNumber = 50;
    }
    noteButtonOn = true;
  } else if (noteButtonOn == true && notePress == LOW) {
    noteButtonOn = false;
  }

    int offButtonRead = digitalRead(offPin);
  if (offButtonOn == false && offButtonRead == HIGH) {
    commandSend(0xB0, 120, 0);
    offButtonOn = true;
  } else if (offButtonOn == true && offButtonRead == LOW) {
    offButtonOn = false;

    }


  // pause 10 ms
  delay(10);
}

/*
   Send MIDI command with one data value
*/
void commandSend(char cmd, char data1) {
  cmd = cmd | char(midiChannel);
  Serial.write(cmd);
  Serial.write(data1);
}

/*
   Send MIDI command with two data values
*/

void commandSend(char cmd, char data1, char data2) {
  cmd = cmd | char(midiChannel);
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}