Tap Tempo Midi Clock

How can i get a bpm value from my tap tempo sketch?
so i can add midi clock output?

unsigned long currentTimer[2] = { 750, 750 };  /* approx 80 bpm */

void runSeq() {
  int tapState = digitalRead(FSW1);
  if ( tapState == LOW && tapState != lastTapState ) /* button up->down */
  {
    tap(); /* we got a HIGH-LOW transition, call our tap() function */
    downTime = millis();
    pressTimeout = false;
  }
  lastTapState = tapState; /* keep track of the last state, for transition detection */

  if (ledState2 > 0) // if footswitch start
  {
    /* check for timer timeout */
    if ( millis() >= timeoutTime2 ) // timeoutTime2 is 4x faster than timeoutTime
    {
      /* timeout happens */

      indicatorTimeout = millis() + 20;  /* this sets the time when the LED goes off */
      rescheduleTimer();            /* and reschedule the timer to keep the pace */
    }
   /* display the tap blink on Trellis */
    if ( millis() < indicatorTimeout)
    {
      // 750ms = 80bpm
      //MIDI.sendClock(); // = 25 bpm
      //MIDI.sendClock(); // = 50 bpm
      //MIDI.sendClock(); // = 75 bpm
      //MIDI.sendClock(); // = 100 bpm

      if (pad == held_button_id && latchingMode == true)
      {
        trellis.pixels.setPixelColor(held_button_id, 0, 255, 0);  //  Make held trellis LED green as pink traveller passes
        trellis.pixels.show();
      }
      else
      {
        trellis.pixels.setPixelColor(pad, 220, 20, 60); // The Pink Traveller
        trellis.pixels.show();
      }
    }



    if (currentPattern[pad] == 1 && latchingMode == true) // if pad is latched on in array
    {
      trellis.pixels.setPixelColor(pad, 0x0000ff); // make latched LEDs Blue again after pink traveller passes
    }
    else {
      trellis.pixels.setPixelColor(pad, 0);  //  Turn off pink traveller after it passes
    }

  } // if footswitch start






  if (ledState2 < 0) // if footswitch stop
  {
    /* check for timer timeout */
    if ( millis() >= timeoutTime ) // timeoutTime2 is 4x faster than timeoutTime
    {
      /* timeout happens */
      indicatorTimeout = millis() + 20;  /* this sets the time when the LED goes off */
      rescheduleTimer();            /* and reschedule the timer to keep the pace */
    }



    /* display the tap blink on LED  */
    if ( millis() < indicatorTimeout)
    {
      pixels.setPixelColor(0, 0, 255, 255); // Tempo LED on aqua
      pixels.show();
    }

    else {
      pixels.setPixelColor(0, 0, 0, 0);  // Tempo LED off
      pixels.show();
    }
  }
}


/****************************************************************************************************************/


void tap()
{
  /* we keep two of these around to average together later */
  currentTimer[1] = currentTimer[0];
  currentTimer[0] = millis() - lastTap; /* current = duration since last tap */
  lastTap = millis();
  timeoutTime = 0; /* force the trigger to happen immediately - sync and blink! */
  timeoutTime2 = 0; /* force the trigger to happen immediately - sync and blink! */
}


/****************************************************************************************************************/

void rescheduleTimer()
{
  /* set the timer to go off again when the time reaches the
     timeout.  The timeout is all of the "currentTimer" values averaged
     together, then added onto the current time.  When that time has been
     reached, the next tick will happen...
  */
  timeoutTime = millis() + ((currentTimer[0] + currentTimer[1]) / 2);  // Neopixel LED speed
  timeoutTime2 = millis() + ((currentTimer[0] + currentTimer[1]) / 8);  // Neotrellis speed x4 faster

  if (ledState2 > 0) // if footswitch start
  {
    pad++;
    pad %= 16;

//midi clock sketch

#include <MIDI.h>


long bpm = 120.0;
long tempo = 1000.0 / (bpm / 60.0);

float prevmillis = 0;
float interval = tempo / 24.0; //interval is the number of milliseconds defined by tempo formula.

MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  Serial.begin(9600);
  MIDI.begin(MIDI_CHANNEL_OMNI);

}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    MIDI.sendClock();
    Serial.print(interval);
    Serial.print('\n');
  }
}

Can you post a schematic showing how and what you have wired. Links to hardware technical information would also help us help you.

Not necessary, the above midi clock code works with my hardware, how to add that to my tap tempo sketch?

It is neccessary. You want answers, not guesses.

Thank you for the kind advice

this doesnt work

unsigned long currentTimer[2] = { 750, 750 };  /* 80 bpm */
void clockOut() {
  unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= currentTimer[1]) {
    //save the last time.
    prevmillis = currentMillis;
    MIDI.sendClock();
  }
}

this doesnt work

float interval = ((currentTimer[0] + currentTimer[1]) / 24.0);

Please post a complete sketch that calls clockOut() and doesn't work.

Looking at one function outside the context of a complete sketch is not helpful.

Obvsly that function works. It looks like you modeled it after the second sketch in your post, which I assume is working and you wanted us to see how it needs to work.

So you doing something wrong, or not doing something right, it seems.

a7

this gives a 60bpm output

long bpm = 60.0; // input
long tempo = 1000.0 / (bpm / 60.0); // = 1000ms
float interval = tempo / 24.0; // = 60 bpm output

but this doesnt

unsigned long currentTimer[2] = { 1000, 1000 }; // 60 bpm
float interval = currentTimer[1] / 24;

void clockOut() {
  unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    MIDI.sendClock();
  }
}

full sketch


#include <SD.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SerialFlash.h>
#include "Adafruit_NeoTrellis.h"
#include <MIDI.h>

// ----------------------------------------FSW NEOPIXELS---------------------------------------------
#include <Adafruit_NeoPixel.h>
#define PIXEL_PIN  5 // (Led Pin)
#define PIXEL_COUNT   2
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// ----------------------------------------FSW NEOPIXELS---------------------------------------------


// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioPlaySerialflashRaw  playFlashRaw0;
AudioPlaySerialflashRaw  playFlashRaw1;
AudioPlaySerialflashRaw  playFlashRaw2;
AudioPlaySerialflashRaw  playFlashRaw3;
AudioPlaySerialflashRaw  playFlashRaw4;
AudioPlaySerialflashRaw  playFlashRaw5;
AudioPlaySerialflashRaw  playFlashRaw6;
AudioPlaySerialflashRaw  playFlashRaw7;
AudioPlaySerialflashRaw  playFlashRaw8;
AudioPlaySerialflashRaw  playFlashRaw9;
AudioPlaySerialflashRaw  playFlashRaw10;
AudioPlaySerialflashRaw  playFlashRaw11;
AudioPlaySerialflashRaw  playFlashRaw12;
AudioPlaySerialflashRaw  playFlashRaw13;
AudioPlaySerialflashRaw  playFlashRaw14;
AudioPlaySerialflashRaw  playFlashRaw15;

