Code button problem

:grinning: I am using this code to stop and start a midi sequencer. It also outputs a sync pulse which works very well. However, the stop start button only controls midi and not the sync pulse. Can someone please help me modify the code so that midi and sync pulse output are both controlled with the start stop button?

#include <TimerOne.h>

/*
 * For all features: if you do not define the pin, the feature will be disabled!
 */

/*
 * FEATURE: TAP BPM INPUT
 */
#define TAP_PIN 2
#define TAP_PIN_POLARITY RISING

#define MINIMUM_TAPS 4
#define EXIT_MARGIN 150 // If no tap after 150% of last tap interval -> measure and set

/*
 * FEATURE: DIMMER BPM INPUT
 */
 #define DIMMER_INPUT_PIN A0

#define DIMMER_CHANGE_MARGIN 20 // Big value to make sure this doesn't interfere. Tweak as needed.

/*
 * FEATURE: DIMMER BPM INCREASE/DECREASE
 */
//#define DIMMER_CHANGE_PIN A1
//#define DEAD_ZONE 50
//#define CHANGE_THRESHOLD 5000
//#define RATE_DIVISOR 30

/*
 * FEATURE: BLINK TEMPO LED
 */
#define BLINK_OUTPUT_PIN 5 // 5
#define BLINK_PIN_POLARITY 0  // 0 = POSITIVE, 255 - NEGATIVE
#define BLINK_TIME 4 // How long to keep LED lit in CLOCK counts (so range is [0,24])

/*
 * FEATURE: SYNC PULSE OUTPUT
 */
#define SYNC_OUTPUT_PIN 9 // Can be used to drive sync analog sequencer (Korg Monotribe etc ...)
#define SYNC_PIN_POLARITY 0 // 0 = POSITIVE, 255 - NEGATIVE

/*
 * FEATURE: Send MIDI start/stop
 */
#define START_STOP_INPUT_PIN 7
#define START_STOP_PIN_POLARITY 0 // 0 = POSITIVE, 1024 = NEGATIVE

#define MIDI_START 0xFA
#define MIDI_STOP 0xFC

#define DEBOUNCE_INTERVAL 500L // Milliseconds

/*
 * FEATURE: EEPROM BPM storage
 */
#define EEPROM_ADDRESS 0 // Where to save BPM
#ifdef EEPROM_ADDRESS
#include <EEPROM.h>
#endif

/*
 * FEATURE: MIDI forwarding
 */
#define MIDI_FORWARD

/*
 * FEATURE: TM1637 display BPM output
 */
#define TM1637_DISPLAY
#ifdef TM1637_DISPLAY
#include <TM1637Display.h>
#define TM1637_CLK_PIN 3
#define TM1637_DIO_PIN 4
#define TM1637_BRIGHTNESS 0x0f
#endif

/*
 * GENERAL PARAMETERS
 */
#define MIDI_TIMING_CLOCK 0xF8
#define CLOCKS_PER_BEAT 24
#define MINIMUM_BPM 400 // Used for debouncing
#define MAXIMUM_BPM 3000 // Used for debouncing

long intervalMicroSeconds;
int bpm;  // BPM in tenths of a BPM!!

boolean initialized = false;
long minimumTapInterval = 60L * 1000 * 1000 * 10 / MAXIMUM_BPM; // 10
long maximumTapInterval = 60L * 1000 * 1000 * 10 / MINIMUM_BPM; // 10

volatile long firstTapTime = 0;
volatile long lastTapTime = 0;
volatile long timesTapped = 0;

volatile int blinkCount = 0;

int lastDimmerValue = 0;

boolean playing = false;
long lastStartStopTime = 0;

#ifdef TM1637_DISPLAY
TM1637Display display(TM1637_CLK_PIN, TM1637_DIO_PIN);
uint8_t tm1637_data[4] = {0x00, 0x00, 0x00, 0x00};
#endif

#ifdef DIMMER_CHANGE_PIN
long changeValue = 0;
#endif

void setup() {
  Serial.begin(38400);
  //  Set MIDI baud rate:
  Serial1.begin(31250);

  // Set pin modes
#ifdef BLINK_OUTPUT_PIN
  pinMode(BLINK_OUTPUT_PIN, OUTPUT);
#endif
#ifdef SYNC_OUTPUT_PIN
  pinMode(SYNC_OUTPUT_PIN, OUTPUT);
#endif
#ifdef DIMMER_INPUT_PIN
  pinMode(DIMMER_INPUT_PIN, INPUT);
#endif
#ifdef START_STOP_INPUT_PIN
  pinMode(START_STOP_INPUT_PIN, INPUT);
#endif

#ifdef EEPROM_ADDRESS
  // Get the saved BPM value from 2 stored bytes: MSB LSB
  bpm = EEPROM.read(EEPROM_ADDRESS) << 8;
  bpm += EEPROM.read(EEPROM_ADDRESS + 1);
  if (bpm < MINIMUM_BPM || bpm > MAXIMUM_BPM) {
    bpm = 1200; // 1200
  }
#endif

#ifdef TAP_PIN
  // Interrupt for catching tap events
  attachInterrupt(digitalPinToInterrupt(TAP_PIN), tapInput, TAP_PIN_POLARITY);
#endif

  // Attach the interrupt to send the MIDI clock and start the timer
  Timer1.initialize(intervalMicroSeconds);
  Timer1.setPeriod(calculateIntervalMicroSecs(bpm));
  Timer1.attachInterrupt(sendClockPulse);

#ifdef DIMMER_INPUT_PIN
  // Initialize dimmer value
  lastDimmerValue = analogRead(DIMMER_INPUT_PIN);
#endif

#ifdef TM1637_DISPLAY
  display.setBrightness(TM1637_BRIGHTNESS);
  setDisplayValue(bpm);
#endif
}

void loop() {
  long now = micros();

#ifdef TAP_PIN
  /*
   * Handle tapping of the tap tempo button
   */
  if (timesTapped > 0 && timesTapped < MINIMUM_TAPS && (now - lastTapTime) > maximumTapInterval) {
    // Single taps, not enough to calculate a BPM -> ignore!
    //    Serial.println("Ignoring lone taps!");
    timesTapped = 0;
  } else if (timesTapped >= MINIMUM_TAPS) {
    long avgTapInterval = (lastTapTime - firstTapTime) / (timesTapped - 1);
    if ((now - lastTapTime) > (avgTapInterval * EXIT_MARGIN / 100)) {
      bpm = 60L * 1000 * 1000 * 10 / avgTapInterval; // 10 Change this number to alter tap (1/4, 1/8 etc!)
      updateBpm(now);
  
      // Update blinkCount to make sure LED blink matches tapped beat
      blinkCount = ((now - lastTapTime) * 24 / avgTapInterval) % CLOCKS_PER_BEAT;

      timesTapped = 0;
    }
  }
#endif

#ifdef DIMMER_INPUT_PIN
  /*
   * Handle change of the dimmer input
   */
  int curDimValue = analogRead(DIMMER_INPUT_PIN);
  if (curDimValue > lastDimmerValue + DIMMER_CHANGE_MARGIN
      || curDimValue < lastDimmerValue - DIMMER_CHANGE_MARGIN) {
    // We've got movement!!
    bpm = map(curDimValue, 0, 1024, MINIMUM_BPM, MAXIMUM_BPM);

    updateBpm(now);
    lastDimmerValue = curDimValue;
  }
#endif

#ifdef DIMMER_CHANGE_PIN
  int curDimValue = analogRead(DIMMER_CHANGE_PIN);
  if (bpm > MINIMUM_BPM && curDimValue < (512 - DEAD_ZONE)) {
    int val = (512 - DEAD_ZONE - curDimValue) / RATE_DIVISOR;
    changeValue += val * val;
  } else if (bpm < MAXIMUM_BPM && curDimValue > (512 + DEAD_ZONE)) {
    int val = (curDimValue - 512 - DEAD_ZONE) / RATE_DIVISOR;
    changeValue += val * val;
  } else {
    changeValue = 0;
  }
  if (changeValue > CHANGE_THRESHOLD) {
    bpm += curDimValue < 512 ? -1 : 1;
    updateBpm(now);
    changeValue = 0;
  }
#endif

#ifdef START_STOP_INPUT_PIN
  /*
   * Check for start/stop button pressed
   */
  boolean startStopPressed =  digitalRead(START_STOP_INPUT_PIN) == HIGH;
  if (startStopPressed && (lastStartStopTime + (DEBOUNCE_INTERVAL * 1000)) < now) {
    startOrStop();
    lastStartStopTime = now;
  }
#endif

#ifdef MIDI_FORWARD
  /*
   * Forward received serial data
   */
  while (Serial1.available()) {
    int b = Serial1.read();
    Serial1.write(b);
  }
#endif
}

void tapInput() {
  long now = micros();
  if (now - lastTapTime < minimumTapInterval) {
    return; // Debounce
  }

  if (timesTapped == 0) {
    firstTapTime = now;
  }

  timesTapped++;
  lastTapTime = now;
  Serial.println("Tap!");
}

void startOrStop() {
  if (!playing) {
    Serial.println("Start playing");
    Serial1.write(MIDI_START);
  } else {
    Serial.println("Stop playing");
    Serial1.write(MIDI_STOP);
  }
  playing = !playing;
}

void sendClockPulse() {
  // Write the timing clock byte
  Serial1.write(MIDI_TIMING_CLOCK);

  blinkCount = (blinkCount + 1) % 12; //CLOCKS_PER_BEAT;
  if (blinkCount == 0) {
    // Turn led on
#ifdef BLINK_OUTPUT_PIN
    analogWrite(BLINK_OUTPUT_PIN, 255 - BLINK_PIN_POLARITY);
#endif

#ifdef SYNC_OUTPUT_PIN
    // Set sync pin to HIGH
    analogWrite(SYNC_OUTPUT_PIN, 255 - SYNC_PIN_POLARITY);
#endif
  } else {
#ifdef SYNC_OUTPUT_PIN
    if (blinkCount == 1) {
      // Set sync pin to LOW
      analogWrite(SYNC_OUTPUT_PIN, 0 + SYNC_PIN_POLARITY);
    }
#endif
#ifdef BLINK_OUTPUT_PIN
    if (blinkCount == BLINK_TIME) {
      // Turn led on
      analogWrite(BLINK_OUTPUT_PIN, 0 + BLINK_PIN_POLARITY);
    }
#endif
  }
}

void updateBpm(long now) {
  // Update the timer
  long interval = calculateIntervalMicroSecs(bpm);
  Timer1.setPeriod(interval);

#ifdef EEPROM_ADDRESS
  // Save the BPM in 2 bytes, MSB LSB
  EEPROM.write(EEPROM_ADDRESS, bpm / 256);
  EEPROM.write(EEPROM_ADDRESS + 1, bpm % 256);
#endif

  Serial.print("Set BPM to: ");
  Serial.print(bpm / 10); // 10
  Serial.print('.');
  Serial.println(bpm % 10);

#ifdef TM1637_DISPLAY
  setDisplayValue(bpm);
#endif
}

long calculateIntervalMicroSecs(int bpm) {
  // Take care about overflows!
  return 60L * 1000 * 1000 * 10 / bpm / CLOCKS_PER_BEAT; // 10 before bpm
}

#ifdef TM1637_DISPLAY
void setDisplayValue(int value) {
  tm1637_data[0] = value >= 1000 ? display.encodeDigit(value / 1000) : 0x00;
  tm1637_data[1] = value >= 100 ? display.encodeDigit((value / 100) % 10) : 0x00;
  tm1637_data[2] = value >= 10 ? display.encodeDigit((value / 10) % 10) : 0x00;
  tm1637_data[3] = display.encodeDigit(value % 10);
  display.setSegments(tm1637_data);
}
#endif

According the to TimerOne library, there are .start(), .stop(), .resume() functions which would probably do what you want. Have you tried them?

