From c661ac7ccea4a4cf0b9d994f6c973d2330106939 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Thu, 1 Feb 2018 19:53:41 -0500 Subject: [PATCH 1/4] Only measure loudness once per step --- src/blocks/scratch3_sensing.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index f7a39b6b..acecc373 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -1,4 +1,5 @@ const Cast = require('../util/cast'); +const Timer = require('../util/timer'); class Scratch3SensingBlocks { constructor (runtime) { @@ -23,6 +24,8 @@ class Scratch3SensingBlocks { this.runtime.on('ANSWER', this._onAnswer.bind(this)); this.runtime.on('PROJECT_START', this._resetAnswer.bind(this)); this.runtime.on('PROJECT_STOP_ALL', this._clearAllQuestions.bind(this)); + + this.timer = new Timer(); } /** @@ -217,7 +220,19 @@ class Scratch3SensingBlocks { getLoudness () { if (typeof this.runtime.audioEngine === 'undefined') return -1; - return this.runtime.audioEngine.getLoudness(); + if (typeof this.runtime.currentStepTime === 'undefined') return -1; + + // Only measure loudness once per step + if (this.loudnessTime) { + const timeSinceLoudness = this.timer.time() - this.loudnessTime; + if (timeSinceLoudness < this.runtime.currentStepTime) { + return this.loudness; + } + } + + this.loudnessTime = this.timer.time(); + this.loudness = this.runtime.audioEngine.getLoudness(); + return this.loudness; } getAttributeOf (args) { From 0a239005a9585e203fb9ad17485b5a1fe979b0cd Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Tue, 6 Feb 2018 11:06:48 -0500 Subject: [PATCH 2/4] Rename and initialize vars --- src/blocks/scratch3_sensing.js | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index acecc373..fd60c4ca 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -15,6 +15,24 @@ class Scratch3SensingBlocks { */ this._answer = ''; + /** + * The timer utility. + * @type {Timer} + */ + this._timer = new Timer(); + + /** + * The stored microphone loudness measurement. + * @type {number} + */ + this._cachedLoudness = -1; + + /** + * The time of the most recent microphone loudness measurement. + * @type {number} + */ + this._cachedLoudnessTimestamp = 0; + /** * The list of queued questions and respective `resolve` callbacks. * @type {!Array} @@ -24,8 +42,6 @@ class Scratch3SensingBlocks { this.runtime.on('ANSWER', this._onAnswer.bind(this)); this.runtime.on('PROJECT_START', this._resetAnswer.bind(this)); this.runtime.on('PROJECT_STOP_ALL', this._clearAllQuestions.bind(this)); - - this.timer = new Timer(); } /** @@ -223,16 +239,14 @@ class Scratch3SensingBlocks { if (typeof this.runtime.currentStepTime === 'undefined') return -1; // Only measure loudness once per step - if (this.loudnessTime) { - const timeSinceLoudness = this.timer.time() - this.loudnessTime; - if (timeSinceLoudness < this.runtime.currentStepTime) { - return this.loudness; - } + const timeSinceLoudness = this._timer.time() - this._cachedLoudnessTimestamp; + if (timeSinceLoudness < this.runtime.currentStepTime) { + return this._cachedLoudness; } - this.loudnessTime = this.timer.time(); - this.loudness = this.runtime.audioEngine.getLoudness(); - return this.loudness; + this._cachedLoudnessTimestamp = this._timer.time(); + this._cachedLoudness = this.runtime.audioEngine.getLoudness(); + return this._cachedLoudness; } getAttributeOf (args) { From 33966ba5829a0c723e1e528719e7fde4589dd975 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Tue, 6 Feb 2018 12:25:44 -0500 Subject: [PATCH 3/4] Check for runtime.currentStepTime is null --- src/blocks/scratch3_sensing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blocks/scratch3_sensing.js b/src/blocks/scratch3_sensing.js index fd60c4ca..2c19683a 100644 --- a/src/blocks/scratch3_sensing.js +++ b/src/blocks/scratch3_sensing.js @@ -236,7 +236,7 @@ class Scratch3SensingBlocks { getLoudness () { if (typeof this.runtime.audioEngine === 'undefined') return -1; - if (typeof this.runtime.currentStepTime === 'undefined') return -1; + if (this.runtime.currentStepTime === null) return -1; // Only measure loudness once per step const timeSinceLoudness = this._timer.time() - this._cachedLoudnessTimestamp; From c32086f56aa25c2046b176676be8ff68514a7ad9 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Tue, 6 Feb 2018 12:26:20 -0500 Subject: [PATCH 4/4] Unit test for loudness with caching --- test/unit/blocks_sensing.js | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/unit/blocks_sensing.js b/test/unit/blocks_sensing.js index 33b48446..a67a8ae0 100644 --- a/test/unit/blocks_sensing.js +++ b/test/unit/blocks_sensing.js @@ -83,3 +83,43 @@ test('set drag mode', t => { t.end(); }); + +test('get loudness with caching', t => { + const rt = new Runtime(); + const sensing = new Sensing(rt); + + // It should report -1 when audio engine is not available. + t.strictEqual(sensing.getLoudness(), -1); + + // Stub the audio engine with its getLoudness function, and set up different + // values to simulate it changing over time. + const firstLoudness = 1; + const secondLoudness = 2; + let simulatedLoudness = firstLoudness; + rt.audioEngine = {getLoudness: () => simulatedLoudness}; + + // It should report -1 when current step time is null. + t.strictEqual(sensing.getLoudness(), -1); + + // Stub the current step time. + rt.currentStepTime = 1000 / 30; + + // The first time it works, it should report the result from the stubbed audio engine. + t.strictEqual(sensing.getLoudness(), firstLoudness); + + // Update the simulated loudness to a new value. + simulatedLoudness = secondLoudness; + + // Simulate time passing by advancing the timer forward a little bit. + // After less than a step, it should still report cached loudness. + let simulatedTime = Date.now() + (rt.currentStepTime / 2); + sensing._timer = {time: () => simulatedTime}; + t.strictEqual(sensing.getLoudness(), firstLoudness); + + // Simulate more than a step passing. It should now request the value + // from the audio engine again. + simulatedTime += rt.currentStepTime; + t.strictEqual(sensing.getLoudness(), secondLoudness); + + t.end(); +});