Last active
November 18, 2016 16:20
Revisions
-
mbarzeev revised this gist
Jul 31, 2013 . 2 changed files with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes.File renamed without changes. -
mbarzeev renamed this gist
Jul 31, 2013 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
mbarzeev created this gist
Jul 31, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,13 @@ // This is the "run" block of your main module .run(['$window', function (window) { // First, let's shim the requestAnimationFrame API, // with a setTimeout fallback window.requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; }]) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,5 @@ <!-- Given that you have a $scope with mytempo defined on it --> <div> <input type="number" ng-model="mytempo"> <metronome tempo="{{mytempo}}"></metronome> </div> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,99 @@ 'use strict'; angular.module('MyModule') .directive('metronome', ['$window', function (window) { return { restrict: 'E', scope: true, link: function ($scope, element, attrs) { $scope.audioContext = new webkitAudioContext(); $scope.isPlaying = false; $scope.current16thNote; $scope.tempo = parseInt(attrs.tempo, 10); $scope.lookahead = 25.0; $scope.scheduleAheadTime = 0.1; $scope.nextNoteTime = 0.0; $scope.noteResolution = 0; $scope.noteLength = 0.05; $scope.timerID = 0; $scope.minimumTempo = 30.0; $scope.maximumTempo = 230.0; attrs.$observe('tempo', function (value) { $scope.tempo = parseInt(value, 10); }); $scope.nextNote = function () { // Advance current note and time by a 16th note... var secondsPerBeat = 60.0 / $scope.tempo; // Notice this picks up the CURRENT // tempo value to calculate beat length. $scope.nextNoteTime += 0.25 * secondsPerBeat; // Add beat length to last beat time $scope.current16thNote++; // Advance the beat number, wrap to zero if ($scope.current16thNote === 16) { $scope.current16thNote = 0; } }, $scope.scheduleNote = function (beatNumber, time) { if (($scope.noteResolution === 1) && (beatNumber % 2)) { return; // we're not playing non-8th 16th notes } if (($scope.noteResolution === 2) && (beatNumber % 4)) { return; // we're not playing non-quarter 8th notes } // create an oscillator var osc = $scope.audioContext.createOscillator(); osc.connect($scope.audioContext.destination); if (!(beatNumber % 16)) { // beat 0 == low pitch osc.frequency.value = 220.0; } else if (beatNumber % 4) { // quarter notes = medium pitch osc.frequency.value = 440.0; } else { // other 16th notes = high pitch osc.frequency.value = 880.0; } // TODO: Once start()/stop() deploys on Safari and iOS, these should be changed. osc.noteOn(time); osc.noteOff(time + $scope.noteLength); }, $scope.scheduler = function () { // while there are notes that will need to play before the // next interval, schedule them and advance the pointer. while ($scope.nextNoteTime < $scope.audioContext.currentTime + $scope.scheduleAheadTime) { $scope.scheduleNote($scope.current16thNote, $scope.nextNoteTime); $scope.nextNote(); } $scope.timerID = window.setTimeout($scope.scheduler, $scope.lookahead); }, $scope.play = function () { $scope.isPlaying = !$scope.isPlaying; if ($scope.isPlaying) { // start playing $scope.current16thNote = 0; $scope.nextNoteTime = $scope.audioContext.currentTime; $scope.scheduler(); // kick off scheduling return 'stop'; } else { window.clearTimeout($scope.timerID); return 'play'; } }; $scope.getButtonText = function () { var result = $scope.isPlaying ? 'Stop': 'Play'; return result; }; }, template: '<div>' + '<input id="bpm" type="number" name="bpm" ng-model="tempo" min="{{minimumTempo}}" max="{{maximumTempo}}"> Bpm' + '<button ng-click="play()">{{getButtonText()}}</button>' + '</div>' }; }]);