soiz1's picture
Upload 811 files
30c32c8 verified
raw
history blame
4.69 kB
const StringUtil = require('../util/string-util');
const log = require('../util/log');
/**
* Initialize a sound from an asset asynchronously.
* @param {!object} sound - the Scratch sound object.
* @property {string} md5 - the MD5 and extension of the sound to be loaded.
* @property {Buffer} data - sound data will be written here once loaded.
* @param {!Asset} soundAsset - the asset loaded from storage.
* @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
* @param {SoundBank} soundBank - Scratch Audio SoundBank to add sounds to.
* @returns {!Promise} - a promise which will resolve to the sound when ready.
*/
const loadSoundFromAsset = function (sound, soundAsset, runtime, soundBank) {
sound.assetId = soundAsset.assetId;
if (!runtime.audioEngine) {
log.warn('No audio engine present; cannot load sound asset: ', sound.md5);
return Promise.resolve(sound);
}
return runtime.audioEngine.decodeSoundPlayer(Object.assign(
{},
sound,
{data: soundAsset.data}
)).then(soundPlayer => {
sound.soundId = soundPlayer.id;
// Set the sound sample rate and sample count based on the
// the audio buffer from the audio engine since the sound
// gets resampled by the audio engine
const soundBuffer = soundPlayer.buffer;
sound.rate = soundBuffer.sampleRate;
sound.sampleCount = soundBuffer.length;
if (soundBank !== null) {
soundBank.addSoundPlayer(soundPlayer);
}
if (runtime.isPackaged) {
sound.asset = null;
}
return sound;
});
};
// Handle sound loading errors by replacing the runtime sound with the
// default sound from storage, but keeping track of the original sound metadata
// in a `broken` field
const handleSoundLoadError = function (sound, runtime, soundBank) {
// Keep track of the old asset information until we're done loading the default sound
const oldAsset = sound.asset; // could be null
const oldAssetId = sound.assetId;
const oldSample = sound.sampleCount;
const oldRate = sound.rate;
const oldFormat = sound.format;
const oldDataFormat = sound.dataFormat;
// Use default asset if original fails to load
sound.assetId = runtime.storage.defaultAssetId.Sound;
sound.asset = runtime.storage.get(sound.assetId);
sound.md5 = `${sound.assetId}.${sound.asset.dataFormat}`;
return loadSoundFromAsset(sound, sound.asset, runtime, soundBank).then(loadedSound => {
loadedSound.broken = {};
loadedSound.broken.assetId = oldAssetId;
loadedSound.broken.md5 = `${oldAssetId}.${oldDataFormat}`;
// Should be null if we got here because the sound was missing
loadedSound.broken.asset = oldAsset;
loadedSound.broken.sampleCount = oldSample;
loadedSound.broken.rate = oldRate;
loadedSound.broken.format = oldFormat;
loadedSound.broken.dataFormat = oldDataFormat;
return loadedSound;
});
};
/**
* Load a sound's asset into memory asynchronously.
* @param {!object} sound - the Scratch sound object.
* @property {string} md5 - the MD5 and extension of the sound to be loaded.
* @property {Buffer} data - sound data will be written here once loaded.
* @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
* @param {SoundBank} soundBank - Scratch Audio SoundBank to add sounds to.
* @returns {!Promise} - a promise which will resolve to the sound when ready.
*/
const loadSound = function (sound, runtime, soundBank) {
if (!runtime.storage) {
log.warn('No storage module present; cannot load sound asset: ', sound.md5);
return Promise.resolve(sound);
}
const idParts = StringUtil.splitFirst(sound.md5, '.');
const md5 = idParts[0];
const ext = idParts[1].toLowerCase();
sound.dataFormat = ext;
return (
(sound.asset && Promise.resolve(sound.asset)) ||
runtime.storage.load(runtime.storage.AssetType.Sound, md5, ext)
)
.then(soundAsset => {
sound.asset = soundAsset;
if (!soundAsset) {
log.warn('Failed to find sound data: ', sound.md5);
return handleSoundLoadError(sound, runtime, soundBank);
}
return loadSoundFromAsset(sound, soundAsset, runtime, soundBank);
})
.catch(e => {
log.warn(`Failed to load sound: ${sound.md5} with error: ${e}`);
return handleSoundLoadError(sound, runtime, soundBank);
});
};
module.exports = {
loadSound,
loadSoundFromAsset
};