"use strict"; /* ---------------- 音频:程序化合成 ---------------- */ const AU={ctx:null,master:null,mgain:null,simMute:false, init(){ if(this.ctx) return; try{ this.ctx=new (window.AudioContext||window.webkitAudioContext)(); this.master=this.ctx.createGain(); this.master.gain.value=0.5; this.master.connect(this.ctx.destination); this.mgain=this.ctx.createGain(); this.mgain.gain.value=(SAVE.mute||!SAVE.music)?0:0.16; this.mgain.connect(this.master); }catch(e){} }, /* 音乐音量统一闸门:静音 或 音乐关 都归零(SAVE.mute 管 SFX 由 tone/noise 自查) */ applyMute(){ if(this.mgain) this.mgain.gain.value=(SAVE.mute||!SAVE.music)?0:0.16; }, now(){return this.ctx?this.ctx.currentTime:0;}, env(g,t,a,d,v){g.gain.setValueAtTime(0,t);g.gain.linearRampToValueAtTime(v,t+a);g.gain.exponentialRampToValueAtTime(0.001,t+a+d);}, tone(f,type,dur,vol=0.2,slide=0){ if(!this.ctx||SAVE.mute||this.simMute)return; const t=this.now(),o=this.ctx.createOscillator(),g=this.ctx.createGain(); o.type=type;o.frequency.setValueAtTime(f,t); if(slide) o.frequency.exponentialRampToValueAtTime(Math.max(20,f+slide),t+dur); this.env(g,t,0.005,dur,vol); o.connect(g);g.connect(this.master); o.start(t);o.stop(t+dur+0.05); }, noise(dur,vol=0.25,hp=400){ if(!this.ctx||SAVE.mute||this.simMute)return; const t=this.now(),len=Math.floor(this.ctx.sampleRate*dur),buf=this.ctx.createBuffer(1,len,this.ctx.sampleRate),d=buf.getChannelData(0); for(let i=0;isetTimeout(()=>AU.tone(f,"square",0.1,0.12),i*70));}, hurt(){AU.tone(160,"sawtooth",0.3,0.3,-100);AU.noise(0.3,0.3,150);}, bomb(){AU.noise(0.8,0.5,60);AU.tone(70,"sawtooth",0.7,0.3,-40);}, od(){[440,660,880,1320].forEach((f,i)=>setTimeout(()=>AU.tone(f,"sawtooth",0.09,0.1),i*50));}, graze(){AU.tone(1800,"sine",0.03,0.04);}, warn(){for(let i=0;i<4;i++)setTimeout(()=>{AU.tone(440,"square",0.15,0.15);setTimeout(()=>AU.tone(349,"square",0.15,0.15),180);},i*400);}, }; /* 简易芯片音序器 */ const MUS={step:0,next:0,bpm:138,playing:false,boss:false, bass:[45,45,48,45,52,45,48,43], lead:[69,72,76,72,74,72,69,64], tick(){ if(!AU.ctx||!this.playing||!SAVE.music)return; const spb=60/(this.bpm*2); while(this.next