AudioMixer4              mix1;
AudioMixer4              mix2;
AudioMixer4              mix3;
AudioMixer4              mix4;
AudioMixer4              mix5;
//AudioOutputAnalog        dac;
AudioOutputI2S           headphones;

// Create Audio connections between the components
//
AudioConnection          patchCord1(playFlashRaw0, 0, mix1, 0);
AudioConnection          patchCord2(playFlashRaw1, 0, mix1, 1);
AudioConnection          patchCord3(playFlashRaw2, 0, mix1, 2);
AudioConnection          patchCord4(playFlashRaw3, 0, mix1, 3);
AudioConnection          patchCord5(playFlashRaw4, 0, mix2, 0);
AudioConnection          patchCord6(playFlashRaw5, 0, mix2, 1);
AudioConnection          patchCord7(playFlashRaw6, 0, mix2, 2);
AudioConnection          patchCord8(playFlashRaw7, 0, mix2, 3);
AudioConnection          patchCord9(playFlashRaw8, 0, mix3, 0);
AudioConnection          patchCord10(playFlashRaw9, 0, mix3, 1);
AudioConnection          patchCord11(playFlashRaw10, 0, mix3, 2);
AudioConnection          patchCord12(playFlashRaw11, 0, mix3, 3);
AudioConnection          patchCord13(playFlashRaw12, 0, mix4, 0);
AudioConnection          patchCord14(playFlashRaw13, 0, mix4, 1);
AudioConnection          patchCord15(playFlashRaw14, 0, mix4, 2);
AudioConnection          patchCord16(playFlashRaw15, 0, mix4, 3);
AudioConnection          patchCord17(mix1, 0, mix5, 0);
AudioConnection          patchCord18(mix2, 0, mix5, 1);
AudioConnection          patchCord19(mix3, 0, mix5, 2);
AudioConnection          patchCord20(mix4, 0, mix5, 3);
//AudioConnection          patchCord21(mix5, dac);
AudioConnection          patchCord22(mix5, 0, headphones, 0);
AudioConnection          patchCord23(mix5, 0, headphones, 1);


// Create an object to control the audio shield.
//
AudioControlSGTL5000 audioShield;

const int FlashChipSelect = 6; // digital pin for flash chip CS pin



Adafruit_NeoTrellis trellis;



unsigned long previousMillis = 0; // will store last time LED was updated
const int FSW1 = 3;  // tap tempo footswitch
const int FSW2 = 2;  // Start/stop footswitch
int ledState = LOW; // ledState used to set the tempo LED
int FSW1State = 0;         // variable for reading the pushbutton status
int FSW2State = HIGH;
int ledState2 = -1; //this variable tracks the state of the LED, negative if off, positive if on
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 500;    // the debounce time; increase if the output flickers
int lastTapState = LOW;  /* the last tap button state */
unsigned long currentTimer[2] = { 1000, 1000 };  /* approx 80 bpm */
unsigned long timeoutTime = 0;  /* this is when the timer will trigger next */
unsigned long timeoutTime2 = 0;   //this is when the timer will trigger next
unsigned long downTime = 0;     /* for our delayed press reset */
unsigned long indicatorTimeout; /* for our fancy "blink" tempo indicator */
unsigned long indicatorTimeout2; //variable used to determine the duration of the pad X4 blinks on state
boolean pressTimeout = false;
unsigned long lastTap = 0; /* when the last tap happened */
elapsedMillis button_hold_counter = 0;
int8_t held_button_id = -1;
int latchingMode = false;

const byte NPATTERNS = 16;

byte patternBank[NPATTERNS][16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

int currentPattern[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

MIDI_CREATE_DEFAULT_INSTANCE();

//long bpm = 60.0;
//long tempo = 1000.0 / (bpm / 60.0); // = 1000ms

float prevmillis = 0;
float interval = currentTimer[1] / 24; //interval is the number of milliseconds defined by tempo formula.

/****************************************************************************************************************/

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);
  Serial.begin(9600);
  trellis.begin();
  trellis.pixels.setBrightness(50);
  pixels.begin(); // for start/stop and tempo LEDs
  pixels.setBrightness(50);
  pixels.setPixelColor(1, 220, 20, 60);
  pixels.show();
  pinMode(FSW1, INPUT_PULLUP);
  pinMode(FSW2, INPUT_PULLUP);
  AudioMemory(40);
  audioShield.enable();
  audioShield.volume(0.9);

  // reduce the gain on mixer channels, so more than 1
  // sound can play simultaneously without clipping
  mix1.gain(0, 0.9);
  mix1.gain(1, 0.9);
  mix1.gain(2, 0.9);
  mix1.gain(3, 0.9);
  mix2.gain(0, 0.9);
  mix2.gain(1, 0.9);
  mix2.gain(2, 0.9);
  mix2.gain(3, 1);
  mix3.gain(0, 0.9);
  mix3.gain(1, 0.9);
  mix3.gain(2, 0.9);
  mix3.gain(3, 0.7);
  mix4.gain(0, 0.9);
  mix4.gain(1, 0.9);
  mix4.gain(2, 0.9);
  mix4.gain(3, 0.9);

  mix5.gain(1, 1);
  mix5.gain(2, 1);

  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7

  SerialFlash.begin(FlashChipSelect);

  //activate momentary pads and set callbacks
  for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) {
    trellis.activateKey(i, SEESAW_KEYPAD_EDGE_RISING);
    trellis.activateKey(i, SEESAW_KEYPAD_EDGE_FALLING);
    trellis.registerCallback(i, momentary);
  }
  //do a little animation to show we're on
  for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, Wheel(map(i, 0, trellis.pixels.numPixels(), 0, 255)));
    trellis.pixels.show();
    delay(25);
  }
  for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, 0x000000);
    trellis.pixels.show();
    delay(25);
  }
}

int pad = -1;



/****************************************************************************************************************/
void clockOut() {
  unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    MIDI.sendClock();
  }
}
/****************************************************************************************************************/

void loop() {
  trellis.read();
  delay(10); // stops freeze up in stop mode when playing pads quickly
  startStopFSW();
  runSeq();
    unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    //MIDI.sendStart();
    MIDI.sendClock();
  }
}


/****************************************************************************************************************/

void startStopFSW() {
  //sample the state of the button - is it pressed or not?
  FSW2State = digitalRead(FSW2);

  //filter out any noise by setting a time buffer
  if ( (millis() - lastDebounceTime) > debounceDelay) {

    //if the button has been pressed, lets toggle the LED from "off to on" or "on to off"
    if ( (FSW2State == LOW) && (ledState2 < 0) ) {

      // turn LED lawn green:
      pixels.setPixelColor(1, 124, 252, 0);
      pixels.show();
      Serial.println("Start");
      //MIDI.sendStart();
      pad = -1;
      ledState2 = -ledState2; //now the LED is on, we need to change the state
      lastDebounceTime = millis(); //set the current time
    }
    else if ( (FSW2State == LOW) && (ledState2 > 0) ) {

      // LED crimson
      pixels.setPixelColor(1, 220, 20, 60);
      pixels.show();
      Serial.println("Stop");
      //MIDI.sendStop();
      ledState2 = -ledState2; //
      lastDebounceTime = millis(); //set the current time
    }
  }
}



/****************************************************************************************************************/

void loadKit() {

}

/****************************************************************************************************************/


void runSeq() {
  int tapState = digitalRead(FSW1);
  if ( tapState == LOW && tapState != lastTapState ) /* button up->down */
  {
    tap(); /* we got a HIGH-LOW transition, call our tap() function */
    downTime = millis();
    pressTimeout = false;
  }



  /* press-and-hold detection start */
  if ( tapState == LOW ) /* button is down... */
  {
    /* if we have not triggered before, and the down time is more than 2 seconds... */
    /* 2000 = 2000ms = 2 seconds */
    if ( !pressTimeout && ((millis() - downTime ) > 1000 ))
    {


      /* Load Kit Here */

      ledState2 = -1;
      pixels.setPixelColor(1, 220, 20, 60); // start LED off (red)
      pixels.setPixelColor(0, 20, 55, 155); // kit LED (blue)
      pixels.show();
      clearTrellis();
      trellis.pixels.setPixelColor(0, 0, 255, 0); // letter "K" (green) Load Kit Page
      trellis.pixels.setPixelColor(2, 0, 255, 0);
      trellis.pixels.setPixelColor(3, 0, 255, 0);
      trellis.pixels.setPixelColor(4, 0, 255, 0);
      trellis.pixels.setPixelColor(5, 0, 255, 0);
      trellis.pixels.setPixelColor(8, 0, 255, 0);
      trellis.pixels.setPixelColor(10, 0, 255, 0);
      trellis.pixels.setPixelColor(12, 0, 255, 0);
      trellis.pixels.setPixelColor(15, 0, 255, 0);
      trellis.pixels.show();

      /* Load Kit Here */


      currentTimer[0] = currentTimer[1]; /* dont let long press change current tempo */
      rescheduleTimer(); /* start the timer */
      pressTimeout = true; /* make sure we don't get called again during this press */
    }
  }
  /* press-and-hold detection end */



  lastTapState = tapState; /* keep track of the last state, for transition detection */

  if (ledState2 > 0) // if footswitch start
  {
    /* check for timer timeout */
    if ( millis() >= timeoutTime2 ) // timeoutTime2 is 4x faster than timeoutTime
    {
      /* timeout happens */

      indicatorTimeout = millis() + 20;  /* this sets the time when the LED goes off */
      rescheduleTimer();            /* and reschedule the timer to keep the pace */
    }



    /* display the tap blink on Trellis */
    if ( millis() < indicatorTimeout)
    {
      // 750ms = 80bpm
      //MIDI.sendClock(); // = 25 bpm
      //MIDI.sendClock(); // = 50 bpm
      //MIDI.sendClock(); // = 75 bpm
      //MIDI.sendClock(); // = 100 bpm

      if (pad == held_button_id && latchingMode == true)
      {
        trellis.pixels.setPixelColor(held_button_id, 0, 255, 0);  //  Make held trellis LED green as pink traveller passes
        trellis.pixels.show();
      }
      else
      {
        trellis.pixels.setPixelColor(pad, 220, 20, 60); // The Pink Traveller
        trellis.pixels.show();
      }
    }



    if (currentPattern[pad] == 1 && latchingMode == true) // if pad is latched on in array
    {
      trellis.pixels.setPixelColor(pad, 0x0000ff); // make latched LEDs Blue again after pink traveller passes
    }
    else {
      trellis.pixels.setPixelColor(pad, 0);  //  Turn off pink traveller after it passes
    }

  } // if footswitch start






  if (ledState2 < 0) // if footswitch stop
  {
    /* check for timer timeout */
    if ( millis() >= timeoutTime ) // timeoutTime2 is 4x faster than timeoutTime
    {
      /* timeout happens */
      indicatorTimeout = millis() + 20;  /* this sets the time when the LED goes off */
      rescheduleTimer();            /* and reschedule the timer to keep the pace */
    }



    /* display the tap blink on LED  */
    if ( millis() < indicatorTimeout)
    {
      pixels.setPixelColor(0, 0, 255, 255); // Tempo LED on aqua
      pixels.show();
    }

    else {
      pixels.setPixelColor(0, 0, 0, 0);  // Tempo LED off
      pixels.show();
    }
  }
}


/****************************************************************************************************************/


void tap()
{
  /* we keep two of these around to average together later */
  currentTimer[1] = currentTimer[0];
  currentTimer[0] = millis() - lastTap; /* current = duration since last tap */
  lastTap = millis();
  timeoutTime = 0; /* force the trigger to happen immediately - sync and blink! */
  timeoutTime2 = 0; /* force the trigger to happen immediately - sync and blink! */
}


/****************************************************************************************************************/

