zzfx.mjsannotatedzzfx.mjssource127 lines · 2.7 KB · raw

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';
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}

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}