looks like when the START_STOP_INPUT_PIN toggles, startOrStop() is invoked which toggles the MIDI_START pin and toggle playing which isn't used elsewhere.

i don't see any actions associated with "sync pulse"

Thanks for your help... If I understand correctly, should this part be placed inside its own function?

blinkCount = (blinkCount + 1) % 12; //CLOCKS_PER_BEAT;
  if (blinkCount == 0) {
    // Turn led on
#ifdef BLINK_OUTPUT_PIN
    analogWrite(BLINK_OUTPUT_PIN, 255 - BLINK_PIN_POLARITY);
#endif

#ifdef SYNC_OUTPUT_PIN
    // Set sync pin to HIGH
    analogWrite(SYNC_OUTPUT_PIN, 255 - SYNC_PIN_POLARITY);
#endif
  } else {
#ifdef SYNC_OUTPUT_PIN
    if (blinkCount == 1) {
      // Set sync pin to LOW
      analogWrite(SYNC_OUTPUT_PIN, 0 + SYNC_PIN_POLARITY);
    }
#endif
#ifdef BLINK_OUTPUT_PIN
    if (blinkCount == BLINK_TIME) {
      // Turn led on
      analogWrite(BLINK_OUTPUT_PIN, 0 + BLINK_PIN_POLARITY);
    }
#endif
  }
}

Am I correct in understanding that when the button is pressed this function void startOrStop() is called? and that I need to create a new function to control the sync output pin at the same time?

After a little experimentation I've kept the blink output within the original void sendClockPulse() I want to keep the LED's visual pulse constantly operating regardless of whether the button is pressed or not.

void sendClockPulse() {
  // Write the timing clock byte
  Serial1.write(MIDI_TIMING_CLOCK);

  blinkCount = (blinkCount + 1) % 12; //CLOCKS_PER_BEAT;
  if (blinkCount == 0) {
    // Turn led on
#ifdef BLINK_OUTPUT_PIN
    analogWrite(BLINK_OUTPUT_PIN, 255 - BLINK_PIN_POLARITY);
#endif
  } else {
#ifdef BLINK_OUTPUT_PIN
    if (blinkCount == BLINK_TIME) {
      // Turn led on
      analogWrite(BLINK_OUTPUT_PIN, 0 + BLINK_PIN_POLARITY);
    }
#endif
  }
}

I have extracted sync output from it though to create a new separate function.

void sendSyncPulse() {

  blinkCount = (blinkCount + 1) % 12; //CLOCKS_PER_BEAT;
  if (blinkCount == 0) {

#ifdef SYNC_OUTPUT_PIN
    // Set sync pin to HIGH
    analogWrite(SYNC_OUTPUT_PIN, 255 - SYNC_PIN_POLARITY);
#endif
  } else {
#ifdef SYNC_OUTPUT_PIN
    if (blinkCount == BLINK_TIME) {
      // Set sync pin to LOW
      analogWrite(SYNC_OUTPUT_PIN, 0 + SYNC_PIN_POLARITY);
    }
#endif
  }
}

If this is correct, how do I call this within void startOrStop()

it's not clear how your code works.

you could

void startOrStop() {
    if (!playing) {
        Serial.println("Start playing");
        Serial1.write(MIDI_START);
    } else {
        Serial.println("Stop playing");
        Serial1.write(MIDI_STOP);
    }
    playing = !playing;

    sendClockPulse();
}

but it's not clear if sendClockPulse() just needs to be done once when the button is pressed or if it needs to be invoked periodically. it looks like that function may be triggered by an interrupt

    Timer1.attachInterrupt(sendClockPulse);

should the Timer1 interrupt be disabled when not playing? i don't know how this code is intended to work

I can't say either as I never wrote it and my skills aren't great with programming. Essentially the sync out pin is giving me a pulse which I'm using to start and stop a sequencer that only requires that simplicity. I just need to turn that pin on or off somehow when the button is pressed.

just start/stop Timer1 like I said in reply #2

