1//import { ZZFX } from 'zzfx'; 2import { midiToFreq, noteToMidi } from './util.mjs'; 3import { registerSound } from './superdough.mjs'; 4import { getAudioContext } from './audioContext.mjs'; 5import { buildSamples } from './zzfx_fork.mjs'; 6import { onceEnded, releaseAudioNode } from './helpers.mjs'; 7 8export const getZZFX = (value, t) => { 9 let { 10 s, 11 note = 36, 12 freq, 13 // 14 zrand = 0, 15 attack = 0, 16 decay = 0, 17 sustain = 0.8, 18 release = 0.1, 19 curve = 1, 20 slide = 0, 21 deltaSlide = 0, 22 pitchJump = 0, 23 pitchJumpTime = 0, 24 lfo = 0, 25 znoise = 0, 26 zmod = 0, 27 zcrush = 0, 28 zdelay = 0, 29 tremolo = 0, 30 duration = 0.2, 31 zzfx, 32 } = value; 33 const sustainTime = Math.max(duration - attack - decay, 0); 34 if (typeof note === 'string') { 35 note = noteToMidi(note); // e.g. c3 => 48 36 } 37 // get frequency 38 if (!freq && typeof note === 'number') { 39 freq = midiToFreq(note); 40 } 41 s = s.replace('z_', ''); 42 const shape = ['sine', 'triangle', 'sawtooth', 'tan', 'noise'].indexOf(s) || 0; 43 curve = s === 'square' ? 0 : curve; 44 45 const params = zzfx || [ 46 0.25, // volume 47 zrand, 48 freq, 49 attack, 50 sustainTime, 51 release, 52 shape, 53 curve, 54 slide, 55 deltaSlide, 56 pitchJump, 57 pitchJumpTime, 58 lfo, 59 znoise, 60 zmod, 61 zcrush, 62 zdelay, 63 sustain, // sustain volume! 64 decay, 65 tremolo, 66 ]; 67 // console.log(redableZZFX(params)); 68 69 const samples = /* ZZFX. */ buildSamples(...params); 70 const context = getAudioContext(); 71 const buffer = context.createBuffer(1, samples.length, context.sampleRate); 72 buffer.getChannelData(0).set(samples); 73 const source = getAudioContext().createBufferSource(); 74 source.buffer = buffer; 75 source.start(t); 76 return { 77 node: source, 78 }; 79}; 80 81export function registerZZFXSounds() { 82 ['zzfx', 'z_sine', 'z_sawtooth', 'z_triangle', 'z_square', 'z_tan', 'z_noise'].forEach((wave) => { 83 registerSound( 84 wave, 85 (t, value, onended) => { 86 const { node: o } = getZZFX({ s: wave, ...value }, t); 87 onceEnded(o, () => { 88 releaseAudioNode(o); 89 onended(); 90 }); 91 return { 92 node: o, 93 nodes: { source: [o] }, 94 stop: () => {}, 95 }; 96 }, 97 { type: 'synth', prebake: true }, 98 ); 99 }); 100} 101 102// just for debugging 103function redableZZFX(params) { 104 const paramOrder = [ 105 'volume', 106 'zrand', 107 'frequency', 108 'attack', 109 'sustain', 110 'release', 111 'shape', 112 'curve', 113 'slide', 114 'deltaSlide', 115 'pitchJump', 116 'pitchJumpTime', 117 'lfo', 118 'noise', 119 'zmod', 120 'zcrush', 121 'zdelay', 122 'sustainVolume', 123 'decay', 124 'tremolo', 125 ]; 126 return Object.fromEntries(paramOrder.map((param, i) => [param, params[i]])); 127}