mirror of
https://github.com/scratchfoundation/scratch-audio.git
synced 2024-12-22 22:12:48 -05:00
Merge pull request #85 from mzgoddard/volume-effect
add and use VolumeEffect in AudioPlayer
This commit is contained in:
commit
6c8edf52b9
4 changed files with 69 additions and 17 deletions
|
@ -1,5 +1,6 @@
|
||||||
const PitchEffect = require('./effects/PitchEffect');
|
|
||||||
const PanEffect = require('./effects/PanEffect');
|
const PanEffect = require('./effects/PanEffect');
|
||||||
|
const PitchEffect = require('./effects/PitchEffect');
|
||||||
|
const VolumeEffect = require('./effects/VolumeEffect');
|
||||||
|
|
||||||
const SoundPlayer = require('./SoundPlayer');
|
const SoundPlayer = require('./SoundPlayer');
|
||||||
|
|
||||||
|
@ -17,9 +18,11 @@ class AudioPlayer {
|
||||||
this.outputNode = this.audioEngine.audioContext.createGain();
|
this.outputNode = this.audioEngine.audioContext.createGain();
|
||||||
|
|
||||||
// Create the audio effects
|
// Create the audio effects
|
||||||
const pitchEffect = new PitchEffect(this.audioEngine, this, null);
|
const volumeEffect = new VolumeEffect(this.audioEngine, this, null);
|
||||||
|
const pitchEffect = new PitchEffect(this.audioEngine, this, volumeEffect);
|
||||||
const panEffect = new PanEffect(this.audioEngine, this, pitchEffect);
|
const panEffect = new PanEffect(this.audioEngine, this, pitchEffect);
|
||||||
this.effects = {
|
this.effects = {
|
||||||
|
volume: volumeEffect,
|
||||||
pitch: pitchEffect,
|
pitch: pitchEffect,
|
||||||
pan: panEffect
|
pan: panEffect
|
||||||
};
|
};
|
||||||
|
@ -28,6 +31,7 @@ class AudioPlayer {
|
||||||
// outputNode -> "pitchEffect" -> panEffect -> audioEngine.input
|
// outputNode -> "pitchEffect" -> panEffect -> audioEngine.input
|
||||||
panEffect.connect(this.audioEngine);
|
panEffect.connect(this.audioEngine);
|
||||||
pitchEffect.connect(panEffect);
|
pitchEffect.connect(panEffect);
|
||||||
|
volumeEffect.connect(pitchEffect);
|
||||||
|
|
||||||
// reset effects to their default parameters
|
// reset effects to their default parameters
|
||||||
this.clearEffects();
|
this.clearEffects();
|
||||||
|
@ -123,9 +127,6 @@ class AudioPlayer {
|
||||||
for (const effectName in this.effects) {
|
for (const effectName in this.effects) {
|
||||||
this.effects[effectName].clear();
|
this.effects[effectName].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.audioEngine === null) return;
|
|
||||||
this.outputNode.gain.setTargetAtTime(1.0, 0, this.audioEngine.DECAY_TIME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,8 +134,7 @@ class AudioPlayer {
|
||||||
* @param {number} value - the volume in range 0-100
|
* @param {number} value - the volume in range 0-100
|
||||||
*/
|
*/
|
||||||
setVolume (value) {
|
setVolume (value) {
|
||||||
if (this.audioEngine === null) return;
|
this.setEffect('volume', value);
|
||||||
this.outputNode.gain.setTargetAtTime(value / 100, 0, this.audioEngine.DECAY_TIME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,6 +142,7 @@ class AudioPlayer {
|
||||||
* @param {object} target - target whose node to should be connected
|
* @param {object} target - target whose node to should be connected
|
||||||
*/
|
*/
|
||||||
connect (target) {
|
connect (target) {
|
||||||
|
this.outputNode.disconnect();
|
||||||
this.outputNode.connect(target.getInputNode());
|
this.outputNode.connect(target.getInputNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +150,7 @@ class AudioPlayer {
|
||||||
* Clean up and disconnect audio nodes.
|
* Clean up and disconnect audio nodes.
|
||||||
*/
|
*/
|
||||||
dispose () {
|
dispose () {
|
||||||
|
this.effects.volume.dispose();
|
||||||
this.effects.pitch.dispose();
|
this.effects.pitch.dispose();
|
||||||
this.effects.pan.dispose();
|
this.effects.pan.dispose();
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class Effect {
|
||||||
* @return {boolean} is the effect affecting the graph?
|
* @return {boolean} is the effect affecting the graph?
|
||||||
*/
|
*/
|
||||||
get _isPatch () {
|
get _isPatch () {
|
||||||
return this.initialized;
|
return this.initialized && this.value !== this.DEFAULT_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +46,7 @@ class Effect {
|
||||||
* @return {AudioNode} - audio node that is the input for this effect
|
* @return {AudioNode} - audio node that is the input for this effect
|
||||||
*/
|
*/
|
||||||
getInputNode () {
|
getInputNode () {
|
||||||
if (this.initialized) {
|
if (this._isPatch) {
|
||||||
return this.inputNode;
|
return this.inputNode;
|
||||||
}
|
}
|
||||||
return this.target.getInputNode();
|
return this.target.getInputNode();
|
||||||
|
@ -117,6 +117,10 @@ class Effect {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.outputNode !== null) {
|
||||||
|
this.outputNode.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
let nextTarget = target;
|
let nextTarget = target;
|
||||||
if (this._isPatch) {
|
if (this._isPatch) {
|
||||||
nextTarget = this;
|
nextTarget = this;
|
||||||
|
|
|
@ -20,14 +20,6 @@ class PanEffect extends Effect {
|
||||||
this.channelMerger = null;
|
this.channelMerger = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Should the effect be connected to the audio graph?
|
|
||||||
* @return {boolean} is the effect affecting the graph?
|
|
||||||
*/
|
|
||||||
get _isPatch () {
|
|
||||||
return this.initialized && this.value !== 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the Effect.
|
* Initialize the Effect.
|
||||||
* Effects start out uninitialized. Then initialize when they are first set
|
* Effects start out uninitialized. Then initialize when they are first set
|
||||||
|
|
54
src/effects/VolumeEffect.js
Normal file
54
src/effects/VolumeEffect.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
const Effect = require('./Effect');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Affect the volume of an effect chain.
|
||||||
|
*/
|
||||||
|
class VolumeEffect extends Effect {
|
||||||
|
/**
|
||||||
|
* Default value to set the Effect to when constructed and when clear'ed.
|
||||||
|
* @const {number}
|
||||||
|
*/
|
||||||
|
get DEFAULT_VALUE () {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Effect.
|
||||||
|
* Effects start out uninitialized. Then initialize when they are first set
|
||||||
|
* with some value.
|
||||||
|
* @throws {Error} throws when left unimplemented
|
||||||
|
*/
|
||||||
|
initialize () {
|
||||||
|
this.inputNode = this.audioEngine.audioContext.createGain();
|
||||||
|
this.outputNode = this.inputNode;
|
||||||
|
|
||||||
|
this.initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the effects value.
|
||||||
|
* @private
|
||||||
|
* @param {number} value - new value to set effect to
|
||||||
|
*/
|
||||||
|
_set (value) {
|
||||||
|
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, 0, this.audioEngine.DECAY_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up and disconnect audio nodes.
|
||||||
|
*/
|
||||||
|
dispose () {
|
||||||
|
this.outputNode.disconnect();
|
||||||
|
|
||||||
|
this.inputNode = null;
|
||||||
|
this.outputNode = null;
|
||||||
|
this.target = null;
|
||||||
|
|
||||||
|
this.initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = VolumeEffect;
|
Loading…
Reference in a new issue