void rescheduleTimer()
{
  /* set the timer to go off again when the time reaches the
     timeout.  The timeout is all of the "currentTimer" values averaged
     together, then added onto the current time.  When that time has been
     reached, the next tick will happen...
  */
  timeoutTime = millis() + ((currentTimer[0] + currentTimer[1]) / 2);  // Neopixel LED speed
  timeoutTime2 = millis() + ((currentTimer[0] + currentTimer[1]) / 8);  // Neotrellis speed x4 faster

  if (ledState2 > 0) // if footswitch start
  {
    pad++;
    pad %= 16;

    if (patternBank[0][pad] == 1) // if pad is latched on in array
    {
      playSound(0);
    }

    if (patternBank[1][pad] == 1) // if pad is latched on in array
    {
      playSound(1);
    }

    if (patternBank[2][pad] == 1) // if pad is latched on in array
    {
      playSound(2);
    }

    if (patternBank[3][pad] == 1) // if pad is latched on in array
    {
      playSound(3);
    }

    if (patternBank[4][pad] == 1) // if pad is latched on in array
    {
      playSound(4);
    }

    if (patternBank[5][pad] == 1) // if pad is latched on in array
    {
      playSound(5);
    }

    if (patternBank[6][pad] == 1) // if pad is latched on in array
    {
      playSound(6);
    }

    if (patternBank[7][pad] == 1) // if pad is latched on in array
    {
      playSound(7);
    }

    if (patternBank[8][pad] == 1) // if pad is latched on in array
    {
      playSound(8);
    }

    if (patternBank[9][pad] == 1) // if pad is latched on in array
    {
      playSound(9);
    }

    if (patternBank[10][pad] == 1) // if pad is latched on in array
    {
      playSound(10);
    }

    if (patternBank[11][pad] == 1) // if pad is latched on in array
    {
      playSound(11);
    }

    if (patternBank[12][pad] == 1) // if pad is latched on in array
    {
      playSound(12);
    }

    if (patternBank[13][pad] == 1) // if pad is latched on in array
    {
      playSound(13);
    }

    if (patternBank[14][pad] == 1) // if pad is latched on in array
    {
      playSound(14);
    }

    if (patternBank[15][pad] == 1) // if pad is latched on in array
    {
      playSound(15);
    }
  }
}

/****************************************************************************************************************/


void clearTrellis() {

  for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, 0); // all trellis leds off
  }
}



/****************************************************************************************************************/


TrellisCallback momentary(keyEvent evt) {  // Trellis Momentary Mode, Main Page, Start Page

  if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) {  // Check is the pad pressed?
    Serial.println("NeoPixel Pressed");

    if (evt.bit.NUM >= 0 && evt.bit.NUM <= 15) { // push pads = sounds
      playSound(evt.bit.NUM);
      delay(10);
    }

    trellis.pixels.setPixelColor(evt.bit.NUM, Wheel(map(evt.bit.NUM, 0, trellis.pixels.numPixels(), 0, 255))); //on rising

    //reset timer for detecting a long press, which will take us to latching pattern page if held for 0.8secs
    button_hold_counter = 0;
    held_button_id = evt.bit.NUM;
  }
  else if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_FALLING) {  // or is the pad released?
    //Serial.println("NeoPixel Released");
    trellis.pixels.setPixelColor(evt.bit.NUM, 0); //off falling

    if (held_button_id == evt.bit.NUM) {  // if the held button has been released,
      if (button_hold_counter >= 800) { // if the button was held for 800 ms
        Serial.println("Long press detected");
        // *Load pattern input page for pressed pad HERE*

        for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) {  // Activate latching trellis buttons
          trellis.registerCallback(i, latching);
        }
        latchingMode = true;
        loadPattern(held_button_id);
      }
      else {
        held_button_id = -1; // Resetting the held button id means we are no longer tracking that long press.
      }
    }
  }
  trellis.pixels.show();  // Turn on/off the neopixels
  return 0;
}





/****************************************************************************************************************/

TrellisCallback latching(keyEvent evt) {  // Trellis Latching Mode
  if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) { // if any pad button is pressed

    //reset timer for detecting a long press, which will take us to momentary main page if held for 0.8secs
    button_hold_counter = 0;
    {
      if (currentPattern[evt.bit.NUM] == 0) {
        trellis.pixels.setPixelColor(evt.bit.NUM, 0x0000FF); // if off latch on
        currentPattern[evt.bit.NUM] = 1; // save state to array
        savePattern(held_button_id); // save array to array bank
      }
      else if (currentPattern[evt.bit.NUM] == 1) {
        trellis.pixels.setPixelColor(evt.bit.NUM, 0); // if on turn off
        currentPattern[evt.bit.NUM] = 0; // save state to array
        savePattern(held_button_id); // save array to array bank
      }
      trellis.pixels.show();
    }
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // long press any pad to exit pattern mode without changing current pattern
  if (button_hold_counter >= 800) {
    Serial.println("Long press detected, loading main page");

    if (currentPattern[evt.bit.NUM] == 1) {
      currentPattern[evt.bit.NUM] = 0;
      savePattern(held_button_id); // save array to array bank
    }
    else if (currentPattern[evt.bit.NUM] == 0) {  // if on turn off
      currentPattern[evt.bit.NUM] = 1;
      savePattern(held_button_id); // save array to array bank
    }

    // long press any pad to exit pattern mode without changing current pattern
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) {  // Activate momentary trellis buttons
      trellis.registerCallback(i, momentary);
    }
    clearTrellis();
    latchingMode = false;
  }
  trellis.pixels.show();
  return 0;
}



/****************************************************************************************************************/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void playSamples() {
  playSound(held_button_id);

  // to do: if pad has a pattern, play that pads sample when pink traveller hits a latched pad
  // to do: on main screen only, blink samples pad led everytime its sample is triggered
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/****************************************************************************************************************/


void playSound(int num) {
  char fileName[5];
  sprintf(fileName, "%d.raw", num);

  switch (num) {
    case 0: playFlashRaw0.play(fileName); break;
    case 1: playFlashRaw1.play(fileName); break;
    case 2: playFlashRaw2.play(fileName); break;
    case 3: playFlashRaw3.play(fileName); break;
    case 4: playFlashRaw4.play(fileName); break;
    case 5: playFlashRaw5.play(fileName); break;
    case 6: playFlashRaw6.play(fileName); break;
    case 7: playFlashRaw7.play(fileName); break;
    case 8: playFlashRaw8.play(fileName); break;
    case 9: playFlashRaw9.play(fileName); break;
    case 10: playFlashRaw10.play(fileName); break;
    case 11: playFlashRaw11.play(fileName); break;
    case 12: playFlashRaw12.play(fileName); break;
    case 13: playFlashRaw12.play(fileName); break;
    case 14: playFlashRaw14.play(fileName); break;
    case 15: playFlashRaw15.play(fileName); break;
  }
}



/****************************************************************************************************************/


void loadPattern(byte patternToLoad)
{
  Serial.print("loading pattern "); Serial.println(patternToLoad);
  for (byte ii = 0; ii < 16; ii++)
    currentPattern[ii] = patternBank[patternToLoad][ii];
  for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) { // load stored pattern
    if (currentPattern[i] == 1) {
      trellis.pixels.setPixelColor(i, 0x0000FF); // stored blue leds on
    }
  }
  trellis.pixels.setPixelColor(held_button_id, 0, 255, 0); // held button green
}

/****************************************************************************************************************/


void savePattern(byte patternToSave)
{
  Serial.print("saving pattern "); Serial.println(patternToSave);
  Serial.print("held button id "); Serial.println(held_button_id);
  for (byte ii = 0; ii < 16; ii++)
    patternBank[patternToSave][ii] = currentPattern[ii];
}

/****************************************************************************************************************/

// Input a value 0 to 255 to get a rainbow color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return trellis.pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return trellis.pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return trellis.pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  return 0;
}

/****************************************************************************************************************/

The first code you posted is three statements declaring and initialising variables. It in no way gives any output.

The second code block has a function that looks plausible. The interval constant is different, slightly, because you divided by 24, an integer, not 24.0, a floating point number.

The third "full sketch" has the clockOut() function, but it is never called. From anywhere.

But you do call MIDI.sendClock() in a timed fashion. Looks plausible. Why aren't those code lines working? BTW what exactly do you meant it is not working?

Use serial print to confirm the value of the interval variable.

Use serial print to check the time that sendClock() is being called, viz:

    Serial.print("clk: "); Serial.println(millis());
    MIDI.sendClock();

So it doesn't slow things down, make your baud rate something more 21st centuty-ish:

  Serial.begin(115200);

Your code would benefit from the use of arrays. I cannot imagine that the pain of dealing with all those scalar objects isn't worse than learning and exploiting a new language feature or two. Just sayin'.

a7

my tap tempo
54 bpm output wrong
24 or 24.0 gives same result

float prevmillis = 0;
float interval = currentTimer[1] / 24;

  unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    MIDI.sendClock();
    Serial.print(interval);
    Serial.print('\n'); // = 41.00
  }

original midi sketch
60 bpm output correct

long bpm = 60.0;
long tempo = 1000.0 / (bpm / 60.0); // = 1000ms
float prevmillis = 0;
float interval = tempo / 24.0;

  unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    MIDI.sendClock();
        Serial.print(interval);
        Serial.print('\n'); // = 41.67
  }

this just prints the timer?

Serial.print("clk: "); Serial.println(millis());
    MIDI.sendClock();

Did you try it? Have you used millis() in your projects?

That was meant to print out the time to the millisecond when your code gets around to calling the swndClock() method.

To see if you are calling it at the right frequency.

Please say what you mean by works and doesn't. Do you mean the clock is incorrect or that it doesn't happen at all?

State the frequency of the calls to the sendClock() method in the code where it works.

State the frequency of the calls to the sendClock() method in the code where it does not work, if it gets called at all.

Don't bother printing constants. You can print numbers you are unsure of once, like in setup().

I can't wrangle all your code and run it in anything like real circumstances.You however, could try

void loop() {
  trellis.read();
  delay(10); // stops freeze up in stop mode when playing pads quickly
  startStopFSW();
  runSeq();
    unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    //MIDI.sendStart();
    MIDI.sendClock();
  }
}

Gack! Remove the delay() I just noticed. I could swear I searched your code thinking you had slipped one on in there somewhere, must have had my attention distracted by something I saw from under the umbrella. An asynchronous delay asserting brain damages into a time-critical loop is a no no. That you need to use a delay kludge to fix something else is an indictment of that other code, which other code is where it should be fixed. Properly.

There is no need for delay() ever, unlike automobiles that do need to brake or even come to a halt.

Next, try a loop that does nothing but generate the clock. Leave all the other code in there, just comment out all the other work the loop does, viz:

void loop() {
//  trellis.read();
//  delay(10); // stops freeze up in stop mode when playing pads quickly
//  startStopFSW();
//  runSeq();

    unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    prevmillis = currentMillis;
    //MIDI.sendStart();
    MIDI.sendClock();
  }
}

I have a feeling you just aren't getting to the code that does the clock frequently enough for that kind of crude timing mechanism to function effectively.

Even all by itself, generating a clock manually, so to speak, in this fashion may not be adequate. I don't know anything about MIDI to a first approximation, so maybe you need to research the requirements for using the clock for whatever it is it you have downstream to it.

Your code would benefit from the use of arrays. I cannot imagine that the pain of dealing with all those scalar objects isn't worse than learning and exploiting a new language feature or two. Just sayin'. It might not solve any current problem, but it would make the future brighter.

a7

Serial.println(currentTimer[0]); correctly changes after a new tap input,
"interval" should read that change and send the updated clock out from the loop but it doesnt

unsigned long currentTimer[2] = { 1000, 1000 };  /* 60 bpm */
float prevmillis = 0;
float interval = currentTimer[0] / 24;

void loop() {
  trellis.read();
  //delay(10); // stops freeze up in stop mode when playing pads quickly
  startStopFSW();
  runSeq();
  unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    //Serial.print("clk: "); Serial.println(millis());
    MIDI.sendClock();
    Serial.println(currentTimer[0]);
    //    Serial.print(interval);
    //    Serial.print('\n'); // = 41.00
  }
}

full sketch:


#include <SD.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SerialFlash.h>
#include "Adafruit_NeoTrellis.h"
#include <MIDI.h>

// ----------------------------------------FSW NEOPIXELS---------------------------------------------
#include <Adafruit_NeoPixel.h>
#define PIXEL_PIN  5 // (Led Pin)
#define PIXEL_COUNT   2
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// ----------------------------------------FSW NEOPIXELS---------------------------------------------


// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioPlaySerialflashRaw  playFlashRaw0;
AudioPlaySerialflashRaw  playFlashRaw1;
AudioPlaySerialflashRaw  playFlashRaw2;
AudioPlaySerialflashRaw  playFlashRaw3;
AudioPlaySerialflashRaw  playFlashRaw4;
AudioPlaySerialflashRaw  playFlashRaw5;
AudioPlaySerialflashRaw  playFlashRaw6;
AudioPlaySerialflashRaw  playFlashRaw7;
AudioPlaySerialflashRaw  playFlashRaw8;
AudioPlaySerialflashRaw  playFlashRaw9;
AudioPlaySerialflashRaw  playFlashRaw10;
AudioPlaySerialflashRaw  playFlashRaw11;
AudioPlaySerialflashRaw  playFlashRaw12;
AudioPlaySerialflashRaw  playFlashRaw13;
AudioPlaySerialflashRaw  playFlashRaw14;
AudioPlaySerialflashRaw  playFlashRaw15;

AudioMixer4              mix1;
AudioMixer4              mix2;
AudioMixer4              mix3;
AudioMixer4              mix4;
AudioMixer4              mix5;
//AudioOutputAnalog        dac;
AudioOutputI2S           headphones;

