<html>
<HEAD>
<meta name="Title" CONTENT="Metronome Lite - HTML5 metronome">
<!-- <link rel="stylesheet" href="style.css" type="text/css"/> -->
</HEAD>
<body onload="JSmetronome.init()">
<footer>2019 - Guitare-electrique.org</footer>
<div id="JSMetroContainer" class="unselectable">
<div id="tempoUp" class="unselectable"></div>
<div id="tempoDown" class="unselectable"></div>
<div id="Beat" class="unselectable">0</div>
<div id="timeSignature" class="unselectable"></div>
<div id="TempoContainer" class="unselectable">
<span id="tempoDisplay" class="unselectable"></span>
<span id="tempoTag" class="unselectable">bpm</span>
</div>
<div id="tapBkg" class="unselectable"></div>
<div id="tap" class="unselectable">TAP</div>
<div id="power" class="unselectable"></div>
<div id="BellButton" class="unselectable"></div>
<audio id="metronomeTick_1" preload="auto">
<source src="https://caljer1.github.io/MetronomeLite/sounds/click.mp3" type="audio/mp3" />
<!-- <source src="https://caljer1.github.io/MetronomeLite/sounds/clave.mp3" type="audio/mp3" /> -->
<!-- <source src="https://caljer1.github.io/MetronomeLite/sounds/clap.mp3" type="audio/mp3" /> -->
<!-- <source src="https://caljer1.github.io/MetronomeLite/sounds/rimshot.mp3" type="audio/mp3" /> -->
</audio>
<audio id="metronomeBell" preload="auto">
<source src="https://caljer1.github.io/MetronomeLite/sounds/bell.mp3" type="audio/mp3" />
</audio>
</div>
<!-- <script src="JSmetronome.js"></script> -->
</body>
</html>
@font-face {
font-family: 'Viga';
font-style: normal;
font-weight: 400;
src: local('Viga-Regular'), url('https://caljer1.github.io/MetronomeLite/fonts/viga.woff') format('woff');
}
* {
margin:0;
padding:0;
}
body{
background-color:#424242;
}
#JSMetroContainer{
position:absolute;
background-image:url('https://caljer1.github.io/MetronomeLite/img/JSMetronome.png');
width:300px;
height:339px;
margin-left:0px;
margin-top:0px;
cursor:default;
font-family: verdana, Tahoma, Geneva, sans-serif;
}
#tapBkg{
background-image:url('https://caljer1.github.io/MetronomeLite/img/tap_bkg.png');
width:115;
height:131;
position:relative;
top:-29px;
left:168px;
visibility:hidden;
}
#tempoUp{
position:relative;
top:41px;
left:133px;
width:28px;
height:28px;
cursor:pointer;
}
#tempoDown{
position:relative;
top:247px;
left:133px;
width:28px;
height:28px;
cursor:pointer;
}
#Beat{
position:relative;
top:40px;
left:109px;
width:68px;
height:105px;
text-align:center;
font-size:100px;
font-family: Viga, Tahoma, Geneva, sans-serif;
}
#BellButton{
}
#timeSignature{
position:relative;
top:20px;
left:68px;
width:38px;
height:15px;
text-align:center;
font-size:10px;
}
#timeSignature:hover{
color:#c32e2e;
font-weight:bold;
}
#tap{
position:relative;
top:-159px;
left:236px;
width:44px;
height:15px;
text-align:right;
font-size:12px;
color:#a3a3a3;
cursor:pointer;
}
#tap:hover{
color:white;
}
#power{
position:absolute;
background-image:url('https://caljer1.github.io/MetronomeLite/img/power.png');
top:150px;
left:290px;
width:21px;
height:32px;
cursor:pointer;
}
#power:hover{
background-image:url('https://caljer1.github.io/MetronomeLite/img/power_focus.png');
}
#TempoContainer{
position:relative;
color:white;
top:50px;
left:105px;
width:78px;
height:19px;
text-align:center;
font-size:16px;
font-family: Viga, Tahoma, Geneva, sans-serif;
}
.unselectable {
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
user-select: none;
}
/**********************************************************
* Metronome Lite based on JSMetronome (Copyright notice below)
* Assets located on github repository
***********************************************************/
/**********************************************************
* JSMetronome v0.1 (Apr 2012)
* Copyright (C) 2012 www.colxi.info
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2 of the License.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* http://www.gnu.org/licenses/gpl-2.0.html
* This program is modified by guitare-electrique.org on 2019
***********************************************************/
var JSmetronome = {
GUI:{
power : document.getElementById("power"),
tap : document.getElementById("tap"),
tapBkg : document.getElementById("tapBkg"),
tempoUp : document.getElementById("tempoUp"),
tempoDown : document.getElementById("tempoDown"),
tempoDisplay : document.getElementById("tempoDisplay"),
metronomeTick : document.getElementById("metronomeTick_1"),
metronomeBell : document.getElementById("metronomeBell"),
timeSignature : document.getElementById("timeSignature"),
beatDisplay : document.getElementById("Beat")
},
vars:{
power : false,
tempo : 0,
BeatsPerMeasure:0,
BeatSubdivision:0,
CurrentBeatSubdivision:0,
currentBeat : 0,
lastTap : 0,
_timeoutID : 0,
_tempoMin : 1,
_tempoMax : 250,
_timeSignature:[
// name , beats, time subdivision(2 = binary / 3 = ternary)
[2,4,2],
[3,4,2],
[4,4,2],
[6,8,3],
[9,8,3],
[12,8,3]
]
},
setTimeSignature: function(timeSignature){
//chekc if it's a number
if(!isNaN(parseFloat(timeSignature)) && isFinite(timeSignature)){
// if its positive, rotate one step positive or negative the array items. Selected item, result as first of list.
if(timeSignature >= 0){
// positive array rotation
var currentTimeSignature = this.vars._timeSignature.shift();
this.vars._timeSignature.push(currentTimeSignature);
currentTimeSignature = this.vars._timeSignature[0];
}else{
// negative array rotation
var currentTimeSignature = this.vars._timeSignature.pop();
this.vars._timeSignature.unshift(currentTimeSignature);
currentTimeSignature = this.vars._timeSignature[0];
};
}else{
// If timesignature provided as String (ex. "4/4"), find coincidences with array items
var currentTimeSignature= timeSignature.split("/");
for(var i=0; i < this.vars._timeSignature.length; i++) {
if(this.vars._timeSignature[i][0]== currentTimeSignature[0] && this.vars._timeSignature[i][1]== currentTimeSignature[1]){
currentTimeSignature[2] = this.vars._timeSignature[i][2];
for(var r=0; r < i; r++) this.setTimeSignature(+1);
};
}
if(!currentTimeSignature[2]) return false;
}
//config system with new Time Signature params.
this.vars.BeatSubdivision = currentTimeSignature[2];
this.vars.BeatsPerMeasure = (this.vars.BeatSubdivision == 3) ? (currentTimeSignature[0]/3) : currentTimeSignature[0];
//reinitiate counters
this.vars.currentBeat = 0;
this.vars.CurrentBeatSubdivision = 0;
//draw interface
this.GUI.timeSignature.innerHTML = currentTimeSignature[0] + "/" + currentTimeSignature[1];
//document.body.style.background='url('+background')';
//reset and restart.
clearTimeout(this.vars._timeoutID);
this.tick();
return true;
},
setTempo: function(newTempo,operator){
if(operator) var newTempo = (operator == "+") ? this.vars.tempo + newTempo : this.vars.tempo - newTempo;
if(newTempo >= this.vars._tempoMax) newTempo = this.vars._tempoMax;
if(newTempo <= this.vars._tempoMin) newTempo = this.vars._tempoMin;
this.vars.tempo = newTempo;
this.GUI.tempoDisplay.innerHTML = this.vars.tempo;
this.vars.currentBeat = 0;
this.vars.CurrentBeatSubdivision = 0;
clearTimeout(this.vars._timeoutID);
this.tick();
return true;
},
tick: function(){
if(!this.vars.power) return false;
if(this.vars.currentBeat >= this.vars.BeatsPerMeasure) this.vars.currentBeat = 1;
else this.vars.currentBeat += 1;
this.GUI.metronomeBell.pause();
this.GUI.metronomeBell.currentTime = 0;
this.GUI.metronomeTick.pause();
this.GUI.metronomeTick.currentTime = 0;
//if(this.vars.currentBeat == 1) this.GUI.metronomeBell.play();
this.GUI.metronomeTick.play();
this.GUI.beatDisplay.innerHTML = this.vars.currentBeat;
this.vars._timeoutID = setTimeout(function(){this.tick()}.bind(this), 1000/(this.vars.tempo/60));
return true;
},
tap: function(){
this.GUI.tapBkg.style.visibility = "visible";
var lastTapTime = this.vars.lastTap;
var currentTapTime = new Date().getTime();
this.vars.lastTap = currentTapTime;
var newTempo = Math.round(1000/(currentTapTime-lastTapTime)*60);
this.setTempo(newTempo);
return true;
},
power: function(status){
if(this.vars.power){
this.vars.power = false;
clearTimeout(this.vars._timeoutID);
this.vars.currentBeat = 0;
this.GUI.beatDisplay.innerHTML = this.vars.currentBeat;
}else{
this.vars.power = true;
this.tick();
};
},
init: function(){
this.GUI.timeSignature.onmousedown = function(){this.setTimeSignature(+1)}.bind(this);
this.GUI.power.onmousedown = function(){this.power()}.bind(this);
this.GUI.tap.onmousedown = function(){this.tap()}.bind(this);
this.GUI.tap.onmouseup = function(){this.GUI.tapBkg.style.visibility = "hidden "}.bind(this);
this.GUI.tap.onmouseout = function(){this.GUI.tapBkg.style.visibility = "hidden"}.bind(this);
this.GUI.tempoUp.onmousedown = function(){ProgInterval.add(function(){this.setTempo(1,'+')}.bind(this),1000,0.18,'tempoUp')}.bind(this);
this.GUI.tempoUp.onmouseup = function(){ProgInterval.del('tempoUp')}.bind(this);
this.GUI.tempoUp.onmouseout = function(){ProgInterval.del('tempoUp')}.bind(this);
this.GUI.tempoDown.onmousedown = function(){ProgInterval.add(function(){this.setTempo(1,'-')}.bind(this),1000,0.18,'tempoDown')}.bind(this);
this.GUI.tempoDown.onmouseup = function(){ProgInterval.del('tempoDown')}.bind(this);
this.GUI.tempoDown.onmouseout = function(){ProgInterval.del('tempoDown')}.bind(this);
this.setTimeSignature("4/4");
this.setTempo(60);
return true;
}
}
var ProgInterval = {
_active: [],
_exec: function(callback,interval,acceleration,ID){
if(this._active.indexOf(ID) == -1) return false;
callback();
interval += interval*(acceleration*(-1));
if(interval <= 1) interval = 1;
//console.log(interval);
setTimeout(function(){this._exec(callback,interval,acceleration,ID)}.bind(this),interval);
},
add: function(callback,interval,acceleration,ID){
var acceleration = acceleration || 0;
this._active.push(ID);
this._exec(callback,interval,acceleration,ID);
},
del: function(ID){
var position = this._active.indexOf(ID);
if(position != -1) this._active.splice(position,1);
}
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.