scratch-audio
Advanced tools
Comparing version 0.1.0-prerelease.20180621194059 to 0.1.0-prerelease.20180621200816
{ | ||
"name": "scratch-audio", | ||
"version": "0.1.0-prerelease.20180621194059", | ||
"version": "0.1.0-prerelease.20180621200816", | ||
"description": "audio engine for scratch 3.0", | ||
@@ -36,6 +36,7 @@ "main": "dist.js", | ||
"eslint-config-scratch": "^3.1.0", | ||
"tap": "^12.0.1", | ||
"web-audio-test-api": "^0.5.2", | ||
"webpack": "^4.8.0", | ||
"webpack-cli": "^2.0.15", | ||
"tap": "^12.0.1" | ||
"webpack-cli": "^2.0.15" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
const StartAudioContext = require('startaudiocontext'); | ||
const StartAudioContext = require('./StartAudioContext'); | ||
const AudioContext = require('audio-context'); | ||
@@ -38,3 +38,3 @@ | ||
class AudioEngine { | ||
constructor () { | ||
constructor (audioContext = new AudioContext()) { | ||
/** | ||
@@ -45,3 +45,3 @@ * AudioContext to play and manipulate sounds with a graph of source | ||
*/ | ||
this.audioContext = new AudioContext(); | ||
this.audioContext = audioContext; | ||
StartAudioContext(this.audioContext); | ||
@@ -71,2 +71,10 @@ | ||
/** | ||
* Current time in the AudioEngine. | ||
* @type {number} | ||
*/ | ||
get currentTime () { | ||
return this.audioContext.currentTime; | ||
} | ||
/** | ||
* Names of the audio effects. | ||
@@ -73,0 +81,0 @@ * @enum {string} |
@@ -85,3 +85,6 @@ /** | ||
// Store whether the graph should currently affected by this effect. | ||
const _isPatch = this._isPatch; | ||
const wasPatch = this._isPatch; | ||
if (wasPatch) { | ||
this._lastPatch = this.audioEngine.currentTime; | ||
} | ||
@@ -93,3 +96,3 @@ // Call the internal implementation per this Effect. | ||
// applies an effect. | ||
if (this._isPatch !== _isPatch && this.target !== null) { | ||
if (this._isPatch !== wasPatch && this.target !== null) { | ||
this.connect(this.target); | ||
@@ -138,3 +141,3 @@ } | ||
if (this._isPatch) { | ||
if (this._isPatch || this._lastPatch + this.audioEngine.DECAY_TIME < this.audioEngine.currentTime) { | ||
this.outputNode.connect(target.getInputNode()); | ||
@@ -141,0 +144,0 @@ } |
@@ -35,9 +35,7 @@ const Effect = require('./Effect'); | ||
this.value = value; | ||
// A gain of 1 is normal. Scale down scratch's volume value. Apply the | ||
// change over a tiny period of time. | ||
this.outputNode.gain.setTargetAtTime( | ||
value / 100, | ||
this.audioEngine.audioContext.currentTime, | ||
this.audioEngine.DECAY_TIME | ||
); | ||
const {gain} = this.outputNode; | ||
const {audioContext: {currentTime}, DECAY_TIME} = this.audioEngine; | ||
gain.setValueAtTime(gain.value, currentTime); | ||
gain.linearRampToValueAtTime(value / 100, currentTime + DECAY_TIME); | ||
} | ||
@@ -44,0 +42,0 @@ |
@@ -30,2 +30,3 @@ const {EventEmitter} = require('events'); | ||
this.outputNode = null; | ||
this.volumeEffect = null; | ||
this.target = null; | ||
@@ -37,2 +38,7 @@ | ||
this.playbackRate = 1; | ||
// handleEvent is a EventTarget api for the DOM, however the web-audio-test-api we use | ||
// uses an addEventListener that isn't compatable with object and requires us to pass | ||
// this bound function instead | ||
this.handleEvent = this.handleEvent.bind(this); | ||
} | ||
@@ -73,3 +79,3 @@ | ||
if (this.outputNode !== null) { | ||
this.outputNode.removeEventListener(ON_ENDED, this); | ||
this.outputNode.removeEventListener(ON_ENDED, this.handleEvent); | ||
this.outputNode.disconnect(); | ||
@@ -82,3 +88,3 @@ } | ||
this.outputNode.addEventListener(ON_ENDED, this); | ||
this.outputNode.addEventListener(ON_ENDED, this.handleEvent); | ||
@@ -96,4 +102,2 @@ if (this.target !== null) { | ||
this.volumeEffect = new VolumeEffect(this.audioEngine, this, null); | ||
this._createSource(); | ||
@@ -120,3 +124,8 @@ } | ||
this.volumeEffect.connect(target); | ||
if (this.volumeEffect === null) { | ||
this.outputNode.disconnect(); | ||
this.outputNode.connect(target.getInputNode()); | ||
} else { | ||
this.volumeEffect.connect(target); | ||
} | ||
@@ -136,4 +145,6 @@ return this; | ||
this.volumeEffect.dispose(); | ||
this.volumeEffect = null; | ||
if (this.volumeEffect !== null) { | ||
this.volumeEffect.dispose(); | ||
this.volumeEffect = null; | ||
} | ||
@@ -159,3 +170,3 @@ this.outputNode.disconnect(); | ||
if (this.outputNode) { | ||
this.outputNode.removeEventListener(ON_ENDED, this); | ||
this.outputNode.removeEventListener(ON_ENDED, this.handleEvent); | ||
} | ||
@@ -168,13 +179,13 @@ | ||
taken.isPlaying = this.isPlaying; | ||
taken.initialize(); | ||
taken.outputNode.disconnect(); | ||
taken.initialized = this.initialized; | ||
taken.outputNode = this.outputNode; | ||
taken.outputNode.addEventListener(ON_ENDED, taken); | ||
taken.volumeEffect.set(this.volumeEffect.value); | ||
taken.outputNode.addEventListener(ON_ENDED, taken.handleEvent); | ||
taken.volumeEffect = this.volumeEffect; | ||
if (taken.volumeEffect) { | ||
taken.volumeEffect.audioPlayer = taken; | ||
} | ||
if (this.target !== null) { | ||
taken.connect(this.target); | ||
} | ||
} | ||
if (this.isPlaying) { | ||
this.emit('stop'); | ||
@@ -185,5 +196,2 @@ taken.emit('play'); | ||
this.outputNode = null; | ||
if (this.volumeEffect !== null) { | ||
this.volumeEffect.dispose(); | ||
} | ||
this.volumeEffect = null; | ||
@@ -205,2 +213,4 @@ this.initialized = false; | ||
if (this.isStarting) { | ||
this.emit('stop'); | ||
this.emit('play'); | ||
return; | ||
@@ -210,15 +220,11 @@ } | ||
if (this.isPlaying) { | ||
// Spawn a Player with the current buffer source, and play for a | ||
// short period until its volume is 0 and release it to be | ||
// eventually garbage collected. | ||
this.take().stop(); | ||
this.stop(); | ||
} | ||
if (!this.initialized) { | ||
if (this.initialized) { | ||
this._createSource(); | ||
} else { | ||
this.initialize(); | ||
} else { | ||
this._createSource(); | ||
} | ||
this.volumeEffect.set(this.volumeEffect.DEFAULT_VALUE); | ||
this.outputNode.start(); | ||
@@ -241,9 +247,16 @@ | ||
this.volumeEffect.set(0); | ||
this.outputNode.stop(this.audioEngine.audioContext.currentTime + this.audioEngine.DECAY_TIME); | ||
// always do a manual stop on a taken / volume effect fade out sound player | ||
// take will emit "stop" as well as reset all of our playing statuses / remove our | ||
// nodes / etc | ||
const taken = this.take(); | ||
taken.volumeEffect = new VolumeEffect(taken.audioEngine, taken, null); | ||
this.isPlaying = false; | ||
this.startingUntil = 0; | ||
taken.volumeEffect.connect(taken.target); | ||
// volumeEffect will recursively connect to us if it needs to, so this happens too: | ||
// taken.connect(taken.volumeEffect); | ||
this.emit('stop'); | ||
taken.finished().then(() => taken.dispose()); | ||
taken.volumeEffect.set(0); | ||
taken.outputNode.stop(this.audioEngine.audioContext.currentTime + this.audioEngine.DECAY_TIME); | ||
} | ||
@@ -250,0 +263,0 @@ |
@@ -5,4 +5,10 @@ class AudioParamMock { | ||
} | ||
setValueAtTime (value) { | ||
this.value = value; | ||
} | ||
linearRampToValueAtTime (value) { | ||
this.value = value; | ||
} | ||
} | ||
module.exports = AudioParamMock; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
551962
61
3880
10