void startOrStop() {
    if (!playing) {
        Serial.println("Start playing");
        Serial1.write(MIDI_START);
        Timer1.start();
    } else {
        Serial.println("Stop playing");
        Serial1.write(MIDI_STOP);
        Timer1.stop();
    }
    playing = !playing;
}

Ok thanks blh64. I wasn't sure how to apply what you had meant but I see it now. Ok, so I tried that and it works. However, the blink output and the sync output now go out of time with the midi or rather, they don't start in time with the midi on each button press. I'm wondering if Timer1 shouldn't be stopped because of this but more specifically be able to stop blink and sync output by turning off the pins? Does that make sense?

In that case, keep the timer running but use the value if playing to decide if you will set the sync pin or not

void sendClockPulse() {
  // Write the timing clock byte
  Serial1.write(MIDI_TIMING_CLOCK);

  blinkCount = (blinkCount + 1) % 12; //CLOCKS_PER_BEAT;
  if (blinkCount == 0) {
    // Turn led on
#ifdef BLINK_OUTPUT_PIN
    analogWrite(BLINK_OUTPUT_PIN, 255 - BLINK_PIN_POLARITY);
#endif

#ifdef SYNC_OUTPUT_PIN
    // Set sync pin to HIGH
  if ( playing ) analogWrite(SYNC_OUTPUT_PIN, 255 - SYNC_PIN_POLARITY);
#endif
  } else {
#ifdef SYNC_OUTPUT_PIN
    if (blinkCount == 1) {
      // Set sync pin to LOW
      analogWrite(SYNC_OUTPUT_PIN, 0 + SYNC_PIN_POLARITY);
    }
#endif
#ifdef BLINK_OUTPUT_PIN
    if (blinkCount == BLINK_TIME) {
      // Turn led on
      analogWrite(BLINK_OUTPUT_PIN, 0 + BLINK_PIN_POLARITY);
    }
#endif
  }
}

Thanks blh64. That also works. However, I realize there is a flaw in this program altogether. When the button is pressed, midi begins immediately, irrespective of the pulse from the sync output. For devices connected to the sync output and midi to start on the first beat of a sequence together, midi out would have to wait until sync out is at 5v. Does that make sense?

maybe the midi should wait for sync to be pulsed.

start enables Timer1 which also sets the midi.

stop disables Timer1 as well as disabling midi

I think the problem is the variable blinkCount. It needs to get reset to 0 when you start so you do get a sync pulse when MIDI starts...
[edit] blinkCount needs to be reset to 11 so it gets incremented and %12 which will be 0 and force a synce pulse

#include <TimerOne.h>

/*
   For all features: if you do not define the pin, the feature will be disabled!
*/

/*
   FEATURE: TAP BPM INPUT
*/
#define TAP_PIN 2
#define TAP_PIN_POLARITY RISING

#define MINIMUM_TAPS 4
#define EXIT_MARGIN 150 // If no tap after 150% of last tap interval -> measure and set

/*
   FEATURE: DIMMER BPM INPUT
*/
#define DIMMER_INPUT_PIN A0

#define DIMMER_CHANGE_MARGIN 20 // Big value to make sure this doesn't interfere. Tweak as needed.

/*
   FEATURE: DIMMER BPM INCREASE/DECREASE
*/
//#define DIMMER_CHANGE_PIN A1
//#define DEAD_ZONE 50
//#define CHANGE_THRESHOLD 5000
//#define RATE_DIVISOR 30

/*
   FEATURE: BLINK TEMPO LED
*/
#define BLINK_OUTPUT_PIN 5 // 5
#define BLINK_PIN_POLARITY 0  // 0 = POSITIVE, 255 - NEGATIVE
#define BLINK_TIME 4 // How long to keep LED lit in CLOCK counts (so range is [0,24])

/*
   FEATURE: SYNC PULSE OUTPUT
*/
#define SYNC_OUTPUT_PIN 9 // Can be used to drive sync analog sequencer (Korg Monotribe etc ...)
#define SYNC_PIN_POLARITY 0 // 0 = POSITIVE, 255 - NEGATIVE

