diff --git a/src/mami.js/audio/context.js b/src/mami.js/audio/context.js index 2c88fdf..41a1fd7 100644 --- a/src/mami.js/audio/context.js +++ b/src/mami.js/audio/context.js @@ -66,10 +66,27 @@ const MamiAudioContext = function() { return await ctx.decodeAudioData(result.body()); }, - createSource: buffer => { + createSource: (buffer, reverse) => { if(ctx === undefined || buffer === undefined) return new MamiAudioSourceDummy; + if(reverse) { + const reverse = new AudioBuffer({ + length: buffer.length, + numberOfChannels: buffer.numberOfChannels, + sampleRate: buffer.sampleRate, + }); + + const data = new Float32Array(buffer.length); + for(let i = 0; i < reverse.numberOfChannels; ++i) { + buffer.copyFromChannel(data, i, 0); + data.reverse(); + reverse.copyToChannel(data, i, 0); + } + + buffer = reverse; + } + const gain = ctx.createGain(); gain.connect(mainGain); diff --git a/src/mami.js/ui/baka.jsx b/src/mami.js/ui/baka.jsx index f11429e..5d65a04 100644 --- a/src/mami.js/ui/baka.jsx +++ b/src/mami.js/ui/baka.jsx @@ -27,16 +27,16 @@ const MamiForceDisconnectNotice = function(banInfo) { marqueeElem.append(
{marqueeString}
); const rng = new MamiRNG; - let sfxBuf, sfxSrc, bgmSrc; + const rotate = rng.next(-20, 20); + let sfxBuf, bgmSrc; const pub = { getElement: () => html, onViewPush: async () => { try { sfxBuf = await mami.sound.library.loadBuffer('touhou:pichuun'); - sfxSrc = mami.sound.audio.createSource(sfxBuf); } catch(ex) { - sfxBuf = sfxSrc = undefined; + sfxBuf = undefined; } try { @@ -48,16 +48,16 @@ const MamiForceDisconnectNotice = function(banInfo) { }, onViewPop: async () => { bgmSrc?.stop(); - bgmSrc = sfxBuf = sfxSrc = undefined; + bgmSrc = sfxBuf = undefined; }, pushOn: async views => { - const rotate = rng.next(-20, 20); - await views.push(pub, ctx => MamiAnimate({ async: true, duration: (sfxBuf?.duration ?? 1.4) * 1000, start: () => { - sfxSrc?.play(); + if(sfxBuf !== undefined) + mami.sound.audio.createSource(sfxBuf).play(); + ctx.toElem.style.top = '-100%'; }, update: t => { @@ -76,6 +76,33 @@ const MamiForceDisconnectNotice = function(banInfo) { }, })); }, + popOff: async views => { + await views.pop(ctx => MamiAnimate({ + async: true, + duration: (sfxBuf?.duration ?? 1.4) * 1000, + start: () => { + bgmSrc?.stop(); + if(sfxBuf !== undefined) + mami.sound.audio.createSource(sfxBuf, true).play(); + + ctx.toElem.style.transform = `scale(1) rotate(${rotate}deg)`; + ctx.toElem.style.filter = 'grayscale(100%)'; + }, + update: t => { + const tOutBounce = MamiEasings.inBounce(t); + ctx.fromElem.style.top = `${tOutBounce * -100}%`; + + const tOutExpo = MamiEasings.inExpo(t); + ctx.toElem.style.transform = `scale(${1 * tOutExpo}) rotate(${rotate - (rotate * tOutExpo)}deg)`; + ctx.toElem.style.filter = `grayscale(${100 - (tOutExpo * 100)}%)`; + }, + end: () => { + ctx.fromElem.style.top = null; + ctx.toElem.style.transform = null; + ctx.toElem.style.filter = null; + }, + })); + }, }; return pub; diff --git a/src/mami.js/ui/settings.jsx b/src/mami.js/ui/settings.jsx index f32cf0d..a66f245 100644 --- a/src/mami.js/ui/settings.jsx +++ b/src/mami.js/ui/settings.jsx @@ -391,12 +391,10 @@ Umi.UI.Settings = (function() { type: 'button', invoke: async button => { button.disabled = true; - await (new MamiForceDisconnectNotice({ - perma: true, - type: 'ban', - })).pushOn(mami.views); + const notice = new MamiForceDisconnectNotice({ perma: true, type: 'ban' }); + await notice.pushOn(mami.views); await MamiSleep(5000); - await mami.views.pop(); + await notice.popOff(mami.views); button.disabled = false; }, },