/*Benchmark MIDI Send Times
  By Benjamin G. Schultz
  July 2017

  Sends a digital trigger (LOW/HIGH) to test the sending and sent time of MIDI messages.
  Connect the device that receives the digital trigger via pin 9 (we used a sound card).
  Connect the MIDI cable via pin 14 (TX3).

  See Schultz (2018) for more details, or contact benjamin.g.schultz@gmail.com

  References:
  Schultz, B. G. (2018). The Schultz MIDI benchmarking toolbox for MIDI interfaces, percussion pads, and sound cards. Behav. Res. Meth. 

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

*/

//  SSET VARIABLES

// variables for MIDI
int note = 84; // defines the frequency (i.e., pitch) of the tone (in Hz)
int engage = 144; //10010000 in binary, MIDI on signal
//int engage = 153; //10011001 in binary, on signal for drums
int cease = 128; // 10000000 in binary, MIDI off signal
int vel = 127;
int off_vel = 0;
unsigned long time_tol = 0; // preset the exact time from which it is ok to make another sound
int tone_dur = 20; // defines the duration of the tone
unsigned long tone_tol = 0; // presets the tone offset time

// variables for pwm
int pwmPin = 9;
int pwm_val = LOW;

// variables for benchmark
unsigned long delay_interval = 5; // Interval between sends
unsigned long num_repetitions = 4002; // Number of on and off signals sent

// SETUP
void setup() {
  Serial.begin(9600); // slow speed debugging
  
  Serial3.begin(31250); // MIDI default
  //Serial3.begin(62500); // Double Speed
  //Serial3.begin(46875); // 150% Speed
  //Serial3.begin(15625); // Half Speed

  pinMode(pwmPin, OUTPUT);
  digitalWrite(pwmPin, LOW);

}

// MAIN LOOP
void loop(void) {

  //Wait for user input
  while (Serial.available() == 0) {           
    // only start when something is sent via Serial Monitor
  }
  // Flush the queue
  Serial.read();
  Serial.flush();

  // Let the user know the benchmark is about to begin
  Serial.println("Starting MIDI Benchmark");
  
  // Wait 50 milliseconds before beginning
  time_tol = millis()+50;

  for (unsigned long i = 0; i < num_repetitions + 1; i++) {

    //// DEBUGGING
    //Serial.println(i);
    //Serial.print("Note: ");
    //Serial.print(note);
    //// END DEBUGGING

    while (millis() < time_tol) {
      // wait until delay time
    }

    time_tol = millis() + delay_interval;

    digitalWrite(pwmPin, HIGH); // change PWM output to ON
    noteOn(engage, note, vel); // Send note
    digitalWrite(pwmPin, LOW); // change PWM output to OFF

    while (millis() < time_tol) {
      // wait until delay time
    }

    time_tol = millis() + delay_interval;

    digitalWrite(pwmPin, HIGH); // change PWM output to ON    
    noteOn(engage, note, off_vel); // turn note off
    digitalWrite(pwmPin, LOW); // change PWM output to ON

  }

  // Tell user that benchmark is complete
  Serial.println("MIDI Benchmark Complete!");

}

// FUNCTIONS
//  Plays a MIDI note (or drum) of given pitch and velocity.  
void noteOn(int cmd, int pitch, int velocity) {
  Serial3.write(cmd);
  Serial3.write(pitch);
  Serial3.write(velocity);
}

