diff --git a/src/blocks/scratch3_sound.js b/src/blocks/scratch3_sound.js index ea8c5e865..f79575b24 100644 --- a/src/blocks/scratch3_sound.js +++ b/src/blocks/scratch3_sound.js @@ -16,6 +16,11 @@ class Scratch3SoundBlocks { this.runtime.on('PROJECT_STOP_ALL', this._clearEffectsForAllTargets); this.runtime.on('PROJECT_START', this._clearEffectsForAllTargets); } + + this._onTargetCreated = this._onTargetCreated.bind(this); + if (this.runtime) { + runtime.on('targetWasCreated', this._onTargetCreated); + } } /** @@ -88,6 +93,23 @@ class Scratch3SoundBlocks { return soundState; } + /** + * When a Target is cloned, clone the sound state. + * @param {Target} newTarget - the newly created target. + * @param {Target} [sourceTarget] - the target used as a source for the new clone, if any. + * @listens Runtime#event:targetWasCreated + * @private + */ + _onTargetCreated (newTarget, sourceTarget) { + if (sourceTarget) { + const soundState = sourceTarget.getCustomState(Scratch3SoundBlocks.STATE_KEY); + if (soundState && newTarget) { + newTarget.setCustomState(Scratch3SoundBlocks.STATE_KEY, Clone.simple(soundState)); + this._syncEffectsForTarget(newTarget); + } + } + } + /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. @@ -208,6 +230,15 @@ class Scratch3SoundBlocks { util.target.audioPlayer.setEffect(effect, soundState.effects[effect]); } + _syncEffectsForTarget (target) { + if (!target || !target.audioPlayer) return; + const soundState = this._getSoundState(target); + for (const effect in soundState.effects) { + if (!soundState.effects.hasOwnProperty(effect)) continue; + target.audioPlayer.setEffect(effect, soundState.effects[effect]); + } + } + clearEffects (args, util) { this._clearEffectsForTarget(util.target); } diff --git a/src/sprites/rendered-target.js b/src/sprites/rendered-target.js index 5f126256f..515a30a0e 100644 --- a/src/sprites/rendered-target.js +++ b/src/sprites/rendered-target.js @@ -131,17 +131,15 @@ class RenderedTarget extends Target { 'control_start_as_clone', null, this ); } + } - /** - * Audio player - */ + /** + * Initialize the audio player for this sprite or clone. + */ + initAudio () { this.audioPlayer = null; if (this.runtime && this.runtime.audioEngine) { - if (this.isOriginal) { - this.audioPlayer = this.runtime.audioEngine.createPlayer(); - } else { - this.audioPlayer = this.sprite.clones[0].audioPlayer; - } + this.audioPlayer = this.runtime.audioEngine.createPlayer(); } } @@ -940,6 +938,10 @@ class RenderedTarget extends Target { this.runtime.requestRedraw(); } } + if (this.audioPlayer) { + this.audioPlayer.stopAllSounds(); + this.audioPlayer.dispose(); + } } } diff --git a/src/sprites/sprite.js b/src/sprites/sprite.js index 268184343..bf68c98d1 100644 --- a/src/sprites/sprite.js +++ b/src/sprites/sprite.js @@ -56,6 +56,7 @@ class Sprite { const newClone = new RenderedTarget(this, this.runtime); newClone.isOriginal = this.clones.length === 0; this.clones.push(newClone); + newClone.initAudio(); if (newClone.isOriginal) { newClone.initDrawable(); this.runtime.fireTargetWasCreated(newClone);