Skip to content

Commit

Permalink
Basic project structure, no functionality implemented yet
Browse files Browse the repository at this point in the history
  • Loading branch information
dxinteractive committed Aug 28, 2016
1 parent 0dd2558 commit 4ea1b1c
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 2 deletions.
17 changes: 17 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Auto detect text files and perform LF normalization
* text=auto

# Custom for Visual Studio
*.cs diff=csharp

# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# ArduinoTapTempo
A simple clock-based library that times consecutive button presses to calculate BPM. Corrects for missed beats and can reset phase with single taps.
# ArduinoTapTempo - under construction
An Arduino library that times consecutive button presses to calculate Beats Per Minute. Corrects for missed beats and can reset phase with single taps.
128 changes: 128 additions & 0 deletions codepen-draft.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@

//
// Constants
//

var TOTAL_TAP_VALUES = 5;
var MS_UNTIL_CHAIN_RESET = 2000;
var SKIPPED_TAP_THRESHOLD_LOW = 1.75;
var SKIPPED_TAP_THRESHOLD_HIGH = 2.75;

//
// Variables
//

var buttonDown = false;
var buttonDownOld = false;
var sinceResetMS = 0;
var sinceResetMSOld = 0;
var beatMS = 500;
var resetMS = millis();
var lastTapMS = 0;
var lastTapSkipped = false;
var beatProgress = 0;

// tapDurations will be used as though it's a fixed length C++ array, as that's where it'll end up
var tapDurations = [0, 0, 0, 0, 0];
var tapDurationIndex = 0;
var tapsInChain = 0;

//
// Functions
//

var getAverageTapDuration = function() {
var amount = tapsInChain - 1;
if(amount > TOTAL_TAP_VALUES) {
amount = TOTAL_TAP_VALUES;
}

var runningTotal = 0;
for(var i=0; i<amount; i++) {
runningTotal += tapDurations[i];
}

return Math.floor(runningTotal / amount);
};

var tap = function(ms) {
elements.tap.stop().css('opacity','1').animate({opacity:0},200);

tapsInChain++;
if(tapsInChain == 1) {
lastTapMS = ms;
return -1;
}

var duration = ms - lastTapMS;

// detect if last duration was unreasonable
if(tapsInChain > 1
&& !lastTapSkipped
&& duration > beatMS * SKIPPED_TAP_THRESHOLD_LOW
&& duration < beatMS * SKIPPED_TAP_THRESHOLD_HIGH) {

elements.tapskipped.stop().css('opacity','1').animate({opacity:0},600);
duration = Math.floor(duration * 0.5);
lastTapSkipped = true;
} else {
lastTapSkipped = false;
}

tapDurations[tapDurationIndex] = duration;
tapDurationIndex++;
if(tapDurationIndex == TOTAL_TAP_VALUES) {
tapDurationIndex = 0;
}

var newBeatMS = getAverageTapDuration();

lastTapMS = ms;
return newBeatMS;
};

var resetTapChain = function(ms) {
tapsInChain = 0;
tapDurationIndex = 0;
resetMS = ms;
for(var i=0; i<TOTAL_TAP_VALUES; i++) {
tapDurations[i] = 0;
}
};

var loop = function() {
var ms = millis();

// if a tap has occured...
if(buttonDown && !buttonDownOld) {

// start a new tap chain if last tap was over an amount of beats ago
if(lastTapMS + MS_UNTIL_CHAIN_RESET < ms) {
resetTapChain(ms);
elements.newtapchain.stop().css('opacity','1').animate({opacity:0},600);
}

var newBeatMS = tap(ms);
if(newBeatMS != -1) {
beatMS = newBeatMS;
}
}

beatprogress = (sinceResetMS / beatMS) % 1;

var b = Math.floor(beatprogress*20);
var beatprog = "";
for(var i = 0; i < 20; i++) {
beatprog += i==b ? "|" : "-";
}

// if a beat has occured since last loop()
sinceResetMS = ms - resetMS;
if(sinceResetMS % beatMS < sinceResetMSOld % beatMS) {
elements.beat.stop().css('opacity','1').animate({opacity:0},200);
}

// set old vars
buttonDownOld = buttonDown;
sinceResetMSOld = sinceResetMS;
};
32 changes: 32 additions & 0 deletions examples/ArduinoTapTempo/ArduinoTapTempo.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// include the ArduinoTapTempo library
#include <ArduinoTapTempo.h>