// Create Audio connections between the components
//
AudioConnection          patchCord1(playFlashRaw0, 0, mix1, 0);
AudioConnection          patchCord2(playFlashRaw1, 0, mix1, 1);
AudioConnection          patchCord3(playFlashRaw2, 0, mix1, 2);
AudioConnection          patchCord4(playFlashRaw3, 0, mix1, 3);
AudioConnection          patchCord5(playFlashRaw4, 0, mix2, 0);
AudioConnection          patchCord6(playFlashRaw5, 0, mix2, 1);
AudioConnection          patchCord7(playFlashRaw6, 0, mix2, 2);
AudioConnection          patchCord8(playFlashRaw7, 0, mix2, 3);
AudioConnection          patchCord9(playFlashRaw8, 0, mix3, 0);
AudioConnection          patchCord10(playFlashRaw9, 0, mix3, 1);
AudioConnection          patchCord11(playFlashRaw10, 0, mix3, 2);
AudioConnection          patchCord12(playFlashRaw11, 0, mix3, 3);
AudioConnection          patchCord13(playFlashRaw12, 0, mix4, 0);
AudioConnection          patchCord14(playFlashRaw13, 0, mix4, 1);
AudioConnection          patchCord15(playFlashRaw14, 0, mix4, 2);
AudioConnection          patchCord16(playFlashRaw15, 0, mix4, 3);
AudioConnection          patchCord17(mix1, 0, mix5, 0);
AudioConnection          patchCord18(mix2, 0, mix5, 1);
AudioConnection          patchCord19(mix3, 0, mix5, 2);
AudioConnection          patchCord20(mix4, 0, mix5, 3);
//AudioConnection          patchCord21(mix5, dac);
AudioConnection          patchCord22(mix5, 0, headphones, 0);
AudioConnection          patchCord23(mix5, 0, headphones, 1);


// Create an object to control the audio shield.
//
AudioControlSGTL5000 audioShield;

const int FlashChipSelect = 6; // digital pin for flash chip CS pin



Adafruit_NeoTrellis trellis;



unsigned long previousMillis = 0; // will store last time LED was updated
const int FSW1 = 3;  // tap tempo footswitch
const int FSW2 = 2;  // Start/stop footswitch
int ledState = LOW; // ledState used to set the tempo LED
int FSW1State = 0;         // variable for reading the pushbutton status
int FSW2State = HIGH;
int ledState2 = -1; //this variable tracks the state of the LED, negative if off, positive if on
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 500;    // the debounce time; increase if the output flickers
int lastTapState = LOW;  /* the last tap button state */
unsigned long currentTimer[2] = { 1000, 1000 };  /* 60 bpm */
unsigned long timeoutTime = 0;  /* this is when the timer will trigger next */
unsigned long timeoutTime2 = 0;   //this is when the timer will trigger next
unsigned long downTime = 0;     /* for our delayed press reset */
unsigned long indicatorTimeout; /* for our fancy "blink" tempo indicator */
unsigned long indicatorTimeout2; //variable used to determine the duration of the pad X4 blinks on state
boolean pressTimeout = false;
unsigned long lastTap = 0; /* when the last tap happened */
elapsedMillis button_hold_counter = 0;
int8_t held_button_id = -1;
int latchingMode = false;

const byte NPATTERNS = 16;

byte patternBank[NPATTERNS][16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

int currentPattern[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

MIDI_CREATE_DEFAULT_INSTANCE();

//long bpm = 60.0;
//long tempo = 1000.0 / (bpm / 60.0); // = 1000ms

float prevmillis = 0;
float interval = currentTimer[0] / 24; //interval is the number of milliseconds defined by tempo formula.

/****************************************************************************************************************/

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);
  Serial.begin(115200);
  trellis.begin();
  trellis.pixels.setBrightness(50);
  pixels.begin(); // for start/stop and tempo LEDs
  pixels.setBrightness(50);
  pixels.setPixelColor(1, 220, 20, 60);
  pixels.show();
  pinMode(FSW1, INPUT_PULLUP);
  pinMode(FSW2, INPUT_PULLUP);
  AudioMemory(40);
  audioShield.enable();
  audioShield.volume(0.9);

  // reduce the gain on mixer channels, so more than 1
  // sound can play simultaneously without clipping
  mix1.gain(0, 0.9);
  mix1.gain(1, 0.9);
  mix1.gain(2, 0.9);
  mix1.gain(3, 0.9);
  mix2.gain(0, 0.9);
  mix2.gain(1, 0.9);
  mix2.gain(2, 0.9);
  mix2.gain(3, 1);
  mix3.gain(0, 0.9);
  mix3.gain(1, 0.9);
  mix3.gain(2, 0.9);
  mix3.gain(3, 0.7);
  mix4.gain(0, 0.9);
  mix4.gain(1, 0.9);
  mix4.gain(2, 0.9);
  mix4.gain(3, 0.9);

  mix5.gain(1, 1);
  mix5.gain(2, 1);

  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7

  SerialFlash.begin(FlashChipSelect);

  //activate momentary pads and set callbacks
  for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) {
    trellis.activateKey(i, SEESAW_KEYPAD_EDGE_RISING);
    trellis.activateKey(i, SEESAW_KEYPAD_EDGE_FALLING);
    trellis.registerCallback(i, momentary);
  }
  //do a little animation to show we're on
  for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, Wheel(map(i, 0, trellis.pixels.numPixels(), 0, 255)));
    trellis.pixels.show();
    delay(25);
  }
  for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, 0x000000);
    trellis.pixels.show();
    delay(25);
  }
}

int pad = -1;


void loop() {
  trellis.read();
  startStopFSW();
  runSeq();
  unsigned long currentMillis = millis();
  if (currentMillis - prevmillis >= interval) {
    //save the last time.
    prevmillis = currentMillis;
    //Serial.print("clk: "); Serial.println(millis());
    MIDI.sendClock();
    Serial.println(currentTimer[0]);
  }
}


/****************************************************************************************************************/

void startStopFSW() {
  //sample the state of the button - is it pressed or not?
  FSW2State = digitalRead(FSW2);

  //filter out any noise by setting a time buffer
  if ( (millis() - lastDebounceTime) > debounceDelay) {

    //if the button has been pressed, lets toggle the LED from "off to on" or "on to off"
    if ( (FSW2State == LOW) && (ledState2 < 0) ) {

      // turn LED lawn green:
      pixels.setPixelColor(1, 124, 252, 0);
      pixels.show();
      Serial.println("Start");
      //MIDI.sendStart();
      pad = -1;
      ledState2 = -ledState2; //now the LED is on, we need to change the state
      lastDebounceTime = millis(); //set the current time
    }
    else if ( (FSW2State == LOW) && (ledState2 > 0) ) {

      // LED crimson
      pixels.setPixelColor(1, 220, 20, 60);
      pixels.show();
      Serial.println("Stop");
      //MIDI.sendStop();
      ledState2 = -ledState2; //
      lastDebounceTime = millis(); //set the current time
    }
  }
}



