1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
import SimpleJSSynth from './simple-js-synth.js';
import * as pattern from './pattern.js';
const panel = document.getElementById('synth');
const enabled = document.getElementById('synth-enabled');
const freq = document.getElementById('synth-freq');
const poly = document.getElementById('synth-voices');
const optsPaste = document.getElementById('synth-opts-paste');
const optsReset = document.getElementById('synth-opts-reset');
const ctx = new window.AudioContext();
const opts = {};
const voices = [];
const tones = [];
export const getOptions = () => opts;
export const setOptions = (o) => {
Object.assign(opts, o);
while (voices.length)
voices.pop().destroy();
for (let i = 0; i < opts.polyphony; i++)
voices.push(SimpleJSSynth(ctx.destination, opts));
};
enabled.onchange = () => {
if (enabled.checked) ctx.resume();
else ctx.suspend();
panel.classList.toggle('controls--minimized', !enabled.checked);
};
freq.onchange = () => {
let frequency = +freq.value;
if (!frequency || frequency < 1) frequency = 110;
opts.frequency = frequency;
};
poly.onchange = () => {
let polyphony = +poly.value;
if (!polyphony || polyphony < 1) polyphony = 1;
setOptions({ polyphony });
};
optsPaste.onclick = () => {
const json = window.prompt("Please paste the JSON from the right panel of the synth page:");
setOptions(JSON.parse(json));
};
optsReset.onclick = () => setOptions({
osc1type: "sine", osc1vol: 0.2, osc1tune: 0,
osc2type: "square", osc2vol: 0.14, osc2tune: 12,
osc3type: "sine", osc3vol: 0.05, osc3tune: -6.7,
attack: 0, decay: 0.3, sustain: 0.5, susdecay: 5,
cutoff: 36,
frequency: 110,
polyphony: 8,
});
optsReset.onclick();
export const on = (key, note, vol=1) => {
if (!enabled.checked) return;
ctx.resume();
if (tones[key]?.note === note) return;
off(key);
const freq = opts.frequency * Math.pow(2, note / pattern.getLength());
const voice = voices.find(s => s.isReady());
if (!voice) return;
voice.noteOn(freq, vol);
tones[key] = off && { note, voice };
};
export const off = (key) => {
tones[key]?.voice.noteOff();
delete tones[key];
};
export const isOn = (note) => Object.values(tones).some(t => t.note === note);
|