From af09fc77163af7ca7d39d0c14369c1fb5e21f6fc Mon Sep 17 00:00:00 2001 From: flashwave Date: Sat, 10 Feb 2024 03:50:23 +0000 Subject: [PATCH] Moved playLibarySound out of the global context. --- src/mami.js/audio/context.js | 89 ++++++++++++------------- src/mami.js/audio/source.js | 109 +++++++++++++++--------------- src/mami.js/context.js | 16 +---- src/mami.js/main.js | 16 ++--- src/mami.js/sockchat_old.js | 12 ++-- src/mami.js/sound/osukeys.js | 2 +- src/mami.js/sound/seinfeld.js | 2 +- src/mami.js/sound/sndlibrary.js | 63 ++++++++++++------ src/mami.js/sound/sndpacks.js | 114 ++++++++++++++------------------ src/mami.js/sound/umisound.js | 15 ++--- src/mami.js/ui/domaintrans.jsx | 5 +- src/mami.js/ui/settings.jsx | 2 +- src/mami.js/youare.jsx | 2 +- 13 files changed, 216 insertions(+), 231 deletions(-) diff --git a/src/mami.js/audio/context.js b/src/mami.js/audio/context.js index e44211c..2c88fdf 100644 --- a/src/mami.js/audio/context.js +++ b/src/mami.js/audio/context.js @@ -2,8 +2,6 @@ #include audio/source.js const MamiAudioContext = function() { - const pub = {}; - let volume; let isMuted = false; @@ -36,51 +34,50 @@ const MamiAudioContext = function() { reset(); - pub.getAudioContext = () => ctx; - pub.getAudioContextGain = () => mainGain; + return { + getAudioContext: () => ctx, + getAudioContextGain: () => mainGain, - pub.isReady = () => ctx !== undefined; - pub.reset = reset; + isReady: () => ctx !== undefined, + reset: reset, + onReset: handler => { + if(!onReset.includes(handler)) + onReset.push(handler); + }, - pub.onReset = handler => { - if(!onReset.includes(handler)) - onReset.push(handler); + getVolume: () => volume, + setVolume: vol => { + volume = vol; + if(!isMuted && mainGain !== undefined) + mainGain.gain.value = volume; + }, + isMuted: () => isMuted, + setMuted: mute => { + isMuted = mute; + if(mainGain !== undefined) + mainGain.gain.value = isMuted ? 0 : volume; + }, + + createBuffer: async url => { + if(ctx === undefined) + return undefined; + + const result = await $x.get(url, { type: 'arraybuffer' }); + return await ctx.decodeAudioData(result.body()); + }, + + createSource: buffer => { + if(ctx === undefined || buffer === undefined) + return new MamiAudioSourceDummy; + + const gain = ctx.createGain(); + gain.connect(mainGain); + + const source = ctx.createBufferSource(); + source.buffer = buffer; + source.connect(gain); + + return new MamiAudioSource(source, gain); + }, }; - - pub.getVolume = () => volume; - pub.setVolume = vol => { - volume = vol; - if(!isMuted && mainGain !== undefined) - mainGain.gain.value = volume; - }; - pub.isMuted = () => isMuted; - pub.setMuted = mute => { - isMuted = mute; - if(mainGain !== undefined) - mainGain.gain.value = isMuted ? 0 : volume; - }; - - pub.createBuffer = async url => { - if(ctx === undefined) - return undefined; - - const result = await $x.get(url, { type: 'arraybuffer' }); - return await ctx.decodeAudioData(result.body()); - }; - - pub.createSource = buffer => { - if(ctx === undefined || buffer === undefined) - return new MamiAudioSourceDummy; - - const gain = ctx.createGain(); - gain.connect(mainGain); - - const source = ctx.createBufferSource(); - source.buffer = buffer; - source.connect(gain); - - return new MamiAudioSource(source, gain); - }; - - return pub; }; diff --git a/src/mami.js/audio/source.js b/src/mami.js/audio/source.js index 6c3b4f1..6c759c8 100644 --- a/src/mami.js/audio/source.js +++ b/src/mami.js/audio/source.js @@ -15,21 +15,11 @@ const MamiAudioSourceDummy = function() { }; const MamiAudioSource = function(source, gain, buffer) { - const pub = {}; - let volume = 1, isMuted = false; let hasDisconnected = false; - const play = () => { - return new Promise(resolve => { - source.addEventListener('ended', () => resolve()); - source.start(); - }); - }; - pub.play = play; - const disconnect = () => { if(hasDisconnected) return; @@ -39,53 +29,58 @@ const MamiAudioSource = function(source, gain, buffer) { source.disconnect(); }; - const stop = () => { - source.stop(); - disconnect(); - }; - pub.stop = stop; - - pub.getRate = () => source.playbackRate.value; - pub.setRate = rate => { - source.playbackRate.value = Math.min( - source.playbackRate.maxValue, - Math.max( - source.playbackRate.minValue, - rate - ) - ); - }; - pub.getDetune = () => source.detune.value; - pub.setDetune = rate => { - source.detune.value = Math.min( - source.detune.maxValue, - Math.max( - source.detune.minValue, - rate - ) - ); - }; - - pub.getVolume = () => volume; - pub.setVolume = vol => { - volume = vol; - if(!isMuted) - gain.gain.value = volume; - }; - pub.isMuted = () => isMuted; - pub.setMuted = mute => { - gain.gain.value = (isMuted = mute) ? 0 : volume; - }; - - pub.setLoop = (loop, start, end) => { - if(typeof start === 'number') - source.loopStart = start; - if(typeof end === 'number') - source.loopEnd = end; - source.loop = !!loop; - }; - source.addEventListener('ended', () => disconnect()); - return pub; + return { + play: () => { + return new Promise(resolve => { + source.addEventListener('ended', () => resolve()); + source.start(); + }); + }, + stop: () => { + source.stop(); + disconnect(); + }, + + getRate: () => source.playbackRate.value, + setRate: rate => { + source.playbackRate.value = Math.min( + source.playbackRate.maxValue, + Math.max( + source.playbackRate.minValue, + rate + ) + ); + }, + getDetune: () => source.detune.value, + setDetune: rate => { + source.detune.value = Math.min( + source.detune.maxValue, + Math.max( + source.detune.minValue, + rate + ) + ); + }, + + getVolume: () => volume, + setVolume: vol => { + volume = vol; + if(!isMuted) + gain.gain.value = volume; + }, + isMuted: () => isMuted, + setMuted: mute => { + gain.gain.value = (isMuted = mute) ? 0 : volume; + }, + + setLoop: (loop, start, end) => { + if(typeof start === 'number') + source.loopStart = start; + if(typeof end === 'number') + source.loopEnd = end; + source.loop = !!loop; + }, + }; }; diff --git a/src/mami.js/context.js b/src/mami.js/context.js index 1c2af6f..9135da4 100644 --- a/src/mami.js/context.js +++ b/src/mami.js/context.js @@ -21,27 +21,15 @@ const MamiContext = function(targetBody) { pub.getAudio = () => audioCtx; const soundMgr = new MamiSoundManager(audioCtx); - const soundLib = new MamiSoundLibrary; + const soundLib = new MamiSoundLibrary(soundMgr); const soundPck = new MamiSoundPacks; - const sndPckPlay = new MamiSoundPackPlayer(soundMgr, soundLib); + const sndPckPlay = new MamiSoundPackPlayer(soundLib); pub.getSound = () => soundMgr; pub.getSoundLibrary = () => soundLib; pub.getSoundPacks = () => soundPck; pub.getSoundPackPlayer = () => sndPckPlay; - pub.playLibrarySound = async (name, volume, rate) => { - const source = await soundMgr.loadSource(soundLib.getSoundSources(name)); - - if(typeof volume === 'number') - source.setVolume(volume); - - if(typeof rate === 'number') - source.setRate(rate); - - await source.play(); - }; - const txtTriggers = new MamiTextTriggers; pub.getTextTriggers = () => txtTriggers; diff --git a/src/mami.js/main.js b/src/mami.js/main.js index 8a0bc50..d5dae22 100644 --- a/src/mami.js/main.js +++ b/src/mami.js/main.js @@ -144,9 +144,9 @@ const Umi = { UI: {} }; try { const sounds = await futami.getJson('sounds2'); if(Array.isArray(sounds.library)) - sndLib.loadSounds(sounds.library, true); + sndLib.register(sounds.library, true); if(Array.isArray(sounds.packs)) - sndPacks.loadPacks(sounds.packs, true); + sndPacks.register(sounds.packs, true); } catch(ex) { console.error(ex); } @@ -175,16 +175,14 @@ const Umi = { UI: {} }; settings.watch('soundPack', (v, n, i) => { const packs = mami.getSoundPacks(); - if(!packs.hasPack(v)) { + if(!packs.has(v)) { settings.delete(n); return; } const player = mami.getSoundPackPlayer(); - if(player !== null) { - player.loadPack(packs.getPack(v)); - if(!i) player.playEvent('server'); - } + player.loadPack(packs.get(v)); + if(!i) player.playEvent('server'); }); settings.watch('soundVolume', v => { @@ -250,7 +248,7 @@ const Umi = { UI: {} }; settings.watch('minecraft', (v, n, i) => { if(v !== 'no') { if(i) - mami.playLibrarySound('minecraft:nether:enter'); + sndLib.play('minecraft:nether:enter'); else Umi.Sound.Play('join'); } @@ -404,7 +402,7 @@ const Umi = { UI: {} }; $r(explode); }, 1700); - ctx.playLibrarySound('misc:explode'); + sndLib.play('misc:explode'); }, }, }); diff --git a/src/mami.js/sockchat_old.js b/src/mami.js/sockchat_old.js index 70a7370..a375178 100644 --- a/src/mami.js/sockchat_old.js +++ b/src/mami.js/sockchat_old.js @@ -102,18 +102,18 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) { }; const playBannedSfx = async () => { - await mami.playLibrarySound('touhou:pichuun'); + await mami.getSoundLibrary().play('touhou:pichuun'); }; const playBannedBgm = async preload => { - const soundMgr = mami.getSound(); - const sources = mami.getSoundLibrary().getSoundSources('touhou:th10score'); + const name = 'touhou:th10score'; + const soundLib = mami.getSoundLibrary(); if(preload) { - await soundMgr.loadBuffer(sources); + await soundLib.loadBuffer(name); return; } - const source = await soundMgr.loadSource(sources); + const source = await soundLib.loadSource(name); source.setLoop(true, 10.512, 38.074); await source.play(); }; @@ -567,7 +567,7 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) { const trigger = mami.getTextTriggers().getTrigger(text); if(trigger.isSoundType()) { sound = ''; - mami.playLibrarySound( + mami.getSoundLibrary().play( trigger.getRandomSoundName(), trigger.getVolume(), trigger.getRate() diff --git a/src/mami.js/sound/osukeys.js b/src/mami.js/sound/osukeys.js index d9bfd55..cbb3a3a 100644 --- a/src/mami.js/sound/osukeys.js +++ b/src/mami.js/sound/osukeys.js @@ -20,7 +20,7 @@ const OsuKeys = (() => { else soundName = `press${rng.next(1, 5)}`; - mami.playLibrarySound( + mami.getSoundLibrary().play( `osu:key:${soundName}`, undefined, sndRng ? (1.8 - (rng.sample() * 1.5)) : undefined diff --git a/src/mami.js/sound/seinfeld.js b/src/mami.js/sound/seinfeld.js index ae11ff0..5be54b9 100644 --- a/src/mami.js/sound/seinfeld.js +++ b/src/mami.js/sound/seinfeld.js @@ -1,6 +1,6 @@ #include rng.js -const Seinfeld = (function() { +const Seinfeld = (() => { const sounds = 22; const rng = new MamiRNG; diff --git a/src/mami.js/sound/sndlibrary.js b/src/mami.js/sound/sndlibrary.js index be77382..4398fc9 100644 --- a/src/mami.js/sound/sndlibrary.js +++ b/src/mami.js/sound/sndlibrary.js @@ -12,27 +12,32 @@ const MamiSoundInfo = function(name, isReadOnly, title, sources) { }; }; -const MamiSoundLibrary = function() { +const MamiSoundLibrary = function(soundMgr) { + if(typeof soundMgr !== 'object' && typeof soundMgr.loadSource !== 'function') + throw 'soundMgr must be an instance of MamiSoundManager'; + const sounds = new Map; - const addSound = soundInfo => { - if(sounds.has(soundInfo.getName())) - throw 'a sound with that name has already been registered'; - sounds.set(soundInfo.getName(), soundInfo); - }; + const soundFormats = ['opus', 'caf', 'ogg', 'mp3', 'wav']; + const registerSound = (soundInfo, readOnly) => { + if(Array.isArray(soundInfo)) { + for(const info of soundInfo) + registerSound(info, readOnly); + return; + } - const loadSoundFormats = ['opus', 'caf', 'ogg', 'mp3', 'wav']; - const loadSound = (soundInfo, readOnly) => { if(typeof soundInfo !== 'object') throw 'soundInfo must be an object'; if(typeof soundInfo.name !== 'string') throw 'soundInfo must contain a name field'; if(typeof soundInfo.sources !== 'object') throw 'soundInfo must contain a sources field'; + if(sounds.has(soundInfo.name)) + throw 'a sound with that name has already been registered'; let sources = {}, sCount = 0; - for(const fmt of loadSoundFormats) { + for(const fmt of soundFormats) { if(typeof soundInfo.sources[fmt] !== 'string') continue; sources[fmt] = soundInfo.sources[fmt]; @@ -42,7 +47,10 @@ const MamiSoundLibrary = function() { if(sCount < 1) throw 'soundInfo does not contain any valid sources'; - addSound(new MamiSoundInfo(soundInfo.name, readOnly, soundInfo.title, sources)); + soundInfo = new MamiSoundInfo(soundInfo.name, readOnly, soundInfo.title, sources); + sounds.set(soundInfo.getName(), soundInfo); + + return soundInfo; }; const getSound = name => { @@ -51,26 +59,37 @@ const MamiSoundLibrary = function() { return sounds.get(name); }; + const getSoundSources = name => getSound(name).getSources(); + const loadSoundSource = async name => await soundMgr.loadSource(getSoundSources(name)); + return { - addSound: addSound, - loadSound: loadSound, - loadSounds: (soundInfos, readOnly) => { - for(const soundInfo of soundInfos) - loadSound(soundInfo, readOnly); - }, - removeSound: name => { + register: registerSound, + unregister: name => { sounds.delete(name); }, - clearSounds: () => { + clear: () => { sounds.clear(); }, - forEachSound: body => { + forEach: body => { if(typeof body !== 'function') return; sounds.forEach(body); }, - hasSound: name => sounds.has(name), - getSound: getSound, - getSoundSources: name => getSound(name).getSources(), + has: name => sounds.has(name), + get: getSound, + getSources: getSoundSources, + loadBuffer: async name => await soundMgr.loadBuffer(getSoundSources(name)), + loadSource: loadSoundSource, + play: async (name, volume, rate) => { + const source = await loadSoundSource(name); + + if(typeof volume === 'number') + source.setVolume(volume); + + if(typeof rate === 'number') + source.setRate(rate); + + await source.play(); + }, }; }; diff --git a/src/mami.js/sound/sndpacks.js b/src/mami.js/sound/sndpacks.js index d12c36f..44c3026 100644 --- a/src/mami.js/sound/sndpacks.js +++ b/src/mami.js/sound/sndpacks.js @@ -40,70 +40,65 @@ const MamiSoundPack = function(name, isReadOnly, title, events) { }; }; -const MamiSoundPackPlayer = function(soundMgr, sndLibrary) { - const pub = {}; - let pack = null; +const MamiSoundPackPlayer = function(sndLibrary) { + let pack; - pub.loadPack = packInfo => { - if(typeof pack !== 'object' && typeof pack.getEventSound !== 'function') - throw 'pack is not a valid soundpack'; - pack = packInfo; - }; + return { + loadPack: packInfo => { + if(typeof packInfo !== 'object' || typeof packInfo.getEventSound !== 'function') + throw 'pack is not a valid soundpack'; + pack = packInfo; + }, + unloadPack: () => { + pack = undefined; + buffers.clear(); + }, + hasPack: () => pack !== undefined, - pub.unloadPack = () => { - pack = null; - buffers.clear(); - }; - - pub.hasPack = () => pack !== null; - - pub.hasEvent = eventName => pack !== null && pack.hasEventSound(eventName); - - pub.playEvent = async eventName => { - if(pack === null) - return; - - if(Array.isArray(eventName)) { - const names = eventName; - eventName = null; - - for(const name of names) { - if(pack.hasEventSound(name)) { - eventName = name; - break; - } - } - - if(eventName === null) + hasEvent: name => pack !== undefined && pack.hasEventSound(event), + playEvent: async event => { + if(pack === undefined) return; - } else if(!pack.hasEventSound(eventName)) - return; - const info = sndLibrary.getSound(pack.getEventSound(eventName)); - const source = await soundMgr.loadSource(info.getSources()); + if(Array.isArray(event)) { + const names = event; + event = undefined; - await source.play(); + for(const name of names) { + if(pack.hasEventSound(name)) { + event = name; + break; + } + } + + if(event === undefined) + return; + } else if(!pack.hasEventSound(event)) + return; + + await sndLibrary.play(pack.getEventSound(event)); + }, }; - - return pub; }; const MamiSoundPacks = function() { const packs = new Map; - const addPack = packInfo => { - if(packs.has(packInfo.getName())) - throw 'a pack with that name has already been registered'; - packs.set(packInfo.getName(), packInfo); - }; + const registerPack = (packInfo, readOnly) => { + if(Array.isArray(packInfo)) { + for(const info of packInfo) + registerPack(info, readOnly); + return; + } - const loadPack = (packInfo, readOnly) => { if(typeof packInfo !== 'object') throw 'packInfo must be an object'; if(typeof packInfo.name !== 'string') throw 'packInfo must contain a name field'; if(typeof packInfo.events !== 'object') throw 'packInfo must contain a events field'; + if(packs.has(packInfo.name)) + throw 'a pack with that name has already been registered'; const events = new Map; for(const eventName in packInfo.events) { @@ -115,34 +110,27 @@ const MamiSoundPacks = function() { if(events.size < 1) throw 'packInfo does not contain any valid events'; - addPack(new MamiSoundPack( - packInfo.name, - readOnly, - packInfo.title, - events - )); + packInfo = new MamiSoundPack(packInfo.name, readOnly, packInfo.title, events); + packs.set(packInfo.getName(), packInfo); + + return packInfo; }; return { - addPack: addPack, - loadPack: loadPack, - loadPacks: (packInfos, readOnly) => { - for(const packInfo of packInfos) - loadPack(packInfo, readOnly); - }, - removePack: name => { + register: registerPack, + unregister: name => { packs.delete(name); }, - clearPacks: () => { + clear: () => { packs.clear(); }, - forEachPack: body => { + forEach: body => { if(typeof body !== 'function') return; packs.forEach(body); }, - hasPack: name => packs.has(name), - getPack: name => { + has: name => packs.has(name), + get: name => { if(!packs.has(name)) throw 'No pack with this name has been registered.'; return packs.get(name); diff --git a/src/mami.js/sound/umisound.js b/src/mami.js/sound/umisound.js index 254f79c..e02c5ba 100644 --- a/src/mami.js/sound/umisound.js +++ b/src/mami.js/sound/umisound.js @@ -1,5 +1,3 @@ -#include audio/context.js -#include sound/sndpacks.js #include sound/seinfeld.js Umi.Sound = (() => { @@ -9,6 +7,7 @@ Umi.Sound = (() => { return; const settings = mami.getSettings(); + const sndLib = mami.getSoundLibrary(); const sndPackPlay = mami.getSoundPackPlayer(); switch(sound) { @@ -17,17 +16,17 @@ Umi.Sound = (() => { return; if(settings.get('seinfeld')) { - mami.playLibrarySound(Seinfeld.getRandom()); + sndLib.play(Seinfeld.getRandom()); break; } switch(settings.get('minecraft')) { case 'yes': - mami.playLibrarySound('minecraft:door:open'); + sndLib.play('minecraft:door:open'); break; case 'old': - mami.playLibrarySound('minecraft:door:open-old'); + sndLib.play('minecraft:door:open-old'); break; default: @@ -42,11 +41,11 @@ Umi.Sound = (() => { switch(settings.get('minecraft')) { case 'yes': - mami.playLibrarySound('minecraft:door:close'); + sndLib.play('minecraft:door:close'); break; case 'old': - mami.playLibrarySound('minecraft:door:close-old'); + sndLib.play('minecraft:door:close-old'); break; default: @@ -81,7 +80,7 @@ Umi.Sound = (() => { return; if(settings.get('windowsLiveMessenger')) { - mami.playLibrarySound('msn:incoming'); + sndLib.play('msn:incoming'); } else { sndPackPlay.playEvent('incoming'); } diff --git a/src/mami.js/ui/domaintrans.jsx b/src/mami.js/ui/domaintrans.jsx index 7290a5f..497b033 100644 --- a/src/mami.js/ui/domaintrans.jsx +++ b/src/mami.js/ui/domaintrans.jsx @@ -55,11 +55,12 @@ const MamiDomainTransition = function(onImport, onDismiss) { ; + const soundLib = mami.getSoundLibrary(); const soundRNG = new MamiRNG(); const soundNames = []; - mami.getSoundLibrary().forEachSound((info, name) => soundNames.push(name)); + soundLib.forEach((info, name) => soundNames.push(name)); - const playRandomSound = () => mami.playLibrarySound(soundNames[soundRNG.next(soundNames.length)]); + const playRandomSound = () => soundLib.play(soundNames[soundRNG.next(soundNames.length)]); for(let i = 0; i < 10; ++i) eggsTarget.appendChild( playRandomSound()} />); diff --git a/src/mami.js/ui/settings.jsx b/src/mami.js/ui/settings.jsx index a1edb96..c63f2c2 100644 --- a/src/mami.js/ui/settings.jsx +++ b/src/mami.js/ui/settings.jsx @@ -139,7 +139,7 @@ Umi.UI.Settings = (function() { type: 'select', options: () => { const packs = {}; - mami.getSoundPacks().forEachPack(function(pack) { + mami.getSoundPacks().forEach(function(pack) { packs[pack.getName()] = pack.getTitle(); }); return packs; diff --git a/src/mami.js/youare.jsx b/src/mami.js/youare.jsx index eb77948..a09fa03 100644 --- a/src/mami.js/youare.jsx +++ b/src/mami.js/youare.jsx @@ -25,7 +25,7 @@ const MamiYouAreAnIdiot = function() { return; try { - const sources = mami.getSoundLibrary().getSoundSources('misc:youare'); + const sources = mami.getSoundLibrary().getSources('misc:youare'); soundSrc = soundMgr.loadSource(sources); soundSrc.setMuted(true);