/*
   FEATURE: Send MIDI start/stop
*/
#define START_STOP_INPUT_PIN 7
#define START_STOP_PIN_POLARITY 0 // 0 = POSITIVE, 1024 = NEGATIVE

#define MIDI_START 0xFA
#define MIDI_STOP 0xFC

#define DEBOUNCE_INTERVAL 500L // Milliseconds

/*
   FEATURE: EEPROM BPM storage
*/
#define EEPROM_ADDRESS 0 // Where to save BPM
#ifdef EEPROM_ADDRESS
#include <EEPROM.h>
#endif

/*
   FEATURE: MIDI forwarding
*/
#define MIDI_FORWARD

/*
   FEATURE: TM1637 display BPM output
*/
#define TM1637_DISPLAY
#ifdef TM1637_DISPLAY
#include <TM1637Display.h>
#define TM1637_CLK_PIN 3
#define TM1637_DIO_PIN 4
#define TM1637_BRIGHTNESS 0x0f
#endif

/*
   GENERAL PARAMETERS
*/
#define MIDI_TIMING_CLOCK 0xF8
#define CLOCKS_PER_BEAT 24
#define MINIMUM_BPM 400 // Used for debouncing
#define MAXIMUM_BPM 3000 // Used for debouncing

long intervalMicroSeconds;
int bpm;  // BPM in tenths of a BPM!!

boolean initialized = false;
long minimumTapInterval = 60L * 1000 * 1000 * 10 / MAXIMUM_BPM; // 10
long maximumTapInterval = 60L * 1000 * 1000 * 10 / MINIMUM_BPM; // 10

volatile long firstTapTime = 0;
volatile long lastTapTime = 0;
volatile long timesTapped = 0;

volatile int blinkCount = 0;

int lastDimmerValue = 0;

boolean playing = false;
long lastStartStopTime = 0;

#ifdef TM1637_DISPLAY
TM1637Display display(TM1637_CLK_PIN, TM1637_DIO_PIN);
uint8_t tm1637_data[4] = {0x00, 0x00, 0x00, 0x00};
#endif

#ifdef DIMMER_CHANGE_PIN
long changeValue = 0;
#endif

void setup() {
  Serial.begin(38400);
  //  Set MIDI baud rate:
  Serial1.begin(31250);

  // Set pin modes
#ifdef BLINK_OUTPUT_PIN
  pinMode(BLINK_OUTPUT_PIN, OUTPUT);
#endif
#ifdef SYNC_OUTPUT_PIN
  pinMode(SYNC_OUTPUT_PIN, OUTPUT);
#endif
#ifdef DIMMER_INPUT_PIN
  pinMode(DIMMER_INPUT_PIN, INPUT);
#endif
#ifdef START_STOP_INPUT_PIN
  pinMode(START_STOP_INPUT_PIN, INPUT);
#endif

#ifdef EEPROM_ADDRESS
  // Get the saved BPM value from 2 stored bytes: MSB LSB
  bpm = EEPROM.read(EEPROM_ADDRESS) << 8;
  bpm += EEPROM.read(EEPROM_ADDRESS + 1);
  if (bpm < MINIMUM_BPM || bpm > MAXIMUM_BPM) {
    bpm = 1200; // 1200
  }
#endif

#ifdef TAP_PIN
  // Interrupt for catching tap events
  attachInterrupt(digitalPinToInterrupt(TAP_PIN), tapInput, TAP_PIN_POLARITY);
#endif

  // Attach the interrupt to send the MIDI clock and start the timer
  Timer1.initialize(intervalMicroSeconds);
  Timer1.setPeriod(calculateIntervalMicroSecs(bpm));
  Timer1.attachInterrupt(sendClockPulse);

#ifdef DIMMER_INPUT_PIN
  // Initialize dimmer value
  lastDimmerValue = analogRead(DIMMER_INPUT_PIN);
#endif

#ifdef TM1637_DISPLAY
  display.setBrightness(TM1637_BRIGHTNESS);
  setDisplayValue(bpm);
#endif
}

