diff --git a/src/mami.js/audio/buffer.js b/src/mami.js/audio/buffer.js index 6abf101..8f5868a 100644 --- a/src/mami.js/audio/buffer.js +++ b/src/mami.js/audio/buffer.js @@ -1,6 +1,5 @@ const MamiAudioBuffer = function(ctx, buffer) { return { - getBuffer: () => buffer, createSource: () => ctx.createSource(buffer), }; }; diff --git a/src/mami.js/audio/context.js b/src/mami.js/audio/context.js index 10a6439..6d5de3a 100644 --- a/src/mami.js/audio/context.js +++ b/src/mami.js/audio/context.js @@ -5,53 +5,75 @@ const MamiAudioContext = function() { const pub = {}; - let volume = null; + let volume; let isMuted = false; const ctxArgs = { latencyHint: 'playback' }; - let ctx = null; - let mainGain = null; - const init = () => { + let ctx, mainGain; + + const onReset = []; + + const reset = () => { const audObj = window.AudioContext || window.webkitAudioContext; try { ctx = new audObj(ctxArgs); } catch(ex) { ctx = new audObj; } + mainGain = ctx.createGain(); - if(volume === null) { + if(volume === undefined) { volume = mainGain.gain.defaultValue; isMuted = false; } else mainGain.gain.value = isMuted ? 0 : volume; mainGain.connect(ctx.destination); + + for(const handler of onReset) + handler(); }; - init(); + reset(); - pub.getContext = () => ctx; - pub.resetContext = init; + pub.getAudioContext = () => ctx; + pub.getAudioContextGain = () => mainGain; + + pub.isReady = () => ctx !== undefined; + pub.reset = reset; + + pub.onReset = handler => { + if(!onReset.includes(handler)) + onReset.push(handler); + }; pub.getVolume = () => volume; pub.setVolume = vol => { volume = vol; - if(!isMuted) + if(!isMuted && mainGain !== undefined) mainGain.gain.value = volume; }; pub.isMuted = () => isMuted; pub.setMuted = mute => { - mainGain.gain.value = (isMuted = mute) ? 0 : volume; + isMuted = mute; + if(mainGain !== undefined) + mainGain.gain.value = isMuted ? 0 : volume; }; pub.createBuffer = async url => { + if(ctx === undefined) + return new MamiAudioBuffer(pub); + const result = await $x.get(url, { type: 'arraybuffer' }); const buffer = await ctx.decodeAudioData(result.body()); return new MamiAudioBuffer(pub, buffer); }; pub.createSource = buffer => { + if(ctx === undefined) + return new MamiAudioSourceDummy; + const gain = ctx.createGain(); gain.connect(mainGain); diff --git a/src/mami.js/audio/source.js b/src/mami.js/audio/source.js index 67ba16b..6c3b4f1 100644 --- a/src/mami.js/audio/source.js +++ b/src/mami.js/audio/source.js @@ -1,3 +1,19 @@ +const MamiAudioSourceDummy = function() { + return { + play: async () => {}, + stop: () => {}, + getRate: () => 0, + setRate: rate => {}, + getDetune: () => 0, + setDetune: rate => {}, + getVolume: () => 0, + setVolume: volume => {}, + isMuted: () => true, + setMuted: mute => {}, + setLoop: (loop, start, end) => {}, + }; +}; + const MamiAudioSource = function(source, gain, buffer) { const pub = {}; @@ -6,8 +22,6 @@ const MamiAudioSource = function(source, gain, buffer) { let hasDisconnected = false; - pub.getSource = () => source; - const play = () => { return new Promise(resolve => { source.addEventListener('ended', () => resolve()); diff --git a/src/mami.js/context.js b/src/mami.js/context.js index 4078c33..010d109 100644 --- a/src/mami.js/context.js +++ b/src/mami.js/context.js @@ -17,41 +17,20 @@ const MamiContext = function(targetBody) { const viewsCtx = new MamiViewsControl({ body: targetBody }); pub.getViews = () => viewsCtx; - let audioCtx = null; - pub.hasAudio = function() { return audioCtx !== null; }; - pub.getAudio = function() { return audioCtx; }; - const initAudio = function() { - if(audioCtx !== null) - return; + const audioCtx = new MamiAudioContext; + pub.getAudio = () => audioCtx; - audioCtx = new MamiAudioContext; - }; - pub.initAudio = initAudio; + const soundMgr = new MamiSoundManager(audioCtx); + const soundLib = new MamiSoundLibrary; + const soundPck = new MamiSoundPacks; + const sndPckPlay = new MamiSoundPackPlayer(soundMgr, soundLib); - let soundMgr = null; - let sndPckPlay = null; - const soundLib = new MamiSoundLibrary(); - const soundPck = new MamiSoundPacks(); - - pub.initSound = function() { - if(soundMgr !== null) - return; - - initAudio(); - soundMgr = new MamiSoundManager(audioCtx); - sndPckPlay = new MamiSoundPackPlayer(soundMgr, soundLib); - }; - - pub.getSound = function() { return soundMgr; }; - pub.hasSound = function() { return soundMgr !== null; }; - pub.getSoundLibrary = function() { return soundLib; }; - pub.getSoundPacks = function() { return soundPck; }; - pub.getSoundPackPlayer = function() { return sndPckPlay; }; + pub.getSound = () => soundMgr; + pub.getSoundLibrary = () => soundLib; + pub.getSoundPacks = () => soundPck; + pub.getSoundPackPlayer = () => sndPckPlay; pub.playLibrarySound = async (name, volume, rate) => { - if(soundMgr === null) - return; - const buffer = await soundMgr.load(soundLib.getSoundSources(name)); const source = buffer.createSource(); @@ -65,12 +44,12 @@ const MamiContext = function(targetBody) { }; const txtTriggers = new MamiTextTriggers; - pub.getTextTriggers = function() { return txtTriggers; }; + pub.getTextTriggers = () => txtTriggers; let eeprom; pub.hasEEPROM = () => eeprom !== undefined; pub.getEEPROM = () => eeprom; - pub.createEEPROM = function() { + pub.createEEPROM = () => { if(eeprom !== undefined) return; diff --git a/src/mami.js/main.js b/src/mami.js/main.js index 6377f72..8a0bc50 100644 --- a/src/mami.js/main.js +++ b/src/mami.js/main.js @@ -157,8 +157,10 @@ const Umi = { UI: {} }; } settings.watch('soundEnable', (v, n, i) => { - if(v && !mami.hasSound()) { - mami.initSound(); + if(v) { + const audio = mami.getAudio(); + if(!audio.isReady()) + audio.reset(); settings.touch('soundVolume'); settings.touch('soundPack'); @@ -168,8 +170,7 @@ const Umi = { UI: {} }; player.playEvent('server'); } - if(mami.hasAudio()) - mami.getAudio().setMuted(!v); + mami.getAudio().setMuted(!v); }); settings.watch('soundPack', (v, n, i) => { @@ -187,8 +188,7 @@ const Umi = { UI: {} }; }); settings.watch('soundVolume', v => { - if(mami.hasAudio()) - mami.getAudio().setVolume(v / 100); + mami.getAudio().setVolume(v / 100); }) @@ -248,10 +248,12 @@ const Umi = { UI: {} }; settings.watch('tmpDisableOldThemeSys', (v, n, i) => { if(!i) Umi.UI.View.AccentReload(); }); settings.watch('minecraft', (v, n, i) => { - if(i) - mami.playLibrarySound('minecraft:nether:enter'); - else - Umi.Sound.Play('join'); + if(v !== 'no') { + if(i) + mami.playLibrarySound('minecraft:nether:enter'); + else + Umi.Sound.Play('join'); + } }); settings.watch('enableNotifications', v => { diff --git a/src/mami.js/sockchat_old.js b/src/mami.js/sockchat_old.js index 9325570..d798478 100644 --- a/src/mami.js/sockchat_old.js +++ b/src/mami.js/sockchat_old.js @@ -105,9 +105,6 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) { await mami.playLibrarySound('touhou:pichuun'); }; const playBannedBgm = async preload => { - if(!mami.hasSound()) - return; - const soundMgr = mami.getSound(); const soundLib = mami.getSoundLibrary(); diff --git a/src/mami.js/sound/sndmgr.js b/src/mami.js/sound/sndmgr.js index 3871109..15973cb 100644 --- a/src/mami.js/sound/sndmgr.js +++ b/src/mami.js/sound/sndmgr.js @@ -1,6 +1,4 @@ #include utility.js -#include sound/sndlibrary.js -#include sound/sndpacks.js const MamiSoundManager = function(context) { const probablySupported = []; @@ -13,8 +11,6 @@ const MamiSoundManager = function(context) { wav: 'audio/wav', }; - const loaded = new Map; - (() => { const elem = $e('audio'); for(const name in formats) { @@ -28,9 +24,7 @@ const MamiSoundManager = function(context) { } })(); - const pub = {}; - - const extractSupportedUrl = urls => { + const extractUrl = urls => { if(typeof urls === 'object' && typeof urls.getSources === 'function') urls = urls.getSources(); @@ -48,25 +42,26 @@ const MamiSoundManager = function(context) { throw 'No supported audio format could be determined.'; }; - pub.load = async urls => { - const url = extractSupportedUrl(urls); + const loaded = new Map; + context.onReset(() => loaded.clear()); - if(loaded.has(url)) - return loaded.get(url); + return { + load: async urls => { + const url = extractUrl(urls); - const buffer = await context.createBuffer(url); - loaded.set(url, buffer); + if(loaded.has(url)) + return loaded.get(url); - return buffer; + const buffer = await context.createBuffer(url); + loaded.set(url, buffer); + + return buffer; + }, + unload: urls => { + loaded.delete(extractUrl(urls)); + }, + reset: () => { + loaded.clear(); + }, }; - - pub.unload = urls => { - loaded.delete(extractSupportedUrl(urls)); - }; - - pub.reset = () => { - loaded.clear(); - }; - - return pub; }; diff --git a/src/mami.js/sound/umisound.js b/src/mami.js/sound/umisound.js index e19b82a..254f79c 100644 --- a/src/mami.js/sound/umisound.js +++ b/src/mami.js/sound/umisound.js @@ -5,7 +5,7 @@ Umi.Sound = (() => { return { Play: sound => { - if(!sound || sound === 'none' || !mami.hasSound()) + if(!sound || sound === 'none') return; const settings = mami.getSettings(); diff --git a/src/mami.js/ui/settings.jsx b/src/mami.js/ui/settings.jsx index f39e7a9..a1edb96 100644 --- a/src/mami.js/ui/settings.jsx +++ b/src/mami.js/ui/settings.jsx @@ -396,6 +396,13 @@ Umi.UI.Settings = (function() { button.disabled = false; }, }, + { + title: 'Reset audio context', + type: 'button', + invoke: async () => { + mami.getAudio().reset(); + }, + }, ], } ];