/****************************************************************************************************************/

void loadKit() { // for later

}

/****************************************************************************************************************/


void runSeq() {
  int tapState = digitalRead(FSW1);
  if ( tapState == LOW && tapState != lastTapState ) /* button up->down */
  {
    tap(); /* we got a HIGH-LOW transition, call our tap() function */
    downTime = millis();
    pressTimeout = false;
  }



  /* press-and-hold detection start */
  if ( tapState == LOW ) /* button is down... */
  {
    /* if we have not triggered before, and the down time is more than 2 seconds... */
    /* 2000 = 2000ms = 2 seconds */
    if ( !pressTimeout && ((millis() - downTime ) > 1000 ))
    {


      /* Load Kit Here */

      ledState2 = -1;
      pixels.setPixelColor(1, 220, 20, 60); // start LED off (red)
      pixels.setPixelColor(0, 20, 55, 155); // kit LED (blue)
      pixels.show();
      clearTrellis();
      trellis.pixels.setPixelColor(0, 0, 255, 0); // letter "K" (green) Load Kit Page
      trellis.pixels.setPixelColor(2, 0, 255, 0);
      trellis.pixels.setPixelColor(3, 0, 255, 0);
      trellis.pixels.setPixelColor(4, 0, 255, 0);
      trellis.pixels.setPixelColor(5, 0, 255, 0);
      trellis.pixels.setPixelColor(8, 0, 255, 0);
      trellis.pixels.setPixelColor(10, 0, 255, 0);
      trellis.pixels.setPixelColor(12, 0, 255, 0);
      trellis.pixels.setPixelColor(15, 0, 255, 0);
      trellis.pixels.show();

      /* Load Kit Here */


      currentTimer[0] = currentTimer[1]; /* dont let long press change current tempo */
      rescheduleTimer(); /* start the timer */
      pressTimeout = true; /* make sure we don't get called again during this press */
    }
  }
  /* press-and-hold detection end */



  lastTapState = tapState; /* keep track of the last state, for transition detection */

  if (ledState2 > 0) // if footswitch start
  {
    /* check for timer timeout */
    if ( millis() >= timeoutTime2 ) // timeoutTime2 is 4x faster than timeoutTime
    {
      /* timeout happens */

      indicatorTimeout = millis() + 20;  /* this sets the time when the LED goes off */
      rescheduleTimer();            /* and reschedule the timer to keep the pace */
    }



    /* display the tap blink on Trellis */
    if ( millis() < indicatorTimeout)
    {
      // 750ms = 80bpm
      //MIDI.sendClock(); // = 25 bpm
      //MIDI.sendClock(); // = 50 bpm
      //MIDI.sendClock(); // = 75 bpm
      //MIDI.sendClock(); // = 100 bpm

      if (pad == held_button_id && latchingMode == true)
      {
        trellis.pixels.setPixelColor(held_button_id, 0, 255, 0);  //  Make held trellis LED green as pink traveller passes
        trellis.pixels.show();
      }
      else
      {
        trellis.pixels.setPixelColor(pad, 220, 20, 60); // The Pink Traveller
        trellis.pixels.show();
      }
    }



    if (currentPattern[pad] == 1 && latchingMode == true) // if pad is latched on in array
    {
      trellis.pixels.setPixelColor(pad, 0x0000ff); // make latched LEDs Blue again after pink traveller passes
    }
    else {
      trellis.pixels.setPixelColor(pad, 0);  //  Turn off pink traveller after it passes
    }

  } // if footswitch start






  if (ledState2 < 0) // if footswitch stop
  {
    /* check for timer timeout */
    if ( millis() >= timeoutTime ) // timeoutTime2 is 4x faster than timeoutTime
    {
      /* timeout happens */
      indicatorTimeout = millis() + 20;  /* this sets the time when the LED goes off */
      rescheduleTimer();            /* and reschedule the timer to keep the pace */
    }



    /* display the tap blink on LED  */
    if ( millis() < indicatorTimeout)
    {
      pixels.setPixelColor(0, 0, 255, 255); // Tempo LED on aqua
      pixels.show();
    }

    else {
      pixels.setPixelColor(0, 0, 0, 0);  // Tempo LED off
      pixels.show();
    }
  }
}


/****************************************************************************************************************/


void tap()
{
  /* we keep two of these around to average together later */
  currentTimer[1] = currentTimer[0];
  currentTimer[0] = millis() - lastTap; /* current = duration since last tap */
  lastTap = millis();
  timeoutTime = 0; /* force the trigger to happen immediately - sync and blink! */
  timeoutTime2 = 0; /* force the trigger to happen immediately - sync and blink! */
}


/****************************************************************************************************************/

void rescheduleTimer()
{
  /* set the timer to go off again when the time reaches the
     timeout.  The timeout is all of the "currentTimer" values averaged
     together, then added onto the current time.  When that time has been
     reached, the next tick will happen...
  */
  timeoutTime = millis() + ((currentTimer[0] + currentTimer[1]) / 2);  // Neopixel LED speed
  timeoutTime2 = millis() + ((currentTimer[0] + currentTimer[1]) / 8);  // Neotrellis speed x4 faster

  if (ledState2 > 0) // if footswitch start
  {
    pad++;
    pad %= 16;

    if (patternBank[0][pad] == 1) // if pad is latched on in array
    {
      playSound(0);
    }

    if (patternBank[1][pad] == 1) // if pad is latched on in array
    {
      playSound(1);
    }

    if (patternBank[2][pad] == 1) // if pad is latched on in array
    {
      playSound(2);
    }

    if (patternBank[3][pad] == 1) // if pad is latched on in array
    {
      playSound(3);
    }

    if (patternBank[4][pad] == 1) // if pad is latched on in array
    {
      playSound(4);
    }

    if (patternBank[5][pad] == 1) // if pad is latched on in array
    {
      playSound(5);
    }

    if (patternBank[6][pad] == 1) // if pad is latched on in array
    {
      playSound(6);
    }

    if (patternBank[7][pad] == 1) // if pad is latched on in array
    {
      playSound(7);
    }

    if (patternBank[8][pad] == 1) // if pad is latched on in array
    {
      playSound(8);
    }

    if (patternBank[9][pad] == 1) // if pad is latched on in array
    {
      playSound(9);
    }

    if (patternBank[10][pad] == 1) // if pad is latched on in array
    {
      playSound(10);
    }

    if (patternBank[11][pad] == 1) // if pad is latched on in array
    {
      playSound(11);
    }

    if (patternBank[12][pad] == 1) // if pad is latched on in array
    {
      playSound(12);
    }

    if (patternBank[13][pad] == 1) // if pad is latched on in array
    {
      playSound(13);
    }

    if (patternBank[14][pad] == 1) // if pad is latched on in array
    {
      playSound(14);
    }

    if (patternBank[15][pad] == 1) // if pad is latched on in array
    {
      playSound(15);
    }
  }
}

/****************************************************************************************************************/


void clearTrellis() {

  for (uint16_t i = 0; i < trellis.pixels.numPixels(); i++) {
    trellis.pixels.setPixelColor(i, 0); // all trellis leds off
  }
}



/****************************************************************************************************************/


TrellisCallback momentary(keyEvent evt) {  // Trellis Momentary Mode, Main Page, Start Page

  if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) {  // Check is the pad pressed?
    Serial.println("NeoPixel Pressed");

    if (evt.bit.NUM >= 0 && evt.bit.NUM <= 15) { // push pads = sounds
      playSound(evt.bit.NUM);
      delay(10);
    }

    trellis.pixels.setPixelColor(evt.bit.NUM, Wheel(map(evt.bit.NUM, 0, trellis.pixels.numPixels(), 0, 255))); //on rising

    //reset timer for detecting a long press, which will take us to latching pattern page if held for 0.8secs
    button_hold_counter = 0;
    held_button_id = evt.bit.NUM;
  }
  else if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_FALLING) {  // or is the pad released?
    //Serial.println("NeoPixel Released");
    trellis.pixels.setPixelColor(evt.bit.NUM, 0); //off falling

    if (held_button_id == evt.bit.NUM) {  // if the held button has been released,
      if (button_hold_counter >= 800) { // if the button was held for 800 ms
        Serial.println("Long press detected");
        // *Load pattern input page for pressed pad HERE*

        for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) {  // Activate latching trellis buttons
          trellis.registerCallback(i, latching);
        }
        latchingMode = true;
        loadPattern(held_button_id);
      }
      else {
        held_button_id = -1; // Resetting the held button id means we are no longer tracking that long press.
      }
    }
  }
  trellis.pixels.show();  // Turn on/off the neopixels
  return 0;
}





/****************************************************************************************************************/

TrellisCallback latching(keyEvent evt) {  // Trellis Latching Mode
  if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) { // if any pad button is pressed

    //reset timer for detecting a long press, which will take us to momentary main page if held for 0.8secs
    button_hold_counter = 0;
    {
      if (currentPattern[evt.bit.NUM] == 0) {
        trellis.pixels.setPixelColor(evt.bit.NUM, 0x0000FF); // if off latch on
        currentPattern[evt.bit.NUM] = 1; // save state to array
        savePattern(held_button_id); // save array to array bank
      }
      else if (currentPattern[evt.bit.NUM] == 1) {
        trellis.pixels.setPixelColor(evt.bit.NUM, 0); // if on turn off
        currentPattern[evt.bit.NUM] = 0; // save state to array
        savePattern(held_button_id); // save array to array bank
      }
      trellis.pixels.show();
    }
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // long press any pad to exit pattern mode without changing current pattern
  if (button_hold_counter >= 800) {
    Serial.println("Long press detected, loading main page");

    if (currentPattern[evt.bit.NUM] == 1) {
      currentPattern[evt.bit.NUM] = 0;
      savePattern(held_button_id); // save array to array bank
    }
    else if (currentPattern[evt.bit.NUM] == 0) {  // if on turn off
      currentPattern[evt.bit.NUM] = 1;
      savePattern(held_button_id); // save array to array bank
    }

    // long press any pad to exit pattern mode without changing current pattern
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) {  // Activate momentary trellis buttons
      trellis.registerCallback(i, momentary);
    }
    clearTrellis();
    latchingMode = false;
  }
  trellis.pixels.show();
  return 0;
}



/****************************************************************************************************************/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void playSamples() {
  playSound(held_button_id);

  // to do: if pad has a pattern, play that pads sample when pink traveller hits a latched pad
  // to do: on main screen only, blink samples pad led everytime its sample is triggered
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/****************************************************************************************************************/


void playSound(int num) {
  char fileName[5];
  sprintf(fileName, "%d.raw", num);

  switch (num) {
    case 0: playFlashRaw0.play(fileName); break;
    case 1: playFlashRaw1.play(fileName); break;
    case 2: playFlashRaw2.play(fileName); break;
    case 3: playFlashRaw3.play(fileName); break;
    case 4: playFlashRaw4.play(fileName); break;
    case 5: playFlashRaw5.play(fileName); break;
    case 6: playFlashRaw6.play(fileName); break;
    case 7: playFlashRaw7.play(fileName); break;
    case 8: playFlashRaw8.play(fileName); break;
    case 9: playFlashRaw9.play(fileName); break;
    case 10: playFlashRaw10.play(fileName); break;
    case 11: playFlashRaw11.play(fileName); break;
    case 12: playFlashRaw12.play(fileName); break;
    case 13: playFlashRaw12.play(fileName); break;
    case 14: playFlashRaw14.play(fileName); break;
    case 15: playFlashRaw15.play(fileName); break;
  }
}



/****************************************************************************************************************/


void loadPattern(byte patternToLoad)
{
  Serial.print("loading pattern "); Serial.println(patternToLoad);
  for (byte ii = 0; ii < 16; ii++)
    currentPattern[ii] = patternBank[patternToLoad][ii];
  for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) { // load stored pattern
    if (currentPattern[i] == 1) {
      trellis.pixels.setPixelColor(i, 0x0000FF); // stored blue leds on
    }
  }
  trellis.pixels.setPixelColor(held_button_id, 0, 255, 0); // held button green
}

/****************************************************************************************************************/


void savePattern(byte patternToSave)
{
  Serial.print("saving pattern "); Serial.println(patternToSave);
  Serial.print("held button id "); Serial.println(held_button_id);
  for (byte ii = 0; ii < 16; ii++)
    patternBank[patternToSave][ii] = currentPattern[ii];
}

/****************************************************************************************************************/

// Input a value 0 to 255 to get a rainbow color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return trellis.pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return trellis.pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return trellis.pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  return 0;
}

/****************************************************************************************************************/

If you mean because you ever said

float interval = currentTimer[0] / 24;

that there is a magical connection that updates interval when currentTimer[0] takes on a new value, that is not what happens.

The only way for interval to take on a new value is if you assign it a new value. If you mean it to track currentTimer[0], you'll have to reassign to interval with changes that would be due to currentTimer[0] having been changed.

If that's not what you thought or meant, I have no idea what you are trying to say.

a7

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.