void loop() {
  long now = micros();

#ifdef TAP_PIN
  /*
     Handle tapping of the tap tempo button
  */
  if (timesTapped > 0 && timesTapped < MINIMUM_TAPS && (now - lastTapTime) > maximumTapInterval) {
    // Single taps, not enough to calculate a BPM -> ignore!
    //    Serial.println("Ignoring lone taps!");
    timesTapped = 0;
  } else if (timesTapped >= MINIMUM_TAPS) {
    long avgTapInterval = (lastTapTime - firstTapTime) / (timesTapped - 1);
    if ((now - lastTapTime) > (avgTapInterval * EXIT_MARGIN / 100)) {
      bpm = 60L * 1000 * 1000 * 10 / avgTapInterval; // 10 Change this number to alter tap (1/4, 1/8 etc!)
      updateBpm(now);

      // Update blinkCount to make sure LED blink matches tapped beat
      blinkCount = ((now - lastTapTime) * 24 / avgTapInterval) % CLOCKS_PER_BEAT;

      timesTapped = 0;
    }
  }
#endif

#ifdef DIMMER_INPUT_PIN
  /*
     Handle change of the dimmer input
  */
  int curDimValue = analogRead(DIMMER_INPUT_PIN);
  if (curDimValue > lastDimmerValue + DIMMER_CHANGE_MARGIN
      || curDimValue < lastDimmerValue - DIMMER_CHANGE_MARGIN) {
    // We've got movement!!
    bpm = map(curDimValue, 0, 1024, MINIMUM_BPM, MAXIMUM_BPM);

    updateBpm(now);
    lastDimmerValue = curDimValue;
  }
#endif

#ifdef DIMMER_CHANGE_PIN
  int curDimValue = analogRead(DIMMER_CHANGE_PIN);
  if (bpm > MINIMUM_BPM && curDimValue < (512 - DEAD_ZONE)) {
    int val = (512 - DEAD_ZONE - curDimValue) / RATE_DIVISOR;
    changeValue += val * val;
  } else if (bpm < MAXIMUM_BPM && curDimValue > (512 + DEAD_ZONE)) {
    int val = (curDimValue - 512 - DEAD_ZONE) / RATE_DIVISOR;
    changeValue += val * val;
  } else {
    changeValue = 0;
  }
  if (changeValue > CHANGE_THRESHOLD) {
    bpm += curDimValue < 512 ? -1 : 1;
    updateBpm(now);
    changeValue = 0;
  }
#endif

#ifdef START_STOP_INPUT_PIN
  /*
     Check for start/stop button pressed
  */
  boolean startStopPressed =  digitalRead(START_STOP_INPUT_PIN) == HIGH;
  if (startStopPressed && (lastStartStopTime + (DEBOUNCE_INTERVAL * 1000)) < now) {
    startOrStop();
    lastStartStopTime = now;
  }
#endif

#ifdef MIDI_FORWARD
  /*
     Forward received serial data
  */
  while (Serial1.available()) {
    int b = Serial1.read();
    Serial1.write(b);
  }
#endif
}

void tapInput() {
  long now = micros();
  if (now - lastTapTime < minimumTapInterval) {
    return; // Debounce
  }

  if (timesTapped == 0) {
    firstTapTime = now;
  }

  timesTapped++;
  lastTapTime = now;
  Serial.println("Tap!");
}

void startOrStop() {
  if (!playing) {
    Serial.println("Start playing");
    Serial1.write(MIDI_START);
    blinkCount = 11;  // force sync pulse right now
  } else {
    Serial.println("Stop playing");
    Serial1.write(MIDI_STOP);
  }
  playing = !playing;
}

