Adding Pause Functionality to BPM Counter

slammer88

New member
Hi,

I'm following this project that's a BPM calculator with tap functionality. The creator of this project says that he wrote this code with much help from others. I asked the following question to him but he said he didn't know much about how to implement it.

It's actually pretty simple. When the encoder button is being held for a second, the bpm counter shall pause, and once released, it'll start from the beginning. I need this functionality to sync with the rest of my band on live stage.

#define USE_TIMER_1 false
#define USE_TIMER_2 true
#define USE_TIMER_3 false
#define USE_TIMER_4 false
#define USE_TIMER_5 false

#include <TimerInterrupt.h>
#include <ISR_Timer.h>
#include <ClickEncoder.h>
#include <TimerOne.h>
#include <ArduinoTapTempo.h>
#include <LiquidCrystal.h>

#define LCD_RS 8
#define LCD_RW 9
#define LCD_EN 10
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 6
#define LCD_D7 7
#define LCD_CHARS 16
#define LCD_LINES 2

LiquidCrystal lcd(LCD_RS, LCD_RW, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

#define LED 2
#define MAX_BPM 480
#define MIN_BPM 40

#define MULT1 11
#define MULT2 12


const int BUTTON_PIN = 3;
ArduinoTapTempo tapTempo;

ClickEncoder *encoder;
int16_t last, value, bpmtemp, encoderpos, interval;
float period;
uint16_t counter = 0;
unsigned long lastUpdate = 0;
uint8_t multiplier = 1;

int multplusState = 0;
int multminState = 0;
int lastmultplusState = 0;
int lastmultminState = 0;

void timerIsr() {
encoder->service();
}

//--PULSE INTERRUPT--//

void PulseHandler()
{

counter+=2;
if (counter >= period)
{
counter = 0;
digitalWrite(LED, !digitalRead(LED));
}
}



void displayAccelerationStatus() {
lcd.setCursor(0, 0);
lcd.print("BEATS PER MINUTE: ");
}


void setup()
{

// IO INIT
pinMode(LED, OUTPUT);
pinMode(BUTTON_PIN, INPUT);
digitalWrite(BUTTON_PIN, HIGH);
pinMode(MULT1, INPUT_PULLUP);
pinMode(MULT2, INPUT_PULLUP);

// ENCODER INIT
encoder = new ClickEncoder(A1, A0, A2, 4);

// LCD INIT
lcd.begin(LCD_CHARS, LCD_LINES);
lcd.clear();
displayAccelerationStatus();

// VARIABLES
value = 120; // The BPM value
bpmtemp = 0; // Temporary BPM
encoderpos = 0; // Encoder position
last = -1; // Last BPM (unused, potentially usable to only update LCD and period once the BPM actually changed)
interval = 1; // Period of BPM timer in ms (2ms or double speed because a pulse consists of an upgoing and downgoing slewage)
period = 30000 / value * 2; // Convert BPM to desired output period

// TIMER INIT
Timer1.initialize(1000); // For rotary acceleration
Timer1.attachInterrupt(timerIsr);
ITimer2.init(); // For output pulses
if (ITimer2.attachInterruptInterval(interval, PulseHandler));

tapTempo.setMinBPM((float)MIN_BPM);
tapTempo.setMaxBPM((float)MAX_BPM);

//tapTempo.disableSkippedTapDetection();
//tapTempo.setTotalTapValues(4);
tapTempo.setBeatsUntilChainReset(10);

Serial.begin(9600);
}

void loop() {
boolean buttonDown = digitalRead(BUTTON_PIN) == LOW; // if pressed, buttondown = true
tapTempo.update(buttonDown); // update if buttondown = true


if ((uint16_t)tapTempo.getBPM() != bpmtemp)
{
encoderpos = 0;
bpmtemp = (uint16_t)tapTempo.getBPM();
}
encoderpos += encoder->getValue();

// MIGHT BE ABLE TO PUT LINES 119 THROUGH 131 INTO AN IF ELSE STATEMENT

value = bpmtemp + encoderpos;

if (value >= MAX_BPM) // Restrict to max bpm
{
encoderpos = MAX_BPM - bpmtemp;
value = MAX_BPM;
}

if (value <= MIN_BPM) // Restrict to min bpm
{
encoderpos = MIN_BPM - bpmtemp;
value = MIN_BPM;
}

// Alter the output pulse period based on the bpm
period = (30000 / value * 2) / multiplier;

multplusState = digitalRead(MULT2);

// compare the buttonState to its previous state
if (multplusState != lastmultplusState) {
// if the state has changed, increment the counter
if (multplusState == HIGH) {
// if the current state is HIGH then the button
// wend from off to on:
multiplier += 1;

if(multiplier >4)
{
multiplier = 4;
}

lcd.setCursor(11, 1);
lcd.print(multiplier);
}
}
// save the current state as the last state,
//for next time through the loop
lastmultplusState = multplusState;

multminState = digitalRead(MULT1);

// compare the buttonState to its previous state
if (multminState != lastmultminState) {
// if the state has changed, increment the counter
if (multminState == HIGH) {
// if the current state is HIGH then the button
// wend from off to on:
multiplier -= 1;

if(multiplier <1)
{
multiplier = 1;
}
lcd.setCursor(11, 1);
lcd.print(multiplier);
}
}
// save the current state as the last state,
//for next time through the loop
lastmultminState = multminState;







// Show the current BPM on the LCD
if (lastUpdate - millis() > 16 && last != value)
{
lastUpdate = millis();
last = value;
Serial.println("JA");
lcd.setCursor(0, 1);
lcd.print(" ");

lcd.setCursor(6, 1);
lcd.print(value);

lcd.setCursor(10, 1);
lcd.print("x");

lcd.setCursor(11, 1);
lcd.print(multiplier);


if (value == MAX_BPM)
{
lcd.setCursor(13, 1);
lcd.print("MAX");
}

if (value == MIN_BPM)
{
lcd.setCursor(0, 1);
lcd.print("MIN");
}
}


ClickEncoder::Button b = encoder->getButton();
if (b != ClickEncoder::Open) {
Serial.print("Button: ");
#define VERBOSECASE(label) case label: Serial.println(#label); break;
switch (b) {
VERBOSECASE(ClickEncoder::pressed);
VERBOSECASE(ClickEncoder::Held)
VERBOSECASE(ClickEncoder::Released)
VERBOSECASE(ClickEncoder::Clicked)
case ClickEncoder::DoubleClicked:
Serial.println("ClickEncoder::DoubleClicked");
encoder->setAccelerationEnabled(!encoder->getAccelerationEnabled());
Serial.print(" Acceleration is ");
Serial.println((encoder->getAccelerationEnabled()) ? "enabled" : "disabled");


#ifdef WITH_LCD
displayAccelerationStatus();
#endif
break;
}
}
}
 
I asked the following question to him but he said he didn't know much about how to implement it.

Okay, so just to be clear, you trying to figure out how to read the tap tempo off of a momentary switch in order to know the bpm, in order to do what? are you setting the tempo of a device, or an lfo, or flash an LED, or what exactly? Cause it seems like this code doesn't really do anything except tell you the bpm, and I'm not even sure it does that.
 
Okay, so just to be clear, you trying to figure out how to read the tap tempo off of a momentary switch in order to know the bpm, in order to do what? are you setting the tempo of a device, or an lfo, or flash an LED, or what exactly? Cause it seems like this code doesn't really do anything except tell you the bpm, and I'm not even sure it does that.

I'm not trying to figure out anything; as it is, it's already a BPM counter. Encoder settings change the BPM, and short-tapping to encoder button acts like a TAP functionality, and there's also this indicator LED.

Check the video here

What I need is that I want to add a hold/pause functionality. When the encoder button is being pressed for more than a second, the counter should stop, and once released it shall start again. It's gonna be like a dual function on the encoder button.

Short Tap: Tap Tempo,
Press & Hold >500ms i.e; Hold the Counter

Why I need this; stages and bandmates I play sometimes go out of tempo, or I just simply lose it as I don't have any in-ears. This will act as sort of an emergency brake for manually syncing the tempo with them.

Also yes, this will be connected to an LFO pedal based on StompLFO. But more than that, it'll guide me visually for BPM count.
 
I'm not trying to figure out anything; as it is, it's already a BPM counter. Encoder settings change the BPM, and short-tapping to encoder button acts like a TAP functionality, and there's also this indicator LED.

Check the video here

What I need is that I want to add a hold/pause functionality. When the encoder button is being pressed for more than a second, the counter should stop, and once released it shall start again. It's gonna be like a dual function on the encoder button.

Short Tap: Tap Tempo,
Press & Hold >500ms i.e; Hold the Counter

Why I need this; stages and bandmates I play sometimes go out of tempo, or I just simply lose it as I don't have any in-ears. This will act as sort of an emergency brake for manually syncing the tempo with them.

Also yes, this will be connected to an LFO pedal based on StompLFO. But more than that, it'll guide me visually for BPM count.
Ok, got it. I'm gonna have to think on this, but I understand what you are trying to do.

EDIT: I guess I should have read the title of your thread. lol.
 
Last edited:
Ok, got it. I'm gonna have to think on this, but I understand what you are trying to do.

EDIT: I guess I should have read the title of your thread. lol.
I checked the GitHub of ClickEncoder.h and there seems to be a definition/usage for hold & release functions, I guess.

 
Back
Top