From 0d76f669db81f88842cda70b21f6c2668f4f8c74 Mon Sep 17 00:00:00 2001 From: Matthieu Cesar Bonnardot Date: Thu, 21 Jan 2021 11:21:18 +0100 Subject: [PATCH 1/7] Added Default values to the set methods to avoid breaks --- metronome.js | 167 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 67 deletions(-) diff --git a/metronome.js b/metronome.js index 05555583..92e5dc4a 100644 --- a/metronome.js +++ b/metronome.js @@ -3,7 +3,7 @@ const DEFAULT_SCHEDULE_S = 0.1; const DEFAULT_BPM = 90; const DEFAULT_TIME_SIGNITURE = 16; const DEFAULT_NOTE_LENGTH = 0.05; -const DEFAULT_OSCILLATOR_TYPE = 'sine'; +const DEFAULT_OSCILLATOR_TYPE = "sine"; const DEFAULT_FREQUENCY = 220; const MIN_FREQUENCY = 40; const MINUTE = 15; @@ -13,12 +13,12 @@ const AudioContext = window.AudioContext || window.webkitAudioContext; //maybe c const audioCtx = new AudioContext(); class Metronome { - constructor( BPM = DEFAULT_BPM, timeSigniture = DEFAULT_TIME_SIGNITURE, - gain = DEFAULT_GAIN) { - //User mutable + gain = DEFAULT_GAIN + ) { + //User mutable this._BPM = BPM; this._timeSigniture = timeSigniture; this._gain = gain; @@ -28,12 +28,12 @@ class Metronome { this._oscillatorType = DEFAULT_OSCILLATOR_TYPE; this._frequency = DEFAULT_FREQUENCY; - //Functionally assigned + //Functionally assigned this._samplesArray = []; this._samplesLoaded = false; this._accentChecked = false; - //Internal values + //Internal values this._notesInQueue = []; this._playing = false; this._timerID; @@ -41,15 +41,14 @@ class Metronome { this._currentNote = 0; this._lookahead = DEFAULT_LOOKAHEAD_MS; this._scheduleAheadTime = DEFAULT_SCHEDULE_S; - - }; + } //Client settings ---------------------------------------- - set BPM(newBPM) { + set BPM(newBPM = DEFAULT_BPM) { this._BPM = Number(newBPM); } - set timeSigniture(newTimeSigniture) { + set timeSigniture(newTimeSigniture = DEFAULT_TIME_SIGNATURE) { this._timeSigniture = Number(newTimeSigniture); } @@ -58,44 +57,51 @@ class Metronome { } set noteVolumes(volumesArray) { - this._noteVolumes = volumesArray; + if (volumesArray) this._noteVolumes = volumesArray; + else console.error("No array of volumes has been passed."); } set budge(time) { - this._pushNote = time; + if (time) this._pushNote = time; + else console.error("No time has been passed."); } set noteLength(time) { - this._noteLength = Number(time); + if (time) this._noteLength = Number(time); + else console.error("No time has been passed."); } set oscillatorType(wave) { - let newWaveType; - switch (wave) { - case 'sine': - case 'square': - case 'sawtooth': - case 'triangle': - newWaveType = wave; - break; - default: - newWaveType = DEFAULT_OSCILLATOR_TYPE; + if (wave) { + let newWaveType; + switch (wave) { + case "sine": + case "square": + case "sawtooth": + case "triangle": + newWaveType = wave; + break; + default: + newWaveType = DEFAULT_OSCILLATOR_TYPE; + } + this._oscillatorType = newWaveType; + } else { + console.error("No wave value has been passed."); } - this._oscillatorType = newWaveType; } - set frequency(freq) { + set frequency(freq = DEFAULT_FREQUENCY) { if (freq <= MIN_FREQUENCY) freq = MIN_FREQUENCY; this._frequency = freq; } - set gain(gain) { + set gain(gain = DEFAULT_GAIN) { this._noteVolumes = new Array(this._timeSigniture).fill(gain); } _valueChecks() { while (this._noteVolumes.length < this._timeSigniture) { - this._noteVolumes = [...this._noteVolumes, ...this._noteVolumes] + this._noteVolumes = [...this._noteVolumes, ...this._noteVolumes]; } } @@ -124,27 +130,43 @@ class Metronome { } // This allows output of the notesInQueue array to sync with graphics - aListener(val) {}; + aListener(val) {} registerListener(listener) { this.aListener = listener; } _scheduleSamples(beatNumber, time) { - this._notesInQueue.push({ note: beatNumber, time: time }); - this.aListener(this._notesInQueue, audioCtx.currentTime, this._samplesArray[0].name) - if (this._notesInQueue.length >= this._timeSigniture) this._notesInQueue.splice(0,1); + this.aListener( + this._notesInQueue, + audioCtx.currentTime, + this._samplesArray[0].name + ); + if (this._notesInQueue.length >= this._timeSigniture) + this._notesInQueue.splice(0, 1); if (this._accentChecked && this._samplesArray.length >= 2) { - if (beatNumber === this._timeSigniture - 1) this._playSample(audioCtx, this._samplesArray[1].audioBuffer, this._noteVolumes[beatNumber]); - else this._playSample(audioCtx, this._samplesArray[0].audioBuffer, this._noteVolumes[beatNumber]); + if (beatNumber === this._timeSigniture - 1) + this._playSample( + audioCtx, + this._samplesArray[1].audioBuffer, + this._noteVolumes[beatNumber] + ); + else + this._playSample( + audioCtx, + this._samplesArray[0].audioBuffer, + this._noteVolumes[beatNumber] + ); } else { - this._playSample(audioCtx, this._samplesArray[0].audioBuffer, this._noteVolumes[beatNumber]); + this._playSample( + audioCtx, + this._samplesArray[0].audioBuffer, + this._noteVolumes[beatNumber] + ); } - } _scheduleOscillator(beatNumber, time) { - this._notesInQueue.push({ note: beatNumber, time: time }); const oscillator = audioCtx.createOscillator(); @@ -155,69 +177,81 @@ class Metronome { oscillator.type = this._oscillatorType; if (this._noteVolumes[beatNumber] === 0) { - gainNode.gain.setValueAtTime(0, audioCtx.currentTime) + gainNode.gain.setValueAtTime(0, audioCtx.currentTime); } if (this._accentChecked) { - if (beatNumber === this._timeSigniture - 1) oscillator.frequency.value = this._frequency * 2; + if (beatNumber === this._timeSigniture - 1) + oscillator.frequency.value = this._frequency * 2; else oscillator.frequency.value = this._frequency; } else if (!this._accentChecked) { oscillator.frequency.value = this._frequency; } // if (this._noteVolumes[beatNumber] != 0) { - oscillator.start(time + this._pushNote); - oscillator.stop(time + this._noteLength + this._pushNote); + oscillator.start(time + this._pushNote); + oscillator.stop(time + this._noteLength + this._pushNote); // } } _scheduler() { - let context; if (!context) context = this; function contextScheduler() { - while (context._nextNoteTime < audioCtx.currentTime + context._scheduleAheadTime) { - if (context._samplesLoaded) context._scheduleSamples(context._currentNote, context._nextNoteTime); - else context._scheduleOscillator(context._currentNote, context._nextNoteTime); + while ( + context._nextNoteTime < + audioCtx.currentTime + context._scheduleAheadTime + ) { + if (context._samplesLoaded) + context._scheduleSamples(context._currentNote, context._nextNoteTime); + else + context._scheduleOscillator( + context._currentNote, + context._nextNoteTime + ); context._nextNote(); } - context._timerID = window.setTimeout(contextScheduler, context._lookahead); + context._timerID = window.setTimeout( + contextScheduler, + context._lookahead + ); } - contextScheduler() - + contextScheduler(); } //Deal with custom samples loadSamples(urlArray) { - this._setUpSample(urlArray) - .then(samples => { - this._samplesArray = [...samples]; - this._samplesLoaded = true; - }) + this._setUpSample(urlArray).then((samples) => { + this._samplesArray = [...samples]; + this._samplesLoaded = true; + }); } async _loadSound(audioCtxParam, filePath) { try { - const response = await fetch(filePath); - const arrayBuffer = await response.arrayBuffer() - const audioBuffer = await audioCtxParam.decodeAudioData(arrayBuffer); - return audioBuffer; + const response = await fetch(filePath); + const arrayBuffer = await response.arrayBuffer(); + const audioBuffer = await audioCtxParam.decodeAudioData(arrayBuffer); + return audioBuffer; } catch (e) { console.log(e); } - }; + } async _setUpSample(urlArray) { - return Promise.all(urlArray.map(async path => { - let sampleHolder = {}; - sampleHolder.audioBuffer = await this._loadSound(audioCtx, path); - sampleHolder.name = path.match(/([^\/]+)(?=\.\w+$)/)[0].replace(/-/, '_'); - return sampleHolder; - })) - .then(data => data); - }; + return Promise.all( + urlArray.map(async (path) => { + let sampleHolder = {}; + sampleHolder.audioBuffer = await this._loadSound(audioCtx, path); + sampleHolder.name = path + .match(/([^\/]+)(?=\.\w+$)/)[0] + .replace(/-/, "_"); + return sampleHolder; + }) + ).then((data) => data); + } _playSample(audioCtxParam, audioBuffer, noteVolume = 1) { const sampleSource = audioCtxParam.createBufferSource(); @@ -229,7 +263,6 @@ class Metronome { sampleSource.start(); return sampleSource; } - } -export default Metronome; \ No newline at end of file +export default Metronome; From 021b326f47f22fca3f499d98c7c4a1ff35bccaab Mon Sep 17 00:00:00 2001 From: Matthieu Cesar Bonnardot Date: Thu, 21 Jan 2021 11:33:35 +0100 Subject: [PATCH 2/7] Updated some of my changes --- metronome.js | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/metronome.js b/metronome.js index 92e5dc4a..fd423c7c 100644 --- a/metronome.js +++ b/metronome.js @@ -52,10 +52,6 @@ class Metronome { this._timeSigniture = Number(newTimeSigniture); } - updateAccentChecked() { - this._accentChecked ^= true; - } - set noteVolumes(volumesArray) { if (volumesArray) this._noteVolumes = volumesArray; else console.error("No array of volumes has been passed."); @@ -71,22 +67,16 @@ class Metronome { else console.error("No time has been passed."); } - set oscillatorType(wave) { - if (wave) { - let newWaveType; - switch (wave) { - case "sine": - case "square": - case "sawtooth": - case "triangle": - newWaveType = wave; - break; - default: - newWaveType = DEFAULT_OSCILLATOR_TYPE; - } - this._oscillatorType = newWaveType; - } else { - console.error("No wave value has been passed."); + set oscillatorType(wave = DEFAULT_OSCILLATOR_TYPE) { + switch (wave) { + case "sine": + case "square": + case "sawtooth": + case "triangle": + this._oscillatorType = wave; + break; + default: + this._oscillatorType = DEFAULT_OSCILLATOR_TYPE; } } @@ -99,6 +89,10 @@ class Metronome { this._noteVolumes = new Array(this._timeSigniture).fill(gain); } + updateAccentChecked() { + this._accentChecked ^= true; + } + _valueChecks() { while (this._noteVolumes.length < this._timeSigniture) { this._noteVolumes = [...this._noteVolumes, ...this._noteVolumes]; @@ -130,10 +124,10 @@ class Metronome { } // This allows output of the notesInQueue array to sync with graphics - aListener(val) {} - registerListener(listener) { - this.aListener = listener; - } + // aListener(val) {} + // registerListener(listener) { + // this.aListener = listener; + // } _scheduleSamples(beatNumber, time) { this._notesInQueue.push({ note: beatNumber, time: time }); From 3d336837c1994ae646a6757463d6665509899c6c Mon Sep 17 00:00:00 2001 From: Alexandra Date: Thu, 21 Jan 2021 11:52:46 +0100 Subject: [PATCH 3/7] commented out functions that were not currenty in use. --- metronome.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/metronome.js b/metronome.js index 05555583..bfd3c739 100644 --- a/metronome.js +++ b/metronome.js @@ -124,10 +124,10 @@ class Metronome { } // This allows output of the notesInQueue array to sync with graphics - aListener(val) {}; - registerListener(listener) { - this.aListener = listener; - } + // aListener(val) {}; + // registerListener(listener) { + // this.aListener = listener; + // } _scheduleSamples(beatNumber, time) { From c729ad5e6c07bd3bbbe9ee1638330f4221831adf Mon Sep 17 00:00:00 2001 From: Alexandra Date: Thu, 21 Jan 2021 12:23:02 +0100 Subject: [PATCH 4/7] correcting regex --- metronome.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/metronome.js b/metronome.js index bfd3c739..eeacecf8 100644 --- a/metronome.js +++ b/metronome.js @@ -134,6 +134,7 @@ class Metronome { this._notesInQueue.push({ note: beatNumber, time: time }); this.aListener(this._notesInQueue, audioCtx.currentTime, this._samplesArray[0].name) if (this._notesInQueue.length >= this._timeSigniture) this._notesInQueue.splice(0,1); + if (this._accentChecked && this._samplesArray.length >= 2) { if (beatNumber === this._timeSigniture - 1) this._playSample(audioCtx, this._samplesArray[1].audioBuffer, this._noteVolumes[beatNumber]); else this._playSample(audioCtx, this._samplesArray[0].audioBuffer, this._noteVolumes[beatNumber]); @@ -213,7 +214,7 @@ class Metronome { return Promise.all(urlArray.map(async path => { let sampleHolder = {}; sampleHolder.audioBuffer = await this._loadSound(audioCtx, path); - sampleHolder.name = path.match(/([^\/]+)(?=\.\w+$)/)[0].replace(/-/, '_'); + sampleHolder.name = path.match(/\/([^\/]+)\/?$/)[1].replace(/-/, '_'); return sampleHolder; })) .then(data => data); From 777dbe2fea690e7219659f9842ee640d3b76f9e7 Mon Sep 17 00:00:00 2001 From: Matthieu Cesar Bonnardot Date: Thu, 21 Jan 2021 12:54:46 +0100 Subject: [PATCH 5/7] Final changes --- metronome.js | 95 ++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/metronome.js b/metronome.js index fd423c7c..0c862fa2 100644 --- a/metronome.js +++ b/metronome.js @@ -52,16 +52,19 @@ class Metronome { this._timeSigniture = Number(newTimeSigniture); } + //array of num set noteVolumes(volumesArray) { if (volumesArray) this._noteVolumes = volumesArray; else console.error("No array of volumes has been passed."); } + //can be negative set budge(time) { if (time) this._pushNote = time; else console.error("No time has been passed."); } + //has to be positive. set noteLength(time) { if (time) this._noteLength = Number(time); else console.error("No time has been passed."); @@ -123,41 +126,34 @@ class Metronome { } } - // This allows output of the notesInQueue array to sync with graphics - // aListener(val) {} - // registerListener(listener) { - // this.aListener = listener; - // } - _scheduleSamples(beatNumber, time) { - this._notesInQueue.push({ note: beatNumber, time: time }); - this.aListener( - this._notesInQueue, - audioCtx.currentTime, - this._samplesArray[0].name - ); - if (this._notesInQueue.length >= this._timeSigniture) - this._notesInQueue.splice(0, 1); - if (this._accentChecked && this._samplesArray.length >= 2) { - if (beatNumber === this._timeSigniture - 1) - this._playSample( - audioCtx, - this._samplesArray[1].audioBuffer, - this._noteVolumes[beatNumber] - ); - else + if (beatNumber && time) { + this._notesInQueue.push({ note: beatNumber, time: time }); + + if (this._notesInQueue.length >= this._timeSigniture) + this._notesInQueue.splice(0, 1); + + if (this._accentChecked && this._samplesArray.length >= 2) { + if (beatNumber === this._timeSigniture - 1) + this._playSample( + audioCtx, + this._samplesArray[1].audioBuffer, + this._noteVolumes[beatNumber] + ); + else + this._playSample( + audioCtx, + this._samplesArray[0].audioBuffer, + this._noteVolumes[beatNumber] + ); + } else { this._playSample( audioCtx, this._samplesArray[0].audioBuffer, this._noteVolumes[beatNumber] ); - } else { - this._playSample( - audioCtx, - this._samplesArray[0].audioBuffer, - this._noteVolumes[beatNumber] - ); - } + } + } else console.error("No beatNumber or time provided.") } _scheduleOscillator(beatNumber, time) { @@ -234,28 +230,33 @@ class Metronome { } } + //Array [str] async _setUpSample(urlArray) { - return Promise.all( - urlArray.map(async (path) => { - let sampleHolder = {}; - sampleHolder.audioBuffer = await this._loadSound(audioCtx, path); - sampleHolder.name = path - .match(/([^\/]+)(?=\.\w+$)/)[0] - .replace(/-/, "_"); - return sampleHolder; - }) - ).then((data) => data); + if (urlArray) { + return Promise.all( + urlArray.map(async (path) => { + let sampleHolder = {}; + sampleHolder.audioBuffer = await this._loadSound(audioCtx, path); + sampleHolder.name = path + .match(/([^\/]+)(?=\.\w+$)/)[0] + .replace(/-/, "_"); + return sampleHolder; + }) + ).then((data) => data); + } else console.error("No path array had been provided"); } _playSample(audioCtxParam, audioBuffer, noteVolume = 1) { - const sampleSource = audioCtxParam.createBufferSource(); - const gainNode = audioCtx.createGain(); - sampleSource.buffer = audioBuffer; - sampleSource.connect(gainNode); - gainNode.connect(audioCtxParam.destination); - gainNode.gain.value = noteVolume; - sampleSource.start(); - return sampleSource; + if (audioCtxParam && audioBuffer) { + const sampleSource = audioCtxParam.createBufferSource(); + const gainNode = audioCtx.createGain(); + sampleSource.buffer = audioBuffer; + sampleSource.connect(gainNode); + gainNode.connect(audioCtxParam.destination); + gainNode.gain.value = noteVolume; + sampleSource.start(); + return sampleSource; + } else console.error("No Audio Parameters or Buffer had been provided"); } } From b6dd57eb49ee96cc02670cbb35e6bc4e8c0ab7f3 Mon Sep 17 00:00:00 2001 From: Matthieu Cesar Bonnardot Date: Thu, 21 Jan 2021 12:58:25 +0100 Subject: [PATCH 6/7] Update metronome.js --- metronome.js | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/metronome.js b/metronome.js index 0c862fa2..58897912 100644 --- a/metronome.js +++ b/metronome.js @@ -153,34 +153,34 @@ class Metronome { this._noteVolumes[beatNumber] ); } - } else console.error("No beatNumber or time provided.") + } else console.error("No beatNumber or time provided."); } _scheduleOscillator(beatNumber, time) { - this._notesInQueue.push({ note: beatNumber, time: time }); + if (beatNumber && time) { + this._notesInQueue.push({ note: beatNumber, time: time }); - const oscillator = audioCtx.createOscillator(); - const gainNode = audioCtx.createGain(); + const oscillator = audioCtx.createOscillator(); + const gainNode = audioCtx.createGain(); - oscillator.connect(gainNode); - gainNode.connect(audioCtx.destination); - oscillator.type = this._oscillatorType; + oscillator.connect(gainNode); + gainNode.connect(audioCtx.destination); + oscillator.type = this._oscillatorType; - if (this._noteVolumes[beatNumber] === 0) { - gainNode.gain.setValueAtTime(0, audioCtx.currentTime); - } - if (this._accentChecked) { - if (beatNumber === this._timeSigniture - 1) - oscillator.frequency.value = this._frequency * 2; - else oscillator.frequency.value = this._frequency; - } else if (!this._accentChecked) { - oscillator.frequency.value = this._frequency; - } + if (this._noteVolumes[beatNumber] === 0) { + gainNode.gain.setValueAtTime(0, audioCtx.currentTime); + } + if (this._accentChecked) { + if (beatNumber === this._timeSigniture - 1) + oscillator.frequency.value = this._frequency * 2; + else oscillator.frequency.value = this._frequency; + } else if (!this._accentChecked) { + oscillator.frequency.value = this._frequency; + } - // if (this._noteVolumes[beatNumber] != 0) { - oscillator.start(time + this._pushNote); - oscillator.stop(time + this._noteLength + this._pushNote); - // } + oscillator.start(time + this._pushNote); + oscillator.stop(time + this._noteLength + this._pushNote); + } else console.error("No beatNumber or time provided."); } _scheduler() { From 9d364a8379aeda1d0645365f714d980111edd54c Mon Sep 17 00:00:00 2001 From: Matthieu Cesar Bonnardot Date: Thu, 21 Jan 2021 12:59:52 +0100 Subject: [PATCH 7/7] Update metronome.js --- metronome.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/metronome.js b/metronome.js index 58897912..bc0aa3f9 100644 --- a/metronome.js +++ b/metronome.js @@ -237,9 +237,7 @@ class Metronome { urlArray.map(async (path) => { let sampleHolder = {}; sampleHolder.audioBuffer = await this._loadSound(audioCtx, path); - sampleHolder.name = path - .match(/([^\/]+)(?=\.\w+$)/)[0] - .replace(/-/, "_"); + sampleHolder.name = path.match(/\/([^\/]+)\/?$/)[1].replace(/-/, "_"); return sampleHolder; }) ).then((data) => data);