Last active
October 1, 2024 19:51
-
-
Save jrod-disco/26620a54a37d886e489251f23f68d2dd to your computer and use it in GitHub Desktop.
An attempt at handling sound sprites in Expo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Audio } from 'expo-av'; | |
import { AssetLibrary } from '../AssetLibrary'; | |
/** | |
* Factory function to create sound sprites. | |
* | |
* Takes configuration object on init. | |
* | |
* Once configured a key can be played like so | |
* spriteInstance.play('validKeyDefinedInConfig')' | |
* | |
* asset - the sound asset | |
* Eg. AssetLibrary.sounds['nextLevel'] | |
* this sound should contain multiple sounds that will be played | |
* based on keys defined below | |
* | |
* sounds - an object containing one or more sound keys and their start and end time in ms | |
* Eg. nextLevel:{from:1000,to:1500} | |
* Note that unlike some other sound sprites we are not sending a duration | |
* Note that by default the sprite has a 100ms granularity and that will be off by 50% | |
* | |
* @param {{asset:sound, sounds{key:{from:number,to:number}}[]}} | |
*/ | |
export const NewSoundSprite = async (config) => { | |
let state = { | |
spritesObject: {}, | |
asset: null, | |
sndObj: null, | |
sounds: { | |
foo: { | |
start: 0, | |
duration: 0, | |
}, | |
}, | |
}; | |
const asset = config.asset; | |
// If the asset doesn't exist, we out... | |
if (!asset) { | |
console.log( | |
'Sound Sprite: Asset not defined in `AssetLibrary.sounds`', | |
config.asset | |
); | |
return; | |
} | |
// Hold some state... | |
state = { ...state, ...config, asset }; | |
// Create a single sound object for each sound we want to play | |
// Set its position where we want it | |
// Store it in state for later use | |
const { sounds } = config; | |
for (const key in sounds) { | |
if (sounds.hasOwnProperty(key)) { | |
const sound = sounds[key]; | |
const r = await Audio.Sound.createAsync(state.asset, { | |
shouldPlay: false, | |
positionMillis: sound.from, | |
volume: 1, | |
progressUpdateIntervalMillis: 50, | |
}); | |
const _onPlaybackStatus = (status) => { | |
if (status.positionMillis > sound.to || status.didJustFinish) { | |
r.sound.setPositionAsync(sound.from); | |
r.sound.stopAsync(); //unloadAsync().catch(() => {}); | |
//console.log('done rewind', status); | |
} else { | |
return; | |
} | |
}; | |
r.sound.setOnPlaybackStatusUpdate(_onPlaybackStatus); | |
state.spritesObject[key] = r; | |
console.log(`${key} loaded`); | |
} | |
} | |
try { | |
const { sound: soundObject, status } = await Audio.Sound.createAsync( | |
state.asset, | |
{ | |
shouldPlay: false, | |
progressUpdateIntervalMillis: 100, | |
} | |
); | |
state.sndObj = soundObject; | |
} catch (error) { | |
console.log('ERROR on CREATE', key); | |
console.log(error); | |
} | |
const play = async (key) => { | |
if (!SETTINGS.getUseSound()) return; // check to see if we should be playing at all | |
console.log('sprite play -->', key); | |
try { | |
await state.spritesObject[key].sound.setPositionAsync( | |
state.sounds[key].from | |
); | |
} catch (error) { | |
console.log('ERROR on SETPOSITION', key); | |
console.log(error); | |
} | |
try { | |
await state.spritesObject[key].sound.playAsync(); | |
} catch (error) { | |
console.log('ERROR on PLAY', key); | |
console.log(error); | |
} | |
}; | |
// the sound sprite itself has a single play method exposed | |
// play takes the key (must match key used in config) play('newGameSound') | |
return { play }; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { NewSoundSprite } from '.'; | |
import { AssetLibrary } from '../AssetLibrary'; | |
// Playing a sound sprite we send the name of the sprite and the key for the specific sound we want | |
// playSoundSprite("yemSprite", "newGame); | |
export const playSoundSprite = (spriteName, soundName) => { | |
soundSpritesAsync.then((ssa) => ssa.getAll()[spriteName].play(soundName)); | |
}; | |
export const soundSpritesAsync = (async () => { | |
const yemSprite = await NewSoundSprite({ | |
asset: AssetLibrary.sounds['yemSprite'], | |
sounds: { | |
s10: { from: 0, to: 400 }, | |
s11: { from: 0, to: 400 }, | |
s20: { from: 775, to: 1140 }, | |
s21: { from: 775, to: 1140 }, | |
s30: { from: 1512, to: 1958 }, | |
s31: { from: 1512, to: 1958 }, | |
s40: { from: 2265, to: 2609 }, | |
s41: { from: 2265, to: 2609 }, | |
s50: { from: 3024, to: 3449 }, | |
s51: { from: 3024, to: 3449 }, | |
s60: { from: 3777, to: 4085 }, | |
s61: { from: 3777, to: 4085 }, | |
s70: { from: 4515, to: 4900 }, | |
s71: { from: 4515, to: 4900 }, | |
s80: { from: 5200, to: 5250 }, | |
s81: { from: 5200, to: 5250 }, | |
s90: { from: 6000, to: 6330 }, | |
s91: { from: 6000, to: 6330 }, | |
gameOver: { from: 14850, to: 16900 }, | |
nextLevel: { from: 17950, to: 19500 }, | |
}, | |
}); | |
const funkSprite = await NewSoundSprite({ | |
asset: AssetLibrary.sounds['funkSprite'], | |
sounds: { | |
s10: { from: 0, to: 555 }, | |
s11: { from: 0, to: 555 }, | |
s20: { from: 740, to: 1240 }, | |
s21: { from: 740, to: 1240 }, | |
s30: { from: 1490, to: 2025 }, | |
s31: { from: 1490, to: 2025 }, | |
s40: { from: 2040, to: 2800 }, | |
s41: { from: 2040, to: 2800 }, | |
s50: { from: 2990, to: 3540 }, | |
s51: { from: 2990, to: 3540 }, | |
s60: { from: 3790, to: 4330 }, | |
s61: { from: 3790, to: 4330 }, | |
s70: { from: 4490, to: 4990 }, | |
s71: { from: 4490, to: 4990 }, | |
s80: { from: 5240, to: 5750 }, | |
s81: { from: 5240, to: 5750 }, | |
s90: { from: 5990, to: 6490 }, | |
s91: { from: 5990, to: 6490 }, | |
gameOver: { from: 7490, to: 8900 }, | |
nextLevel: { from: 9730, to: 11250 }, | |
}, | |
}); | |
const getAll = () => { | |
return { | |
yemSprite, | |
funkSprite, | |
}; | |
}; | |
return { | |
getAll, | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment