mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-24 06:52:40 -05:00
Merge pull request #1972 from mzgoddard/sound-bank-over-sprite
Sound bank over sprite
This commit is contained in:
commit
33f4482127
5 changed files with 29 additions and 22 deletions
|
@ -8,10 +8,10 @@ const log = require('../util/log');
|
||||||
* @property {Buffer} data - sound data will be written here once loaded.
|
* @property {Buffer} data - sound data will be written here once loaded.
|
||||||
* @param {!Asset} soundAsset - the asset loaded from storage.
|
* @param {!Asset} soundAsset - the asset loaded from storage.
|
||||||
* @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
|
* @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
|
||||||
* @param {Sprite} sprite - Scratch sprite to add sounds to.
|
* @param {SoundBank} soundBank - Scratch Audio SoundBank to add sounds to.
|
||||||
* @returns {!Promise} - a promise which will resolve to the sound when ready.
|
* @returns {!Promise} - a promise which will resolve to the sound when ready.
|
||||||
*/
|
*/
|
||||||
const loadSoundFromAsset = function (sound, soundAsset, runtime, sprite) {
|
const loadSoundFromAsset = function (sound, soundAsset, runtime, soundBank) {
|
||||||
sound.assetId = soundAsset.assetId;
|
sound.assetId = soundAsset.assetId;
|
||||||
if (!runtime.audioEngine) {
|
if (!runtime.audioEngine) {
|
||||||
log.error('No audio engine present; cannot load sound asset: ', sound.md5);
|
log.error('No audio engine present; cannot load sound asset: ', sound.md5);
|
||||||
|
@ -30,8 +30,8 @@ const loadSoundFromAsset = function (sound, soundAsset, runtime, sprite) {
|
||||||
sound.rate = soundBuffer.sampleRate;
|
sound.rate = soundBuffer.sampleRate;
|
||||||
sound.sampleCount = soundBuffer.length;
|
sound.sampleCount = soundBuffer.length;
|
||||||
|
|
||||||
if (sprite.soundBank !== null) {
|
if (soundBank !== null) {
|
||||||
sprite.soundBank.addSoundPlayer(soundPlayer);
|
soundBank.addSoundPlayer(soundPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sound;
|
return sound;
|
||||||
|
@ -44,10 +44,10 @@ const loadSoundFromAsset = function (sound, soundAsset, runtime, sprite) {
|
||||||
* @property {string} md5 - the MD5 and extension of the sound to be loaded.
|
* @property {string} md5 - the MD5 and extension of the sound to be loaded.
|
||||||
* @property {Buffer} data - sound data will be written here once loaded.
|
* @property {Buffer} data - sound data will be written here once loaded.
|
||||||
* @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
|
* @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
|
||||||
* @param {Sprite} sprite - Scratch sprite to add sounds to.
|
* @param {SoundBank} soundBank - Scratch Audio SoundBank to add sounds to.
|
||||||
* @returns {!Promise} - a promise which will resolve to the sound when ready.
|
* @returns {!Promise} - a promise which will resolve to the sound when ready.
|
||||||
*/
|
*/
|
||||||
const loadSound = function (sound, runtime, sprite) {
|
const loadSound = function (sound, runtime, soundBank) {
|
||||||
if (!runtime.storage) {
|
if (!runtime.storage) {
|
||||||
log.error('No storage module present; cannot load sound asset: ', sound.md5);
|
log.error('No storage module present; cannot load sound asset: ', sound.md5);
|
||||||
return Promise.resolve(sound);
|
return Promise.resolve(sound);
|
||||||
|
@ -61,7 +61,7 @@ const loadSound = function (sound, runtime, sprite) {
|
||||||
runtime.storage.load(runtime.storage.AssetType.Sound, md5, ext)
|
runtime.storage.load(runtime.storage.AssetType.Sound, md5, ext)
|
||||||
).then(soundAsset => {
|
).then(soundAsset => {
|
||||||
sound.asset = soundAsset;
|
sound.asset = soundAsset;
|
||||||
return loadSoundFromAsset(sound, soundAsset, runtime, sprite);
|
return loadSoundFromAsset(sound, soundAsset, runtime, soundBank);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -399,9 +399,10 @@ const parseMonitorObject = (object, runtime, targets, extensions) => {
|
||||||
* @param {!Runtime} runtime - Runtime object to load all structures into.
|
* @param {!Runtime} runtime - Runtime object to load all structures into.
|
||||||
* @param {boolean} topLevel - Whether this is the top-level object (stage).
|
* @param {boolean} topLevel - Whether this is the top-level object (stage).
|
||||||
* @param {?object} zip - Optional zipped assets for local file import
|
* @param {?object} zip - Optional zipped assets for local file import
|
||||||
* @return {?{costumePromises:Array.<Promise>,soundPromises:Array.<Promise>,children:object}}
|
* @return {?{costumePromises:Array.<Promise>,soundPromises:Array.<Promise>,soundBank:SoundBank,children:object}}
|
||||||
* Object of arrays of promises and child objects for asset objects used in
|
* Object of arrays of promises and child objects for asset objects used in
|
||||||
* Sprites. null for unsupported objects.
|
* Sprites. As well as a SoundBank for the sound assets. null for unsupported
|
||||||
|
* objects.
|
||||||
*/
|
*/
|
||||||
const parseScratchAssets = function (object, runtime, topLevel, zip) {
|
const parseScratchAssets = function (object, runtime, topLevel, zip) {
|
||||||
if (!object.hasOwnProperty('objName')) {
|
if (!object.hasOwnProperty('objName')) {
|
||||||
|
@ -409,7 +410,12 @@ const parseScratchAssets = function (object, runtime, topLevel, zip) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const assets = {costumePromises: [], soundPromises: [], children: []};
|
const assets = {
|
||||||
|
costumePromises: [],
|
||||||
|
soundPromises: [],
|
||||||
|
soundBank: runtime.audioEngine && runtime.audioEngine.createBank(),
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
|
||||||
// Costumes from JSON.
|
// Costumes from JSON.
|
||||||
const costumePromises = assets.costumePromises;
|
const costumePromises = assets.costumePromises;
|
||||||
|
@ -457,7 +463,7 @@ const parseScratchAssets = function (object, runtime, topLevel, zip) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Sounds from JSON
|
// Sounds from JSON
|
||||||
const soundPromises = assets.soundPromises;
|
const {soundBank, soundPromises} = assets;
|
||||||
if (object.hasOwnProperty('sounds')) {
|
if (object.hasOwnProperty('sounds')) {
|
||||||
for (let s = 0; s < object.sounds.length; s++) {
|
for (let s = 0; s < object.sounds.length; s++) {
|
||||||
const soundSource = object.sounds[s];
|
const soundSource = object.sounds[s];
|
||||||
|
@ -486,7 +492,10 @@ const parseScratchAssets = function (object, runtime, topLevel, zip) {
|
||||||
// the file name of the sound should be the soundID (provided from the project.json)
|
// the file name of the sound should be the soundID (provided from the project.json)
|
||||||
// followed by the file ext
|
// followed by the file ext
|
||||||
const assetFileName = `${soundSource.soundID}.${ext}`;
|
const assetFileName = `${soundSource.soundID}.${ext}`;
|
||||||
soundPromises.push(deserializeSound(sound, runtime, zip, assetFileName).then(() => sound));
|
soundPromises.push(
|
||||||
|
deserializeSound(sound, runtime, zip, assetFileName)
|
||||||
|
.then(() => loadSound(sound, runtime, soundBank))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,11 +555,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip,
|
||||||
// Costumes from JSON.
|
// Costumes from JSON.
|
||||||
const costumePromises = assets.costumePromises;
|
const costumePromises = assets.costumePromises;
|
||||||
// Sounds from JSON
|
// Sounds from JSON
|
||||||
const soundPromises = assets.soundPromises;
|
const {soundBank, soundPromises} = assets;
|
||||||
for (let s = 0; s < soundPromises.length; s++) {
|
|
||||||
soundPromises[s] = soundPromises[s]
|
|
||||||
.then(sound => loadSound(sound, runtime, sprite));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the first clone, and load its run-state from JSON.
|
// Create the first clone, and load its run-state from JSON.
|
||||||
const target = sprite.createClone(topLevel ? StageLayering.BACKGROUND_LAYER : StageLayering.SPRITE_LAYER);
|
const target = sprite.createClone(topLevel ? StageLayering.BACKGROUND_LAYER : StageLayering.SPRITE_LAYER);
|
||||||
|
@ -738,6 +743,8 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip,
|
||||||
|
|
||||||
Promise.all(soundPromises).then(sounds => {
|
Promise.all(soundPromises).then(sounds => {
|
||||||
sprite.sounds = sounds;
|
sprite.sounds = sounds;
|
||||||
|
// Make sure if soundBank is undefined, sprite.soundBank is then null.
|
||||||
|
sprite.soundBank = soundBank || null;
|
||||||
});
|
});
|
||||||
|
|
||||||
// The stage will have child objects; recursively process them.
|
// The stage will have child objects; recursively process them.
|
||||||
|
|
|
@ -914,7 +914,7 @@ const parseScratchObject = function (object, runtime, extensions, zip) {
|
||||||
// any translation that needs to happen will happen in the process
|
// any translation that needs to happen will happen in the process
|
||||||
// of building up the costume object into an sb3 format
|
// of building up the costume object into an sb3 format
|
||||||
return deserializeSound(sound, runtime, zip)
|
return deserializeSound(sound, runtime, zip)
|
||||||
.then(() => loadSound(sound, runtime, sprite));
|
.then(() => loadSound(sound, runtime, sprite.soundBank));
|
||||||
// Only attempt to load the sound after the deserialization
|
// Only attempt to load the sound after the deserialization
|
||||||
// process has been completed.
|
// process has been completed.
|
||||||
});
|
});
|
||||||
|
|
|
@ -153,7 +153,7 @@ class Sprite {
|
||||||
newSprite.sounds = this.sounds.map(sound => {
|
newSprite.sounds = this.sounds.map(sound => {
|
||||||
const newSound = Object.assign({}, sound);
|
const newSound = Object.assign({}, sound);
|
||||||
const soundAsset = sound.asset;
|
const soundAsset = sound.asset;
|
||||||
assetPromises.push(loadSoundFromAsset(newSound, soundAsset, this.runtime, newSprite));
|
assetPromises.push(loadSoundFromAsset(newSound, soundAsset, this.runtime, newSprite.soundBank));
|
||||||
return newSound;
|
return newSound;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -678,7 +678,7 @@ class VirtualMachine extends EventEmitter {
|
||||||
duplicateSound (soundIndex) {
|
duplicateSound (soundIndex) {
|
||||||
const originalSound = this.editingTarget.getSounds()[soundIndex];
|
const originalSound = this.editingTarget.getSounds()[soundIndex];
|
||||||
const clone = Object.assign({}, originalSound);
|
const clone = Object.assign({}, originalSound);
|
||||||
return loadSound(clone, this.runtime, this.editingTarget.sprite).then(() => {
|
return loadSound(clone, this.runtime, this.editingTarget.sprite.soundBank).then(() => {
|
||||||
this.editingTarget.addSound(clone, soundIndex + 1);
|
this.editingTarget.addSound(clone, soundIndex + 1);
|
||||||
this.emitTargetsUpdate();
|
this.emitTargetsUpdate();
|
||||||
});
|
});
|
||||||
|
@ -723,7 +723,7 @@ class VirtualMachine extends EventEmitter {
|
||||||
const target = optTargetId ? this.runtime.getTargetById(optTargetId) :
|
const target = optTargetId ? this.runtime.getTargetById(optTargetId) :
|
||||||
this.editingTarget;
|
this.editingTarget;
|
||||||
if (target) {
|
if (target) {
|
||||||
return loadSound(soundObject, this.runtime, target.sprite).then(() => {
|
return loadSound(soundObject, this.runtime, target.sprite.soundBank).then(() => {
|
||||||
target.addSound(soundObject);
|
target.addSound(soundObject);
|
||||||
this.emitTargetsUpdate();
|
this.emitTargetsUpdate();
|
||||||
});
|
});
|
||||||
|
@ -1250,7 +1250,7 @@ class VirtualMachine extends EventEmitter {
|
||||||
const originalSound = this.editingTarget.getSounds()[soundIndex];
|
const originalSound = this.editingTarget.getSounds()[soundIndex];
|
||||||
const clone = Object.assign({}, originalSound);
|
const clone = Object.assign({}, originalSound);
|
||||||
const target = this.runtime.getTargetById(targetId);
|
const target = this.runtime.getTargetById(targetId);
|
||||||
return loadSound(clone, this.runtime, target.sprite).then(() => {
|
return loadSound(clone, this.runtime, target.sprite.soundBank).then(() => {
|
||||||
if (target) {
|
if (target) {
|
||||||
target.addSound(clone);
|
target.addSound(clone);
|
||||||
this.emitTargetsUpdate();
|
this.emitTargetsUpdate();
|
||||||
|
|
Loading…
Reference in a new issue