Files
NumberSwipe_New/wechat-campaign-200-r2/music-assets.mjs
T

23 lines
2.1 KiB
JavaScript

import fs from 'node:fs';import path from 'node:path';
const rate=22050;
function writeWav(root,name,samples){const n=samples.length,b=Buffer.alloc(44+n*2);b.write('RIFF');b.writeUInt32LE(b.length-8,4);b.write('WAVEfmt ',8);b.writeUInt32LE(16,16);b.writeUInt16LE(1,20);b.writeUInt16LE(1,22);b.writeUInt32LE(rate,24);b.writeUInt32LE(rate*2,28);b.writeUInt16LE(2,32);b.writeUInt16LE(16,34);b.write('data',36);b.writeUInt32LE(n*2,40);for(let i=0;i<n;i++)b.writeInt16LE(Math.round(Math.max(-1,Math.min(1,samples[i]))*32767),44+i*2);fs.writeFileSync(path.join(root,'music',name+'.wav'),b);}
export function buildMusic(root){
fs.mkdirSync(path.join(root,'music'),{recursive:true});
// Selection music is byte-for-byte unchanged.
const select=new Float64Array(rate*16),notes=[60,67,72,64,69,67,64,62];
for(let k=0;k<notes.length;k++){const f=440*2**((notes[k]-69)/12),offset=k*2;for(let j=0;j<rate*4;j++){const t=j/rate,env=(1-Math.exp(-t/.025))*Math.exp(-t/.65)*Math.min(1,(4-t)/.15);select[(offset*rate+j)%select.length]+=(Math.sin(2*Math.PI*f*t)+.12*Math.sin(4*Math.PI*f*t))*env*.24;}}
writeWav(root,'select',select);
// Original 32-second warm pad: no percussion, note attacks or recurring beat.
// Integer cycles and periodic crossfades preserve both waveform and slope at wrap.
const seconds=32,samples=new Float64Array(rate*seconds),chords=[[48,55,60,64],[45,52,55,60],[48,55,62,67]];
const voices=chords.map((notes,k)=>notes.map((midi,j)=>({f:Math.round(440*2**((midi-69)/12)*seconds)/seconds,phase:(k*1.7+j*.9),gain:j===0?.75:1})));
let sum=0,peak=0;
for(let i=0;i<samples.length;i++){const t=i/rate;let value=0;
for(let k=0;k<voices.length;k++){const weight=(1-Math.cos(2*Math.PI*(t/seconds-k/voices.length)))/2;
for(const v of voices[k]){const phase=2*Math.PI*v.f*t+v.phase;value+=weight*v.gain*(Math.sin(phase)+.055*Math.sin(2*phase)+.012*Math.sin(3*phase));}}
samples[i]=value;sum+=value*value;peak=Math.max(peak,Math.abs(value));
}
const gain=Math.min(.035/Math.sqrt(sum/samples.length),.16/peak);for(let i=0;i<samples.length;i++)samples[i]*=gain;
writeWav(root,'play',samples);
}