void sendClockPulse() {
  // Write the timing clock byte
  Serial1.write(MIDI_TIMING_CLOCK);

  blinkCount = (blinkCount + 1) % 12; //CLOCKS_PER_BEAT;
  if (blinkCount == 0) {
    // Turn led on
#ifdef BLINK_OUTPUT_PIN
    analogWrite(BLINK_OUTPUT_PIN, 255 - BLINK_PIN_POLARITY);
#endif

#ifdef SYNC_OUTPUT_PIN
    // Set sync pin to HIGH
  if ( playing ) analogWrite(SYNC_OUTPUT_PIN, 255 - SYNC_PIN_POLARITY);
#endif
  } else {
#ifdef SYNC_OUTPUT_PIN
    if (blinkCount == 1) {
      // Set sync pin to LOW
      analogWrite(SYNC_OUTPUT_PIN, 0 + SYNC_PIN_POLARITY);
    }
#endif
#ifdef BLINK_OUTPUT_PIN
    if (blinkCount == BLINK_TIME) {
      // Turn led on
      analogWrite(BLINK_OUTPUT_PIN, 0 + BLINK_PIN_POLARITY);
    }
#endif
  }
}


void updateBpm(long now) {
  // Update the timer
  long interval = calculateIntervalMicroSecs(bpm);
  Timer1.setPeriod(interval);

#ifdef EEPROM_ADDRESS
  // Save the BPM in 2 bytes, MSB LSB
  EEPROM.write(EEPROM_ADDRESS, bpm / 256);
  EEPROM.write(EEPROM_ADDRESS + 1, bpm % 256);
#endif

  Serial.print("Set BPM to: ");
  Serial.print(bpm / 10); // 10
  Serial.print('.');
  Serial.println(bpm % 10);

#ifdef TM1637_DISPLAY
  setDisplayValue(bpm);
#endif
}

long calculateIntervalMicroSecs(int bpm) {
  // Take care about overflows!
  return 60L * 1000 * 1000 * 10 / bpm / CLOCKS_PER_BEAT; // 10 before bpm
}

#ifdef TM1637_DISPLAY
void setDisplayValue(int value) {
  tm1637_data[0] = value >= 1000 ? display.encodeDigit(value / 1000) : 0x00;
  tm1637_data[1] = value >= 100 ? display.encodeDigit((value / 100) % 10) : 0x00;
  tm1637_data[2] = value >= 10 ? display.encodeDigit((value / 10) % 10) : 0x00;
  tm1637_data[3] = display.encodeDigit(value % 10);
  display.setSegments(tm1637_data);
}
#endif

edit #2. You might need to reset TimesTapped back to 0 as well when you start. If you do not, blinkCount could get altered on the next iteration of loop() before Timer1 fires and then the sync may not happen. This is all theory on my part since things would have to happen rather quickly (a couple of taps, the stop button pressed, then start).

It is just a possibility... maybe irrelevant

Thanks blh64. That works perfectly now and everything is in sync.
As you have suggested to reset TimesTapped back to 0 at the start of each button press, how might I write that in please? When the tap tempo button is pressed 4 times the new tempo causes midi and pulse to go out of sync whilst playing. I s this what you meant could happen in edit#2?

C'mon now. I believe you can figure out how to set a variable equal to 0. If you can't, you need to take some time and learn C/C++ and study the examples in the IDE.

Hint: it is at the same location you reset blinkCount.

Is it as simple as writing this... timesTapped = 0; ?

And placed here...

Serial.println("Start playing");
    Serial1.write(MIDI_START);
    blinkCount = 11; // force sync pulse right now
    timesTapped = 0;

If so, it's not working but probably because I've got it wrong. Thanks for the push!

Must timesTapped be reset to zero in an "if" statement? Such as this?

if (timesTapped > 0) { 
      timesTapped = 0;  
    } else {
      timesTapped = something;
    }

And then placed within the startOrStop function? Though, blinkCount isn't being reset there is it because it's set to 11. Is that correct?

maybe the midi should wait for sync to be pulsed.

start enables Timer1 which also sets the midi.

stop disables Timer1 as well as disabling midi

I realise now after some observation that you are correct gcjr.

If midi needs to wait for sync out to be pulsed, then would something like this be correct?

if (SYNC_OUTPUT_PIN, 255) {
      Serial1.write(MIDI_START);