Always have audio context and sound manager available.
This commit is contained in:
parent
3bc595c3ee
commit
fc58537974
9 changed files with 99 additions and 84 deletions
|
@ -1,6 +1,5 @@
|
|||
const MamiAudioBuffer = function(ctx, buffer) {
|
||||
return {
|
||||
getBuffer: () => buffer,
|
||||
createSource: () => ctx.createSource(buffer),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
Umi.Sound = (() => {
|
||||
return {
|
||||
Play: sound => {
|
||||
if(!sound || sound === 'none' || !mami.hasSound())
|
||||
if(!sound || sound === 'none')
|
||||
return;
|
||||
|
||||
const settings = mami.getSettings();
|
||||
|
|
|
@ -396,6 +396,13 @@ Umi.UI.Settings = (function() {
|
|||
button.disabled = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Reset audio context',
|
||||
type: 'button',
|
||||
invoke: async () => {
|
||||
mami.getAudio().reset();
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
];
|
||||
|
|
Loading…
Reference in a new issue