// define the pin you want to attach your tap button to
const int BUTTON_PIN = 5;

// make an ArduinoTapTempo object
ArduinoTapTempo tapTempo;

void setup() {
// begin serial so we can see the state of the tempo object through the serial monitor
Serial.begin(9600);

// setup your button as required by your project
pinMode(BUTTON_PIN, INPUT);
digitalWrite(BUTTON_PIN, HIGH);
}

void loop() {
// get the state of the button
boolean buttonDown = digitalRead(BUTTON_PIN) == LOW;
if(buttonDown) {
Serial.println("Button down");
} else {
Serial.println("Button up");
}

// update the ArduinoTapTempo object
tapTempo.update(buttonDown);

delay(10);
}
27 changes: 27 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#######################################
# Syntax Coloring Map
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

ArduinoTapTempo KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################
isPressed KEYWORD2
isPressedBefore KEYWORD2
isPressedAfter KEYWORD2
onPress KEYWORD2
onPressAfter KEYWORD2
onPressAndAfter KEYWORD2
onPressAfter KEYWORD2
onPressAndAfter KEYWORD2
onRelease KEYWORD2
onReleaseBefore KEYWORD2
onReleaseAfter KEYWORD2
getPressDuration KEYWORD2
getLastReleasePressDuration KEYWORD2
update KEYWORD2
9 changes: 9 additions & 0 deletions library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=AnalogMultiButton
version=1.0
author=Damien Clarke <dxinteractive@gmail.com>
maintainer=Damien Clarke <dxinteractive@gmail.com>
sentence=An Arduino library to capture button presses on multiple buttons through a single analog pin.
paragraph=Includes debouncing and many options for triggering timed / delayed / repeated press events.
category=Signal Input/Output
url=http://damienclarke.me/code/analog-multi-button
architectures=*
55 changes: 55 additions & 0 deletions src/ArduinoTapTempo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* ArduinoTapTempo.cpp
* An Arduino library that times consecutive button presses to calculate Beats Per Minute. Corrects for missed beats and can reset phase with single taps.
*
* Copyright (c) 2016 Damien Clarke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include <Arduino.h>
#include "ArduinoTapTempo.h"

ArduinoTapTempo::ArduinoTapTempo(int millisUntilChainReset, int totalTapValues)
{
this->millisUntilChainReset = millisUntilChainReset;
this->totalTapValues = totalTapValues;
}

void ArduinoTapTempo::setSkippedTapThresholdLow(float threshold)
{
if(threshold > 1.0 && threshold < 2.0)
{
skippedTapThresholdLow = threshold;
}
}

void ArduinoTapTempo::setSkippedTapThresholdHigh(float threshold)
{
if(threshold > 2.0 && threshold < 4.0)
{
skippedTapThresholdHigh = threshold;
}
}


void ArduinoTapTempo::update(boolean buttonDown)
{

}
52 changes: 52 additions & 0 deletions src/ArduinoTapTempo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* ArduinoTapTempo.h
* An Arduino library that times consecutive button presses to calculate Beats Per Minute. Corrects for missed beats and can reset phase with single taps. *
* Copyright (c) 2016 Damien Clarke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef ARDUINO_TAP_TEMPO_H
#define ARDUINO_TAP_TEMPO_H

#include <Arduino.h>

class ArduinoTapTempo
{
public:

// millisUntilChainReset - the current chain of taps will finish this many milliseconds after the most recent tap
// totalTapValues - the maximum number of most recent taps that will be averaged out to calculate the tempo

ArduinoTapTempo(int millisUntilChainReset = 2000, int totalTapValues = 5);

// skipped taps are detected when a tap duration is close to double the last tap duration.
void setSkippedTapThresholdLow(float threshold); // This sets the lower threshold, accepts a float from 1.0 to 2.0.
void setSkippedTapThresholdHigh(float threshold); // This sets the upper threshold, accepts a float from 2.0 to 4.0.

void update(boolean buttonDown);

private:
int millisUntilChainReset;
int totalTapValues;
float skippedTapThresholdLow = 1.75;
float skippedTapThresholdHigh = 2.75;
};

#endif

0 comments on commit 4ea1b1c

Please sign in to comment.