// LearnPlay adaptation tooling, MIT. Run: node addons/vendor/beepbox/compile-csp.mjs // Only three known instruments are supported. Do not add arbitrary song imports. import fs from 'node:fs'; import vm from 'node:vm'; const root = new URL('./', import.meta.url); const original = fs.readFileSync(new URL('global/beepbox_synth.js', root), 'utf8'); const functions = new Map(); function capture(...args) { const body = args.at(-1); functions.set(body, args); return Function(...args); } const sandbox = { console, Function: capture, performance }; vm.createContext(sandbox); vm.runInContext(original, sandbox); const { Song, Synth } = sandbox.beepbox; const instruments = [ {type: 'chip', wave: 'triangle', volume: 65, effects: []}, {type: 'chip', wave: 'square', volume: 30, effects: []}, {type: 'noise', wave: 'retro', volume: 45, effects: []}, ]; for (const [i, instrument] of instruments.entries()) { const song = new Song(); song.fromJsonObject({format:'BeepBox', version:9, key:'C', beatsPerBar:4, ticksPerBeat:4, beatsPerMinute:100, introBars:0, loopBars:1, channels:[{type:i === 2 ? 'drum':'pitch', instruments:[instrument], patterns:[{notes:[{pitches:[i===2?4:36],points:[{tick:0,pitchBend:0,volume:100},{tick:16,pitchBend:0,volume:0}]}]}],sequence:[1]}]}); const synth = new Synth(song); for (let block=0; block<30; block++) synth.synthesize(new Float32Array(4096),new Float32Array(4096),4096,true); } function hash(s) { let h=2166136261; for(let i=0;i>>0).toString(36); } const seen = new Set(); const entries = [...functions].map(([body,args]) => { const key=hash(body); if(seen.has(key)) throw Error('Hash collision'); seen.add(key); return JSON.stringify(key)+': function('+args.slice(0,-1).join(',')+') {\n'+body+'\n}'; }); const prefix = '// BeepBox 4.2.0 by John Nesky, MIT (LICENSE.md).\n// LearnPlay CSP adaptation: precompiled fixed instrument functions; no runtime eval.\n'+ 'var beepboxStaticFunctions={'+entries.join(',\n')+'};\n'+ 'function beepboxStaticFunction(...args){const body=args[args.length-1];let h=2166136261;for(let i=0;i>>0).toString(36)];if(!fn)throw Error("Unsupported BeepBox instrument configuration");return fn;}\n'; const compiled = prefix + original.replace(/new Function\(/g,'beepboxStaticFunction(').replace(/\/\/# sourceMappingURL=.*$/m,''); fs.writeFileSync(new URL('beepbox-csp.js',root),compiled); console.log('Compiled '+functions.size+' static DSP factories; '+compiled.length+' bytes.');