UNPKG

superdough

Version:

simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.

1,055 lines 54.1 kB
import { map as Zn } from "nanostores"; if (typeof DelayNode < "u") { class e extends DelayNode { constructor(t, o, c, g) { super(t), o = Math.abs(o), this.delayTime.value = c; const s = t.createGain(); s.gain.value = Math.min(Math.abs(g), 0.995), this.feedback = s.gain; const a = t.createGain(); return a.gain.value = o, this.delayGain = a, this.connect(s), this.connect(a), s.connect(this), this.connect = (I) => a.connect(I), this; } start(t) { this.delayGain.gain.setValueAtTime(this.delayGain.gain.value, t + this.delayTime.value); } } AudioContext.prototype.createFeedbackDelay = function(n, t, o) { return new e(this, n, t, o); }; } var fe = {}; fe.generateReverb = function(e, n) { for (var t = e.audioContext || new AudioContext(), o = t.sampleRate, c = e.numChannels || 2, g = e.decayTime * 1.5, s = Math.round(e.decayTime * o), a = Math.round(g * o), I = Math.round((e.fadeInTime || 0) * o), i = Math.pow(1 / 1e3, 1 / s), r = t.createBuffer(c, a, o), d = 0; d < c; d++) { for (var l = r.getChannelData(d), C = 0; C < a; C++) l[C] = wn() * Math.pow(i, C); for (var C = 0; C < I; C++) l[C] *= C / I; } yn(r, e.lpFreqStart || 0, e.lpFreqEnd || 0, e.decayTime, n); }; fe.generateGraph = function(e, n, t, o, c) { var g = document.createElement("canvas"); g.width = n, g.height = t; var s = g.getContext("2d"); s.fillStyle = "#000", s.fillRect(0, 0, g.width, g.height), s.fillStyle = "#fff"; for (var a = n / e.length, I = t / (c - o), i = 0; i < e.length; i++) s.fillRect(i * a, t - (e[i] - o) * I, 1, 1); return g; }; var yn = function(e, n, t, o, c) { if (n == 0) { c(e); return; } var g = Xn(e), s = new OfflineAudioContext(e.numberOfChannels, g[0].length, e.sampleRate), a = s.createBufferSource(); a.buffer = e; var I = s.createBiquadFilter(); n = Math.min(n, e.sampleRate / 2), t = Math.min(t, e.sampleRate / 2), I.type = "lowpass", I.Q.value = 1e-4, I.frequency.setValueAtTime(n, 0), I.frequency.linearRampToValueAtTime(t, o), a.connect(I), I.connect(s.destination), a.start(), s.oncomplete = function(i) { c(i.renderedBuffer); }, s.startRendering(), window.filterNode = I; }, Xn = function(e) { for (var n = [], t = 0; t < e.numberOfChannels; t++) n[t] = e.getChannelData(t); return n; }, wn = function() { return Math.random() * 2 - 1; }; typeof AudioContext < "u" && (AudioContext.prototype.adjustLength = function(e, n) { const t = n.sampleRate * e, o = this.createBuffer(n.numberOfChannels, n.length, n.sampleRate); for (let c = 0; c < n.numberOfChannels; c++) { let g = n.getChannelData(c), s = o.getChannelData(c); for (let a = 0; a < t; a++) s[a] = g[a] || 0; } return o; }, AudioContext.prototype.createReverb = function(e, n, t, o, c) { const g = this.createConvolver(); return g.generate = (s = 2, a = 0.1, I = 15e3, i = 1e3, r) => { g.duration = s, g.fade = a, g.lp = I, g.dim = i, g.ir = r, r ? g.buffer = this.adjustLength(s, r) : fe.generateReverb( { audioContext: this, numChannels: 2, decayTime: s, fadeInTime: a, lpFreqStart: I, lpFreqEnd: i }, (d) => { g.buffer = d; } ); }, g.generate(e, n, t, o, c), g; }); var Oe = { a: { freqs: [660, 1120, 2750, 3e3, 3350], gains: [1, 0.5012, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, e: { freqs: [440, 1800, 2700, 3e3, 3300], gains: [1, 0.1995, 0.1259, 0.1, 0.1], qs: [70, 80, 100, 120, 120] }, i: { freqs: [270, 1850, 2900, 3350, 3590], gains: [1, 0.0631, 0.0631, 0.0158, 0.0158], qs: [40, 90, 100, 120, 120] }, o: { freqs: [430, 820, 2700, 3e3, 3300], gains: [1, 0.3162, 0.0501, 0.0794, 0.01995], qs: [40, 80, 100, 120, 120] }, u: { freqs: [370, 630, 2750, 3e3, 3400], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, ae: { freqs: [650, 1515, 2400, 3e3, 3350], gains: [1, 0.5, 0.1008, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, aa: { freqs: [560, 900, 2570, 3e3, 3300], gains: [1, 0.5, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, oe: { freqs: [500, 1430, 2300, 3e3, 3300], gains: [1, 0.2, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, ue: { freqs: [250, 1750, 2150, 3200, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, y: { freqs: [400, 1460, 2400, 3e3, 3300], gains: [1, 0.2, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, uh: { freqs: [600, 1250, 2100, 3100, 3500], gains: [1, 0.3, 0.0608, 0.0316, 0.01995], qs: [40, 70, 100, 120, 130] }, un: { freqs: [500, 1240, 2280, 3e3, 3500], gains: [1, 0.1, 0.1708, 0.0216, 0.02995], qs: [40, 60, 100, 120, 120] }, en: { freqs: [600, 1480, 2450, 3200, 3300], gains: [1, 0.15, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, an: { freqs: [700, 1050, 2500, 3e3, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, on: { freqs: [500, 1080, 2350, 3e3, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, get æ() { return this.ae; }, get ø() { return this.oe; }, get ɑ() { return this.aa; }, get å() { return this.aa; }, get ö() { return this.oe; }, get ü() { return this.ue; }, get ı() { return this.y; } }; if (typeof GainNode < "u") { class e extends GainNode { constructor(t, o) { if (super(t), !Oe[o]) throw new Error("vowel: unknown vowel " + o); const { gains: c, qs: g, freqs: s } = Oe[o], a = t.createGain(); for (let I = 0; I < 5; I++) { const i = t.createGain(); i.gain.value = c[I]; const r = t.createBiquadFilter(); r.type = "bandpass", r.Q.value = g[I], r.frequency.value = s[I], this.connect(r), r.connect(i), i.connect(a); } return a.gain.value = 8, this.connect = (I) => a.connect(I), this; } } AudioContext.prototype.createVowelFilter = function(n) { return new e(this, n); }; } let qe = (e) => console.log(e); const v = (...e) => qe(...e), dt = (e) => { qe = e; }, Vn = (e) => { if (typeof e != "string") return []; const [n, t = "", o] = e.match(/^([a-gA-G])([#bsf]*)([0-9]*)$/)?.slice(1) || []; return n ? [n, t, o ? Number(o) : void 0] : []; }, Wn = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 }, Hn = { "#": 1, b: -1, s: 1, f: -1 }, ie = (e, n = 3) => { const [t, o, c = n] = Vn(e); if (!t) throw new Error('not a note: "' + e + '"'); const g = Wn[t.toLowerCase()], s = o?.split("").reduce((a, I) => a + Hn[I], 0) || 0; return (Number(c) + 1) * 12 + g + s; }, Pe = (e) => Math.pow(2, (e - 69) / 12) * 440, ne = (e, n, t) => Math.min(Math.max(e, n), t), Nn = (e) => 12 * Math.log(e / 440) / Math.LN2 + 69, Kn = (e, n) => { if (typeof e != "object") throw new Error("valueToMidi: expected object value"); let { freq: t, note: o } = e; if (typeof t == "number") return Nn(t); if (typeof o == "string") return ie(o); if (typeof o == "number") return o; if (!n) throw new Error("valueToMidi: expected freq or note to be set"); return n; }; function J(e, n = 0, t) { return isNaN(Number(e)) ? (!t && v(`"${e}" is not a number, falling back to ${n}`, "warning"), n) : e; } const _e = (e, n) => (e % n + n) % n, je = (e, n) => _e(Math.round(J(e, 0)), n), Yn = "data:application/javascript;base64,Ly8gY29hcnNlLCBjcnVzaCwgYW5kIHNoYXBlIHByb2Nlc3NvcnMgYWRhcHRlZCBmcm9tIGRrdHIwJ3Mgd2ViZGlydDogaHR0cHM6Ly9naXRodWIuY29tL2RrdHIwL1dlYkRpcnQvYmxvYi81Y2UzZDY5ODM2MmM1NGQ2ZTFiNjhhY2M0N2ViMjk1NWFjNjJjNzkzL2Rpc3QvQXVkaW9Xb3JrbGV0cy5qcwovLyBMSUNFTlNFIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIHYzLjAgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9ka3RyMC9XZWJEaXJ0L2Jsb2IvbWFpbi9MSUNFTlNFCi8vIFRPRklYOiBUSElTIEZJTEUgRE9FUyBOT1QgU1VQUE9SVCBJTVBPUlRTIE9OIERFUE9MWU1FTlQKY29uc3QgY2xhbXAgPSAobnVtLCBtaW4sIG1heCkgPT4gTWF0aC5taW4oTWF0aC5tYXgobnVtLCBtaW4pLCBtYXgpOwpjb25zdCBfbW9kID0gKG4sIG0pID0+ICgobiAlIG0pICsgbSkgJSBtOwoKY29uc3QgYmxvY2tTaXplID0gMTI4OwovLyBhZGp1c3Qgd2F2ZXNoYXBlIHRvIHJlbW92ZSBmcmVxdWVuY2llcyBhYm92ZSBueXF1aXN0IHRvIHByZXZlbnQgYWxpYXNpbmcKLy8gcmVmZXJlbmNlZCBmcm9tIGh0dHBzOi8vd3d3Lmt2cmF1ZGlvLmNvbS9mb3J1bS92aWV3dG9waWMucGhwP3Q9Mzc1NTE3CmZ1bmN0aW9uIHBvbHlCbGVwKHBoYXNlLCBkdCkgewogIC8vIDAgPD0gcGhhc2UgPCAxCiAgaWYgKHBoYXNlIDwgZHQpIHsKICAgIHBoYXNlIC89IGR0OwogICAgLy8gMiAqIChwaGFzZSAtIHBoYXNlXjIvMiAtIDAuNSkKICAgIHJldHVybiBwaGFzZSArIHBoYXNlIC0gcGhhc2UgKiBwaGFzZSAtIDE7CiAgfQoKICAvLyAtMSA8IHBoYXNlIDwgMAogIGVsc2UgaWYgKHBoYXNlID4gMSAtIGR0KSB7CiAgICBwaGFzZSA9IChwaGFzZSAtIDEpIC8gZHQ7CiAgICAvLyAyICogKHBoYXNlXjIvMiArIHBoYXNlICsgMC41KQogICAgcmV0dXJuIHBoYXNlICogcGhhc2UgKyBwaGFzZSArIHBoYXNlICsgMTsKICB9CgogIC8vIDAgb3RoZXJ3aXNlCiAgZWxzZSB7CiAgICByZXR1cm4gMDsKICB9Cn0KCmNvbnN0IHdhdmVzaGFwZXMgPSB7CiAgdHJpKHBoYXNlLCBza2V3ID0gMC41KSB7CiAgICBjb25zdCB4ID0gMSAtIHNrZXc7CiAgICBpZiAocGhhc2UgPj0gc2tldykgewogICAgICByZXR1cm4gMSAvIHggLSBwaGFzZSAvIHg7CiAgICB9CiAgICByZXR1cm4gcGhhc2UgLyBza2V3OwogIH0sCiAgc2luZShwaGFzZSkgewogICAgcmV0dXJuIE1hdGguc2luKE1hdGguUEkgKiAyICogcGhhc2UpICogMC41ICsgMC41OwogIH0sCiAgcmFtcChwaGFzZSkgewogICAgcmV0dXJuIHBoYXNlOwogIH0sCiAgc2F3KHBoYXNlKSB7CiAgICByZXR1cm4gMSAtIHBoYXNlOwogIH0sCgogIHNxdWFyZShwaGFzZSwgc2tldyA9IDAuNSkgewogICAgaWYgKHBoYXNlID49IHNrZXcpIHsKICAgICAgcmV0dXJuIDA7CiAgICB9CiAgICByZXR1cm4gMTsKICB9LAogIGN1c3RvbShwaGFzZSwgdmFsdWVzID0gWzAsIDFdKSB7CiAgICBjb25zdCBudW1QYXJ0cyA9IHZhbHVlcy5sZW5ndGggLSAxOwogICAgY29uc3QgY3VyclBhcnQgPSBNYXRoLmZsb29yKHBoYXNlICogbnVtUGFydHMpOwoKICAgIGNvbnN0IHBhcnRMZW5ndGggPSAxIC8gbnVtUGFydHM7CiAgICBjb25zdCBzdGFydFZhbCA9IGNsYW1wKHZhbHVlc1tjdXJyUGFydF0sIDAsIDEpOwogICAgY29uc3QgZW5kVmFsID0gY2xhbXAodmFsdWVzW2N1cnJQYXJ0ICsgMV0sIDAsIDEpOwogICAgY29uc3QgeTIgPSBlbmRWYWw7CiAgICBjb25zdCB5MSA9IHN0YXJ0VmFsOwogICAgY29uc3QgeDEgPSAwOwogICAgY29uc3QgeDIgPSBwYXJ0TGVuZ3RoOwogICAgY29uc3Qgc2xvcGUgPSAoeTIgLSB5MSkgLyAoeDIgLSB4MSk7CiAgICByZXR1cm4gc2xvcGUgKiAocGhhc2UgLSBwYXJ0TGVuZ3RoICogY3VyclBhcnQpICsgc3RhcnRWYWw7CiAgfSwKICBzYXdibGVwKHBoYXNlLCBkdCkgewogICAgY29uc3QgdiA9IDIgKiBwaGFzZSAtIDE7CiAgICByZXR1cm4gdiAtIHBvbHlCbGVwKHBoYXNlLCBkdCk7CiAgfSwKfTsKCmNvbnN0IHdhdmVTaGFwZU5hbWVzID0gT2JqZWN0LmtleXMod2F2ZXNoYXBlcyk7CmNsYXNzIExGT1Byb2Nlc3NvciBleHRlbmRzIEF1ZGlvV29ya2xldFByb2Nlc3NvciB7CiAgc3RhdGljIGdldCBwYXJhbWV0ZXJEZXNjcmlwdG9ycygpIHsKICAgIHJldHVybiBbCiAgICAgIHsgbmFtZTogJ3RpbWUnLCBkZWZhdWx0VmFsdWU6IDAgfSwKICAgICAgeyBuYW1lOiAnZW5kJywgZGVmYXVsdFZhbHVlOiAwIH0sCiAgICAgIHsgbmFtZTogJ2ZyZXF1ZW5jeScsIGRlZmF1bHRWYWx1ZTogMC41IH0sCiAgICAgIHsgbmFtZTogJ3NrZXcnLCBkZWZhdWx0VmFsdWU6IDAuNSB9LAogICAgICB7IG5hbWU6ICdkZXB0aCcsIGRlZmF1bHRWYWx1ZTogMSB9LAogICAgICB7IG5hbWU6ICdwaGFzZW9mZnNldCcsIGRlZmF1bHRWYWx1ZTogMCB9LAogICAgICB7IG5hbWU6ICdzaGFwZScsIGRlZmF1bHRWYWx1ZTogMCB9LAogICAgICB7IG5hbWU6ICdkY29mZnNldCcsIGRlZmF1bHRWYWx1ZTogMCB9LAogICAgXTsKICB9CgogIGNvbnN0cnVjdG9yKCkgewogICAgc3VwZXIoKTsKICAgIHRoaXMucGhhc2U7CiAgfQoKICBpbmNyZW1lbnRQaGFzZShkdCkgewogICAgdGhpcy5waGFzZSArPSBkdDsKICAgIGlmICh0aGlzLnBoYXNlID4gMS4wKSB7CiAgICAgIHRoaXMucGhhc2UgPSB0aGlzLnBoYXNlIC0gMTsKICAgIH0KICB9CgogIHByb2Nlc3MoaW5wdXRzLCBvdXRwdXRzLCBwYXJhbWV0ZXJzKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWYKICAgIGlmIChjdXJyZW50VGltZSA+PSBwYXJhbWV0ZXJzLmVuZFswXSkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CgogICAgY29uc3Qgb3V0cHV0ID0gb3V0cHV0c1swXTsKICAgIGNvbnN0IGZyZXF1ZW5jeSA9IHBhcmFtZXRlcnNbJ2ZyZXF1ZW5jeSddWzBdOwoKICAgIGNvbnN0IHRpbWUgPSBwYXJhbWV0ZXJzWyd0aW1lJ11bMF07CiAgICBjb25zdCBkZXB0aCA9IHBhcmFtZXRlcnNbJ2RlcHRoJ11bMF07CiAgICBjb25zdCBza2V3ID0gcGFyYW1ldGVyc1snc2tldyddWzBdOwogICAgY29uc3QgcGhhc2VvZmZzZXQgPSBwYXJhbWV0ZXJzWydwaGFzZW9mZnNldCddWzBdOwoKICAgIGNvbnN0IGRjb2Zmc2V0ID0gcGFyYW1ldGVyc1snZGNvZmZzZXQnXVswXTsKICAgIGNvbnN0IHNoYXBlID0gd2F2ZVNoYXBlTmFtZXNbcGFyYW1ldGVyc1snc2hhcGUnXVswXV07CgogICAgY29uc3QgYmxvY2tTaXplID0gb3V0cHV0WzBdLmxlbmd0aCA/PyAwOwoKICAgIGlmICh0aGlzLnBoYXNlID09IG51bGwpIHsKICAgICAgdGhpcy5waGFzZSA9IF9tb2QodGltZSAqIGZyZXF1ZW5jeSArIHBoYXNlb2Zmc2V0LCAxKTsKICAgIH0KICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZgogICAgY29uc3QgZHQgPSBmcmVxdWVuY3kgLyBzYW1wbGVSYXRlOwogICAgZm9yIChsZXQgbiA9IDA7IG4gPCBibG9ja1NpemU7IG4rKykgewogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG91dHB1dC5sZW5ndGg7IGkrKykgewogICAgICAgIGNvbnN0IG1vZHZhbCA9ICh3YXZlc2hhcGVzW3NoYXBlXSh0aGlzLnBoYXNlLCBza2V3KSArIGRjb2Zmc2V0KSAqIGRlcHRoOwogICAgICAgIG91dHB1dFtpXVtuXSA9IG1vZHZhbDsKICAgICAgfQogICAgICB0aGlzLmluY3JlbWVudFBoYXNlKGR0KTsKICAgIH0KCiAgICByZXR1cm4gdHJ1ZTsKICB9Cn0KcmVnaXN0ZXJQcm9jZXNzb3IoJ2xmby1wcm9jZXNzb3InLCBMRk9Qcm9jZXNzb3IpOwoKY2xhc3MgQ29hcnNlUHJvY2Vzc29yIGV4dGVuZHMgQXVkaW9Xb3JrbGV0UHJvY2Vzc29yIHsKICBzdGF0aWMgZ2V0IHBhcmFtZXRlckRlc2NyaXB0b3JzKCkgewogICAgcmV0dXJuIFt7IG5hbWU6ICdjb2Fyc2UnLCBkZWZhdWx0VmFsdWU6IDEgfV07CiAgfQoKICBjb25zdHJ1Y3RvcigpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLnN0YXJ0ZWQgPSBmYWxzZTsKICB9CgogIHByb2Nlc3MoaW5wdXRzLCBvdXRwdXRzLCBwYXJhbWV0ZXJzKSB7CiAgICBjb25zdCBpbnB1dCA9IGlucHV0c1swXTsKICAgIGNvbnN0IG91dHB1dCA9IG91dHB1dHNbMF07CgogICAgY29uc3QgaGFzSW5wdXQgPSAhKGlucHV0WzBdID09PSB1bmRlZmluZWQpOwogICAgaWYgKHRoaXMuc3RhcnRlZCAmJiAhaGFzSW5wdXQpIHsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgdGhpcy5zdGFydGVkID0gaGFzSW5wdXQ7CgogICAgbGV0IGNvYXJzZSA9IHBhcmFtZXRlcnMuY29hcnNlWzBdID8/IDA7CiAgICBjb2Fyc2UgPSBNYXRoLm1heCgxLCBjb2Fyc2UpOwogICAgZm9yIChsZXQgbiA9IDA7IG4gPCBibG9ja1NpemU7IG4rKykgewogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlucHV0Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgb3V0cHV0W2ldW25dID0gbiAlIGNvYXJzZSA9PT0gMCA/IGlucHV0W2ldW25dIDogb3V0cHV0W2ldW24gLSAxXTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQp9CnJlZ2lzdGVyUHJvY2Vzc29yKCdjb2Fyc2UtcHJvY2Vzc29yJywgQ29hcnNlUHJvY2Vzc29yKTsKCmNsYXNzIENydXNoUHJvY2Vzc29yIGV4dGVuZHMgQXVkaW9Xb3JrbGV0UHJvY2Vzc29yIHsKICBzdGF0aWMgZ2V0IHBhcmFtZXRlckRlc2NyaXB0b3JzKCkgewogICAgcmV0dXJuIFt7IG5hbWU6ICdjcnVzaCcsIGRlZmF1bHRWYWx1ZTogMCB9XTsKICB9CgogIGNvbnN0cnVjdG9yKCkgewogICAgc3VwZXIoKTsKICAgIHRoaXMuc3RhcnRlZCA9IGZhbHNlOwogIH0KCiAgcHJvY2VzcyhpbnB1dHMsIG91dHB1dHMsIHBhcmFtZXRlcnMpIHsKICAgIGNvbnN0IGlucHV0ID0gaW5wdXRzWzBdOwogICAgY29uc3Qgb3V0cHV0ID0gb3V0cHV0c1swXTsKCiAgICBjb25zdCBoYXNJbnB1dCA9ICEoaW5wdXRbMF0gPT09IHVuZGVmaW5lZCk7CiAgICBpZiAodGhpcy5zdGFydGVkICYmICFoYXNJbnB1dCkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICB0aGlzLnN0YXJ0ZWQgPSBoYXNJbnB1dDsKCiAgICBsZXQgY3J1c2ggPSBwYXJhbWV0ZXJzLmNydXNoWzBdID8/IDg7CiAgICBjcnVzaCA9IE1hdGgubWF4KDEsIGNydXNoKTsKCiAgICBmb3IgKGxldCBuID0gMDsgbiA8IGJsb2NrU2l6ZTsgbisrKSB7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW5wdXQubGVuZ3RoOyBpKyspIHsKICAgICAgICBjb25zdCB4ID0gTWF0aC5wb3coMiwgY3J1c2ggLSAxKTsKICAgICAgICBvdXRwdXRbaV1bbl0gPSBNYXRoLnJvdW5kKGlucHV0W2ldW25dICogeCkgLyB4OwogICAgICB9CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsKICB9Cn0KcmVnaXN0ZXJQcm9jZXNzb3IoJ2NydXNoLXByb2Nlc3NvcicsIENydXNoUHJvY2Vzc29yKTsKCmNsYXNzIFNoYXBlUHJvY2Vzc29yIGV4dGVuZHMgQXVkaW9Xb3JrbGV0UHJvY2Vzc29yIHsKICBzdGF0aWMgZ2V0IHBhcmFtZXRlckRlc2NyaXB0b3JzKCkgewogICAgcmV0dXJuIFsKICAgICAgeyBuYW1lOiAnc2hhcGUnLCBkZWZhdWx0VmFsdWU6IDAgfSwKICAgICAgeyBuYW1lOiAncG9zdGdhaW4nLCBkZWZhdWx0VmFsdWU6IDEgfSwKICAgIF07CiAgfQoKICBjb25zdHJ1Y3RvcigpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLnN0YXJ0ZWQgPSBmYWxzZTsKICB9CgogIHByb2Nlc3MoaW5wdXRzLCBvdXRwdXRzLCBwYXJhbWV0ZXJzKSB7CiAgICBjb25zdCBpbnB1dCA9IGlucHV0c1swXTsKICAgIGNvbnN0IG91dHB1dCA9IG91dHB1dHNbMF07CgogICAgY29uc3QgaGFzSW5wdXQgPSAhKGlucHV0WzBdID09PSB1bmRlZmluZWQpOwogICAgaWYgKHRoaXMuc3RhcnRlZCAmJiAhaGFzSW5wdXQpIHsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgdGhpcy5zdGFydGVkID0gaGFzSW5wdXQ7CgogICAgbGV0IHNoYXBlID0gcGFyYW1ldGVycy5zaGFwZVswXTsKICAgIHNoYXBlID0gc2hhcGUgPCAxID8gc2hhcGUgOiAxLjAgLSA0ZS0xMDsKICAgIHNoYXBlID0gKDIuMCAqIHNoYXBlKSAvICgxLjAgLSBzaGFwZSk7CiAgICBjb25zdCBwb3N0Z2FpbiA9IE1hdGgubWF4KDAuMDAxLCBNYXRoLm1pbigxLCBwYXJhbWV0ZXJzLnBvc3RnYWluWzBdKSk7CgogICAgZm9yIChsZXQgbiA9IDA7IG4gPCBibG9ja1NpemU7IG4rKykgewogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlucHV0Lmxlbmd0aDsgaSsrKSB7CiAgICAgICAgb3V0cHV0W2ldW25dID0gKCgoMSArIHNoYXBlKSAqIGlucHV0W2ldW25dKSAvICgxICsgc2hhcGUgKiBNYXRoLmFicyhpbnB1dFtpXVtuXSkpKSAqIHBvc3RnYWluOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsKICB9Cn0KcmVnaXN0ZXJQcm9jZXNzb3IoJ3NoYXBlLXByb2Nlc3NvcicsIFNoYXBlUHJvY2Vzc29yKTsKCmZ1bmN0aW9uIGZhc3RfdGFuaCh4KSB7CiAgY29uc3QgeDIgPSB4ICogeDsKICByZXR1cm4gKHggKiAoMjcuMCArIHgyKSkgLyAoMjcuMCArIDkuMCAqIHgyKTsKfQpjb25zdCBfUEkgPSAzLjE0MTU5MjY1MzU5OwovL2FkYXB0ZWQgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vVGhlQm91dGVpbGxhY0JlYXIvd2ViYXVkaW93b3JrbGV0LXdhc20/dGFiPU1JVC0xLW92LWZpbGUKY2xhc3MgTGFkZGVyUHJvY2Vzc29yIGV4dGVuZHMgQXVkaW9Xb3JrbGV0UHJvY2Vzc29yIHsKICBzdGF0aWMgZ2V0IHBhcmFtZXRlckRlc2NyaXB0b3JzKCkgewogICAgcmV0dXJuIFsKICAgICAgeyBuYW1lOiAnZnJlcXVlbmN5JywgZGVmYXVsdFZhbHVlOiA1MDAgfSwKICAgICAgeyBuYW1lOiAncScsIGRlZmF1bHRWYWx1ZTogMSB9LAogICAgICB7IG5hbWU6ICdkcml2ZScsIGRlZmF1bHRWYWx1ZTogMC42OSB9LAogICAgXTsKICB9CgogIGNvbnN0cnVjdG9yKCkgewogICAgc3VwZXIoKTsKICAgIHRoaXMuc3RhcnRlZCA9IGZhbHNlOwogICAgdGhpcy5wMCA9IFswLCAwXTsKICAgIHRoaXMucDEgPSBbMCwgMF07CiAgICB0aGlzLnAyID0gWzAsIDBdOwogICAgdGhpcy5wMyA9IFswLCAwXTsKICAgIHRoaXMucDMyID0gWzAsIDBdOwogICAgdGhpcy5wMzMgPSBbMCwgMF07CiAgICB0aGlzLnAzNCA9IFswLCAwXTsKICB9CgogIHByb2Nlc3MoaW5wdXRzLCBvdXRwdXRzLCBwYXJhbWV0ZXJzKSB7CiAgICBjb25zdCBpbnB1dCA9IGlucHV0c1swXTsKICAgIGNvbnN0IG91dHB1dCA9IG91dHB1dHNbMF07CgogICAgY29uc3QgaGFzSW5wdXQgPSAhKGlucHV0WzBdID09PSB1bmRlZmluZWQpOwogICAgaWYgKHRoaXMuc3RhcnRlZCAmJiAhaGFzSW5wdXQpIHsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQoKICAgIHRoaXMuc3RhcnRlZCA9IGhhc0lucHV0OwoKICAgIGNvbnN0IHJlc29uYW5jZSA9IHBhcmFtZXRlcnMucVswXTsKICAgIGNvbnN0IGRyaXZlID0gY2xhbXAoTWF0aC5leHAocGFyYW1ldGVycy5kcml2ZVswXSksIDAuMSwgMjAwMCk7CgogICAgbGV0IGN1dG9mZiA9IHBhcmFtZXRlcnMuZnJlcXVlbmN5WzBdOwogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmCiAgICBjdXRvZmYgPSAoY3V0b2ZmICogMiAqIF9QSSkgLyBzYW1wbGVSYXRlOwogICAgY3V0b2ZmID0gY3V0b2ZmID4gMSA/IDEgOiBjdXRvZmY7CgogICAgY29uc3QgayA9IE1hdGgubWluKDgsIHJlc29uYW5jZSAqIDAuNCk7CiAgICAvLyAgICAgICAgICAgICAgIGRyaXZlIG1ha2V1cCAgKiByZXNvbmFuY2Ugdm9sdW1lIGxvc3MgbWFrZXVwCiAgICBsZXQgbWFrZXVwZ2FpbiA9ICgxIC8gZHJpdmUpICogTWF0aC5taW4oMS43NSwgMSArIGspOwoKICAgIGZvciAobGV0IG4gPSAwOyBuIDwgYmxvY2tTaXplOyBuKyspIHsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbnB1dC5sZW5ndGg7IGkrKykgewogICAgICAgIGNvbnN0IG91dCA9IHRoaXMucDNbaV0gKiAwLjM2MDg5MSArIHRoaXMucDMyW2ldICogMC40MTcyOSArIHRoaXMucDMzW2ldICogMC4xNzc4OTYgKyB0aGlzLnAzNFtpXSAqIDAuMDQzOTcyNTsKCiAgICAgICAgdGhpcy5wMzRbaV0gPSB0aGlzLnAzM1tpXTsKICAgICAgICB0aGlzLnAzM1tpXSA9IHRoaXMucDMyW2ldOwogICAgICAgIHRoaXMucDMyW2ldID0gdGhpcy5wM1tpXTsKCiAgICAgICAgdGhpcy5wMFtpXSArPSAoZmFzdF90YW5oKGlucHV0W2ldW25dICogZHJpdmUgLSBrICogb3V0KSAtIGZhc3RfdGFuaCh0aGlzLnAwW2ldKSkgKiBjdXRvZmY7CiAgICAgICAgdGhpcy5wMVtpXSArPSAoZmFzdF90YW5oKHRoaXMucDBbaV0pIC0gZmFzdF90YW5oKHRoaXMucDFbaV0pKSAqIGN1dG9mZjsKICAgICAgICB0aGlzLnAyW2ldICs9IChmYXN0X3RhbmgodGhpcy5wMVtpXSkgLSBmYXN0X3RhbmgodGhpcy5wMltpXSkpICogY3V0b2ZmOwogICAgICAgIHRoaXMucDNbaV0gKz0gKGZhc3RfdGFuaCh0aGlzLnAyW2ldKSAtIGZhc3RfdGFuaCh0aGlzLnAzW2ldKSkgKiBjdXRvZmY7CgogICAgICAgIG91dHB1dFtpXVtuXSA9IG91dCAqIG1ha2V1cGdhaW47CiAgICAgIH0KICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KfQpyZWdpc3RlclByb2Nlc3NvcignbGFkZGVyLXByb2Nlc3NvcicsIExhZGRlclByb2Nlc3Nvcik7CgpjbGFzcyBEaXN0b3J0UHJvY2Vzc29yIGV4dGVuZHMgQXVkaW9Xb3JrbGV0UHJvY2Vzc29yIHsKICBzdGF0aWMgZ2V0IHBhcmFtZXRlckRlc2NyaXB0b3JzKCkgewogICAgcmV0dXJuIFsKICAgICAgeyBuYW1lOiAnZGlzdG9ydCcsIGRlZmF1bHRWYWx1ZTogMCB9LAogICAgICB7IG5hbWU6ICdwb3N0Z2FpbicsIGRlZmF1bHRWYWx1ZTogMSB9LAogICAgXTsKICB9CgogIGNvbnN0cnVjdG9yKCkgewogICAgc3VwZXIoKTsKICAgIHRoaXMuc3RhcnRlZCA9IGZhbHNlOwogIH0KCiAgcHJvY2VzcyhpbnB1dHMsIG91dHB1dHMsIHBhcmFtZXRlcnMpIHsKICAgIGNvbnN0IGlucHV0ID0gaW5wdXRzWzBdOwogICAgY29uc3Qgb3V0cHV0ID0gb3V0cHV0c1swXTsKCiAgICBjb25zdCBoYXNJbnB1dCA9ICEoaW5wdXRbMF0gPT09IHVuZGVmaW5lZCk7CiAgICBpZiAodGhpcy5zdGFydGVkICYmICFoYXNJbnB1dCkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICB0aGlzLnN0YXJ0ZWQgPSBoYXNJbnB1dDsKCiAgICBjb25zdCBzaGFwZSA9IE1hdGguZXhwbTEocGFyYW1ldGVycy5kaXN0b3J0WzBdKTsKICAgIGNvbnN0IHBvc3RnYWluID0gTWF0aC5tYXgoMC4wMDEsIE1hdGgubWluKDEsIHBhcmFtZXRlcnMucG9zdGdhaW5bMF0pKTsKCiAgICBmb3IgKGxldCBuID0gMDsgbiA8IGJsb2NrU2l6ZTsgbisrKSB7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW5wdXQubGVuZ3RoOyBpKyspIHsKICAgICAgICBvdXRwdXRbaV1bbl0gPSAoKCgxICsgc2hhcGUpICogaW5wdXRbaV1bbl0pIC8gKDEgKyBzaGFwZSAqIE1hdGguYWJzKGlucHV0W2ldW25dKSkpICogcG9zdGdhaW47CiAgICAgIH0KICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KfQpyZWdpc3RlclByb2Nlc3NvcignZGlzdG9ydC1wcm9jZXNzb3InLCBEaXN0b3J0UHJvY2Vzc29yKTsKCi8vIFNVUEVSU0FXCmZ1bmN0aW9uIGxlcnAoYSwgYiwgbikgewogIHJldHVybiBuICogKGIgLSBhKSArIGE7Cn0KCmZ1bmN0aW9uIGdldFVuaXNvbkRldHVuZSh1bmlzb24sIGRldHVuZSwgdm9pY2VJbmRleCkgewogIGlmICh1bmlzb24gPCAyKSB7CiAgICByZXR1cm4gMDsKICB9CiAgcmV0dXJuIGxlcnAoLWRldHVuZSAqIDAuNSwgZGV0dW5lICogMC41LCB2b2ljZUluZGV4IC8gKHVuaXNvbiAtIDEpKTsKfQpjbGFzcyBTdXBlclNhd09zY2lsbGF0b3JQcm9jZXNzb3IgZXh0ZW5kcyBBdWRpb1dvcmtsZXRQcm9jZXNzb3IgewogIGNvbnN0cnVjdG9yKCkgewogICAgc3VwZXIoKTsKICAgIHRoaXMucGhhc2UgPSBbXTsKICB9CiAgc3RhdGljIGdldCBwYXJhbWV0ZXJEZXNjcmlwdG9ycygpIHsKICAgIHJldHVybiBbCiAgICAgIHsKICAgICAgICBuYW1lOiAnYmVnaW4nLAogICAgICAgIGRlZmF1bHRWYWx1ZTogMCwKICAgICAgICBtYXg6IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSwKICAgICAgICBtaW46IDAsCiAgICAgIH0sCgogICAgICB7CiAgICAgICAgbmFtZTogJ2VuZCcsCiAgICAgICAgZGVmYXVsdFZhbHVlOiAwLAogICAgICAgIG1heDogTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZLAogICAgICAgIG1pbjogMCwKICAgICAgfSwKCiAgICAgIHsKICAgICAgICBuYW1lOiAnZnJlcXVlbmN5JywKICAgICAgICBkZWZhdWx0VmFsdWU6IDQ0MCwKICAgICAgICBtaW46IE51bWJlci5FUFNJTE9OLAogICAgICB9LAoKICAgICAgewogICAgICAgIG5hbWU6ICdwYW5zcHJlYWQnLAogICAgICAgIGRlZmF1bHRWYWx1ZTogMC40LAogICAgICAgIG1pbjogMCwKICAgICAgICBtYXg6IDEsCiAgICAgIH0sCiAgICAgIHsKICAgICAgICBuYW1lOiAnZnJlcXNwcmVhZCcsCiAgICAgICAgZGVmYXVsdFZhbHVlOiAwLjIsCiAgICAgICAgbWluOiAwLAogICAgICB9LAogICAgICB7CiAgICAgICAgbmFtZTogJ2RldHVuZScsCiAgICAgICAgZGVmYXVsdFZhbHVlOiAwLAogICAgICAgIG1pbjogMCwKICAgICAgfSwKCiAgICAgIHsKICAgICAgICBuYW1lOiAndm9pY2VzJywKICAgICAgICBkZWZhdWx0VmFsdWU6IDUsCiAgICAgICAgbWluOiAxLAogICAgICB9LAogICAgXTsKICB9CiAgcHJvY2VzcyhpbnB1dCwgb3V0cHV0cywgcGFyYW1zKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWYKICAgIGlmIChjdXJyZW50VGltZSA8PSBwYXJhbXMuYmVnaW5bMF0pIHsKICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWYKICAgIGlmIChjdXJyZW50VGltZSA+PSBwYXJhbXMuZW5kWzBdKSB7CiAgICAgIC8vIHRoaXMucG9ydC5wb3N0TWVzc2FnZSh7IHR5cGU6ICdvbmVuZGVkJyB9KTsKICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgbGV0IGZyZXF1ZW5jeSA9IHBhcmFtcy5mcmVxdWVuY3lbMF07CiAgICAvL2FwcGx5IGRldHVuZSBpbiBjZW50cwogICAgZnJlcXVlbmN5ID0gZnJlcXVlbmN5ICogTWF0aC5wb3coMiwgcGFyYW1zLmRldHVuZVswXSAvIDEyMDApOwoKICAgIGNvbnN0IG91dHB1dCA9IG91dHB1dHNbMF07CiAgICBjb25zdCB2b2ljZXMgPSBwYXJhbXMudm9pY2VzWzBdOwogICAgY29uc3QgZnJlcXNwcmVhZCA9IHBhcmFtcy5mcmVxc3ByZWFkWzBdOwogICAgY29uc3QgcGFuc3ByZWFkID0gcGFyYW1zLnBhbnNwcmVhZFswXSAqIDAuNSArIDAuNTsKICAgIGNvbnN0IGdhaW4xID0gTWF0aC5zcXJ0KDEgLSBwYW5zcHJlYWQpOwogICAgY29uc3QgZ2FpbjIgPSBNYXRoLnNxcnQocGFuc3ByZWFkKTsKCiAgICBmb3IgKGxldCBuID0gMDsgbiA8IHZvaWNlczsgbisrKSB7CiAgICAgIGNvbnN0IGlzT2RkID0gKG4gJiAxKSA9PSAxOwoKICAgICAgLy9hcHBsaWVzIHVuaXNvbiAic3ByZWFkIiBkZXR1bmUgaW4gc2VtaXRvbmVzCiAgICAgIGNvbnN0IGZyZXEgPSBmcmVxdWVuY3kgKiBNYXRoLnBvdygyLCBnZXRVbmlzb25EZXR1bmUodm9pY2VzLCBmcmVxc3ByZWFkLCBuKSAvIDEyKTsKICAgICAgbGV0IGdhaW5MID0gZ2FpbjE7CiAgICAgIGxldCBnYWluUiA9IGdhaW4yOwogICAgICAvLyBpbnZlcnQgcmlnaHQgYW5kIGxlZnQgZ2FpbgogICAgICBpZiAoaXNPZGQpIHsKICAgICAgICBnYWluTCA9IGdhaW4yOwogICAgICAgIGdhaW5SID0gZ2FpbjE7CiAgICAgIH0KICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmCiAgICAgIGNvbnN0IGR0ID0gZnJlcSAvIHNhbXBsZVJhdGU7CgogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG91dHB1dFswXS5sZW5ndGg7IGkrKykgewogICAgICAgIHRoaXMucGhhc2Vbbl0gPSB0aGlzLnBoYXNlW25dID8/IE1hdGgucmFuZG9tKCk7CiAgICAgICAgY29uc3QgdiA9IHdhdmVzaGFwZXMuc2F3YmxlcCh0aGlzLnBoYXNlW25dLCBkdCk7CgogICAgICAgIG91dHB1dFswXVtpXSA9IG91dHB1dFswXVtpXSArIHYgKiBnYWluTDsKICAgICAgICBvdXRwdXRbMV1baV0gPSBvdXRwdXRbMV1baV0gKyB2ICogZ2FpblI7CgogICAgICAgIHRoaXMucGhhc2Vbbl0gKz0gZHQ7CgogICAgICAgIGlmICh0aGlzLnBoYXNlW25dID4gMS4wKSB7CiAgICAgICAgICB0aGlzLnBoYXNlW25dID0gdGhpcy5waGFzZVtuXSAtIDE7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsKICB9Cn0KCnJlZ2lzdGVyUHJvY2Vzc29yKCdzdXBlcnNhdy1vc2NpbGxhdG9yJywgU3VwZXJTYXdPc2NpbGxhdG9yUHJvY2Vzc29yKTsK"; function Q(e) { const n = m().createGain(); return n.gain.value = e, n; } const Qe = (e, n, t, o) => o - t === 0 ? 0 : (n - e) / (o - t); function E(e, n, t, o) { const c = new AudioWorkletNode(e, n, o); return Object.entries(t).forEach(([g, s]) => { c.parameters.get(g).value = s; }), c; } const U = (e, n, t, o, c, g, s, a, I, i = "exponential") => { n = J(n), t = J(t), o = J(o), c = J(c); const r = i === "exponential" ? "exponentialRampToValueAtTime" : "linearRampToValueAtTime"; i === "exponential" && (g = g === 0 ? 1e-3 : g, s = s === 0 ? 1e-3 : s); const d = s - g, l = s, C = g + o * d, u = I - a, A = (h) => { let b; if (n > h) { let f = Qe(g, l, 0, n); b = h * f + (g > l ? g : 0); } else b = (h - n) * Qe(l, C, 0, t) + l; return i === "exponential" && (b = b || 1e-3), b; }; e.setValueAtTime(g, a), n > u ? e[r](A(u), I) : n + t > u ? (e[r](A(n), a + n), e[r](A(u), I)) : (e[r](A(n), a + n), e[r](A(n + t), a + n + t), e.setValueAtTime(C, I)), e[r](g, I + c); }; function Sn(e, n, t, o, c, g) { const s = { threshold: n ?? -3, ratio: t ?? 10, knee: o ?? 10, attack: c ?? 5e-3, release: g ?? 0.05 }; return new DynamicsCompressorNode(e, s); } const q = (e, n = "linear", t) => { const [s, a, I, i] = e; if (s == null && a == null && I == null && i == null) return t ?? [1e-3, 1e-3, 1, 0.01]; const r = I ?? (s != null && a == null || s == null && a == null ? 1 : 1e-3); return [Math.max(s ?? 0, 1e-3), Math.max(a ?? 0, 1e-3), Math.min(r, 1), Math.max(i ?? 0, 0.01)]; }; function Ce(e, n, t, o, c, g, s, a, I, i, r, d, l, C) { const u = "exponential", [A, h, b, f] = q([c, g, s, a], u, [5e-3, 0.14, 0, 0.1]); let Z, p; if (l === "ladder" ? (Z = E(e, "ladder-processor", { frequency: t, q: o, drive: C }), p = Z.parameters.get("frequency")) : (Z = e.createBiquadFilter(), Z.type = n, Z.Q.value = o, Z.frequency.value = t, p = Z.frequency), (c ?? g ?? s ?? a ?? I) !== void 0) { I = J(I, 1, !0), d = J(d, 0, !0); const W = Math.abs(I), S = W * d; let K = ne(2 ** -S * t, 0, 2e4), H = ne(2 ** (W - S) * t, 0, 2e4); return I < 0 && ([K, H] = [H, K]), U(p, A, h, b, f, K, H, i, r, u), Z; } return Z; } let Ee = (e) => e < 0.5 ? 1 : 1 - (e - 0.5) / 0.5; function Fn(e, n, t = 0) { const o = m(); if (!t) return e; let c = o.createGain(), g = o.createGain(); e.connect(c), n.connect(g), c.gain.value = Ee(t), g.gain.value = Ee(1 - t); let s = o.createGain(); return c.connect(s), g.connect(s), s; } let Rn = ["linear", "exponential"]; function Ge(e, n, t, o) { if (!(n.pattack ?? n.pdecay ?? n.psustain ?? n.prelease ?? n.penv)) return; const g = J(n.penv, 1, !0), s = Rn[n.pcurve ?? 0]; let [a, I, i, r] = q( [n.pattack, n.pdecay, n.psustain, n.prelease], s, [0.2, 1e-3, 1, 1e-3] ), d = n.panchor ?? i; const l = g * 100, C = 0 - l * d, u = l - l * d; U(e, a, I, i, r, C, u, t, o, s); } function me(e, n, t) { const { vibmod: o = 0.5, vib: c } = n; let g; if (c > 0) { g = m().createOscillator(), g.frequency.value = c; const s = m().createGain(); return s.gain.value = o * 100, g.connect(s), s.connect(e), g.start(t), g; } } function zn(e, n, t, o) { const c = e.createConstantSource(); c.start(t), c.stop(o), c.onended = () => { n(); }; } const Mn = (e, n = 1, t = "sine") => { const o = m(), c = o.createOscillator(); c.type = t, c.frequency.value = e, c.start(); const g = new GainNode(o, { gain: n }); return c.connect(g), { node: g, stop: (s) => c.stop(s) }; }, vn = (e, n, t, o = "sine") => { const g = e.value * n, s = g * t; return Mn(g, s, o); }; function $e(e, n, t) { const { fmh: o = 1, fmi: c, fmenv: g = "exp", fmattack: s, fmdecay: a, fmsustain: I, fmrelease: i, fmvelocity: r, fmwave: d = "sine", duration: l } = n; let C, u = () => { }; if (c) { const h = m().createGain(), b = vn(e, o, c, d); if (C = b.node, u = b.stop, ![s, a, I, i, r].find((f) => f !== void 0)) C.connect(e); else { const [f, Z, p, y] = q([s, a, I, i]), W = t + l; U( h.gain, f, Z, p, y, 0, 1, t, W, g === "exp" ? "exponential" : "linear" ), C.connect(h), h.connect(e); } } return { stop: u }; } const pe = {}, de = {}, ut = (e) => pe[e]; function Dn(e, n) { var t = n ? 1e3 : 1024; if (e < t) return e + " B"; var o = n ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], c = -1; do e /= t, ++c; while (e >= t); return e.toFixed(1) + " " + o[c]; } const Jn = async (e, n, t, o, c, g, s) => { let a = 0; c !== void 0 && t !== void 0 && v("[sampler] hap has note and freq. ignoring note", "warning"); let I = Kn({ freq: c, note: t }, 36); a = I - 36; const i = m(); let r, d = 0; if (Array.isArray(g)) d = je(n, g.length), r = g[d]; else { const A = (b) => ie(b) - I, h = Object.keys(g).filter((b) => !b.startsWith("_")).reduce( (b, f, Z) => !b || Math.abs(A(f)) < Math.abs(A(b)) ? f : b, null ); a = -A(h), d = je(n, g[h].length), r = g[h][d]; } s && (r = await s(r)); let l = await en(r, i, e, d); o < 0 && (l = kn(l)); const C = i.createBufferSource(); C.buffer = l; const u = 1 * Math.pow(2, a / 12); return C.playbackRate.value = u, C; }, en = (e, n, t, o = 0) => { const c = t ? `sound "${t}:${o}"` : "sample"; if (e = e.replace("#", "%23"), !de[e]) { v(`[sampler] load ${c}..`, "load-sample", { url: e }); const g = Date.now(); de[e] = fetch(e).then((s) => s.arrayBuffer()).then(async (s) => { const a = Date.now() - g, I = Dn(s.byteLength); v(`[sampler] load ${c}... done! loaded ${I} in ${a}ms`, "loaded-sample", { url: e }); const i = await n.decodeAudioData(s); return pe[e] = i, i; }); } return de[e]; }; function kn(e) { const n = m(), t = n.createBuffer(e.numberOfChannels, e.length, n.sampleRate); for (let o = 0; o < e.numberOfChannels; o++) t.copyToChannel(e.getChannelData(o).slice().reverse(), o, o); return t; } const At = (e) => pe[e]; function nn(e) { if (e.startsWith("bubo:")) { const [n, t] = e.split(":"); e = `github:Bubobubobubobubo/dough-${t}`; } return e; } function tn(e, n = "") { if (!e.startsWith("github:")) throw new Error('expected "github:" at the start of pseudoUrl'); let [t, o] = e.split("github:"); return o = o.endsWith("/") ? o.slice(0, -1) : o, o.split("/").length === 2 && (o += "/main"), `https://raw.githubusercontent.com/${o}/${n}`; } const Tn = (e, n, t = e._base || "") => Object.entries(e).forEach(([o, c]) => { if (typeof c == "string" && (c = [c]), typeof c != "object") throw new Error("wrong sample map format for " + o); t = c._base || t, t = nn(t), t.startsWith("github:") && (t = tn(t, "")); const g = (s) => t + s; Array.isArray(c) ? c = c.map(g) : c = Object.fromEntries( Object.entries(c).map(([s, a]) => [s, (typeof a == "string" ? [a] : a).map(g)]) ), n(o, c); }); let on = {}; function ht(e, n) { on[e] = n; } function Ln(e) { const n = Object.entries(on).find(([t]) => e.startsWith(t)); if (n) return n[1]; } const xn = async (e, n = e._base || "", t = {}) => { if (typeof e == "string") { const g = Ln(e); if (g) return g(e); if (e = nn(e), e.startsWith("github:") && (e = tn(e, "strudel.json")), e.startsWith("local:") && (e = "http://localhost:5432"), e.startsWith("shabda:")) { let [a, I] = e.split("shabda:"); e = `https://shabda.ndre.gr/${I}.json?strudel=1`; } if (e.startsWith("shabda/speech")) { let [a, I] = e.split("shabda/speech"); I = I.startsWith("/") ? I.substring(1) : I; let [i, r] = I.split(":"), d = "f", l = "en-GB"; i && ([l, d] = i.split("/")), e = `https://shabda.ndre.gr/speech/${r}.json?gender=${d}&language=${l}&strudel=1'`; } if (typeof fetch != "function") return; const s = e.split("/").slice(0, -1).join("/"); return typeof fetch > "u" ? void 0 : fetch(e).then((a) => a.json()).then((a) => xn(a, n || a._base || s, t)).catch((a) => { throw console.error(a), new Error(`error loading "${e}"`); }); } const { prebake: o, tag: c } = t; Tn( e, (g, s) => oe(g, (a, I, i) => On(a, I, i, s), { type: "sample", samples: s, baseUrl: n, prebake: o, tag: c }), n ); }, Ue = []; async function On(e, n, t, o, c) { let { s: g, freq: s, unit: a, nudge: I = 0, // TODO: is this in seconds? cut: i, loop: r, clip: d = void 0, // if set, samples will be cut off when the hap ends n: l = 0, note: C, speed: u = 1, // sample playback speed loopBegin: A = 0, begin: h = 0, loopEnd: b = 1, end: f = 1, duration: Z } = n; if (u === 0) return; r = g.startsWith("wt_") ? 1 : n.loop; const p = m(); let [y, W, S, K] = q([n.attack, n.decay, n.sustain, n.release]); const H = e + I, B = await Jn(g, l, C, u, s, o, c); let D = me(B.detune, n, e); if (p.currentTime > e) { v(`[sampler] still loading sound "${g}:${l}"`, "highlight"); return; } if (!B) { v(`[sampler] could not load "${g}:${l}"`, "error"); return; } B.playbackRate.value = Math.abs(u) * B.playbackRate.value, a === "c" && (B.playbackRate.value = B.playbackRate.value * B.buffer.duration * 1); const X = h * B.buffer.duration; r && (B.loop = !0, B.loopStart = A * B.buffer.duration - X, B.loopEnd = b * B.buffer.duration - X), B.start(H, X); const Y = p.createGain(), L = B.connect(Y); if (d == null && r == null && n.release == null) { const k = B.buffer.duration / B.playbackRate.value; Z = (f - h) * k; } let x = e + Z; U(L.gain, y, W, S, K, 0, 1, e, x, "linear"), Ge(B.detune, n, e, x); const N = p.createGain(); L.connect(N), B.onended = function() { B.disconnect(), D?.stop(), L.disconnect(), N.disconnect(), t(); }; let F = x + K + 0.01; B.stop(F); const O = { node: N, bufferSource: B, stop: (k, we) => { } }; if (i !== void 0) { const k = Ue[i]; k && (k.node.gain.setValueAtTime(1, H), k.node.gain.linearRampToValueAtTime(0, H + 0.01)), Ue[i] = O; } return O; } const Ze = Zn(); function oe(e, n, t = {}) { Ze.setKey(e, { onTrigger: n, data: t }); } function ue(e) { return Ze.get()[e]; } const gn = { s: "triangle", gain: 0.8, postgain: 1, density: ".03", ftype: "12db", fanchor: 0, resonance: 1, hresonance: 1, bandq: 1, channels: [1, 2], phaserdepth: 0.75, shapevol: 1, distortvol: 1, delay: 0, delayfeedback: 0.5, delaytime: 0.25, orbit: 1, i: 1, velocity: 1, fft: 8 }; let ye = new Map(Object.entries(gn)); function cn(e, n) { ye.set(e, n); } function V(e) { return ye.get(e); } function bt(e) { Object.keys(e).forEach((n) => { cn(n, e[n]); }); } function jn() { ye = new Map(Object.entries(gn)); } function Bt(e) { jn(), e === "1.0" && cn("fanchor", 0.5); } const ft = () => Ze.set({}); let ae; const Qn = () => (ae = new AudioContext(), ae), m = () => ae || Qn(); let Ae; function En() { return Ae || (Ae = m().audioWorklet.addModule(Yn)), Ae; } async function Un(e = {}) { const { disableWorklets: n = !1 } = e; if (!(typeof window > "u")) { if (await m().resume(), n) { v("[superdough]: AudioWorklets disabled with disableWorklets"); return; } try { await En(), v("[superdough] AudioWorklets loaded"); } catch (t) { console.warn("could not load AudioWorklet effects", t); } v("[superdough] ready"); } } let he; async function Gt(e) { return he || (he = new Promise((n) => { document.addEventListener("click", async function t() { document.removeEventListener("click", t), await Un(e), n(); }); })), he; } let T = {}, Ie, _; function qn() { const e = m(), n = e.destination.maxChannelCount; e.destination.channelCount = n, Ie = new ChannelMergerNode(e, { numberOfInputs: e.destination.channelCount }), _ = new GainNode(e), Ie.connect(_), _.connect(e.destination); } const Xe = (e, n = [0, 1]) => { const t = m(); Ie == null && qn(); const o = new StereoPannerNode(t); e.connect(o); const c = new ChannelSplitterNode(t, { numberOfOutputs: o.channelCount }); o.connect(c), n.forEach((g, s) => { c.connect(Ie, s % o.channelCount, ne(g, 0, t.destination.channelCount - 1)); }); }, mt = () => { _ != null && (_.gain.linearRampToValueAtTime(0, m().currentTime + 0.01), _ = null); }; function Pn(e, n, t, o) { if (t = ne(t, 0, 0.98), !T[e]) { const g = m().createFeedbackDelay(1, n, t); g.start?.(o), Xe(g, [0, 1]), T[e] = g; } return T[e].delayTime.value !== n && T[e].delayTime.setValueAtTime(n, o), T[e].feedback.value !== t && T[e].feedback.setValueAtTime(t, o), T[e]; } function _n(e, n, t = 1, o = 0.5, c = 1e3, g = 2e3) { const s = m(), a = s.createGain(); a.gain.value = g * 2, E(s, "lfo-processor", { frequency: t, depth: 1, skew: 0, phaseoffset: 0, time: e, end: n, shape: 1, dcoffset: -0.5 }).connect(a); const i = 2; let r = 0; const d = []; for (let l = 0; l < i; l++) { const C = s.createBiquadFilter(); C.type = "notch", C.gain.value = 1, C.frequency.value = c + r, C.Q.value = 2 - Math.min(Math.max(o * 2, 0), 1.9), a.connect(C.detune), r += 282, l > 0 && d[l - 1].connect(C), d.push(C); } return d[d.length - 1]; } function $n(e) { e = e ?? 0; const n = ["12db", "ladder", "24db"]; return typeof e == "number" ? n[Math.floor(_e(e, n.length))] : e; } let z = {}, se = (e, n) => e !== void 0 && e !== n; function et(e, n, t, o, c, g) { if (!z[e]) { const a = m().createReverb(n, t, o, c, g); Xe(a, [0, 1]), z[e] = a; } return (se(n, z[e].duration) || se(t, z[e].fade) || se(o, z[e].lp) || se(c, z[e].dim) || z[e].ir !== g) && z[e].generate(n, t, o, c, g), z[e]; } let M = {}, $ = {}; function nt(e, n = 1024) { if (!M[e]) { const t = m().createAnalyser(); t.fftSize = n, M[e] = t, $[e] = new Float32Array(M[e].frequencyBinCount); } return M[e].fftSize !== n && (M[e].fftSize = n, $[e] = new Float32Array(M[e].frequencyBinCount)), M[e]; } function pt(e = "time", n = 1) { const t = { time: () => M[n]?.getFloatTimeDomainData($[n]), frequency: () => M[n]?.getFloatFrequencyData($[n]) }[e]; if (!t) throw new Error(`getAnalyzerData: ${e} not supported. use one of ${Object.keys(t).join(", ")}`); return t(), $[n]; } function be(e, n, t) { const o = Q(t); return e.connect(o), o.connect(n), o; } function Zt() { T = {}, z = {}, M = {}, $ = {}; } const tt = async (e, n, t) => { const o = m(); if (typeof e != "object") throw new Error( `expected hap.value to be an object, but got "${e}". Hint: append .note() or .s() to the end`, "error" ); if (e.duration = t, n = typeof n == "string" && n.startsWith("=") ? Number(n.slice(1)) : o.currentTime + n, n < o.currentTime) { console.warn( `[superdough]: cannot schedule sounds in the past (target: ${n.toFixed(2)}, now: ${o.currentTime.toFixed(2)})` ); return; } let { s: c = V("s"), bank: g, source: s, gain: a = V("gain"), postgain: I = V("postgain"), density: i = V("density"), // filters fanchor: r = V("fanchor"), drive: d = 0.69, // low pass cutoff: l, lpenv: C, lpattack: u, lpdecay: A, lpsustain: h, lprelease: b, resonance: f = V("resonance"), // high pass hpenv: Z, hcutoff: p, hpattack: y, hpdecay: W, hpsustain: S, hprelease: K, hresonance: H = V("hresonance"), // band pass bpenv: B, bandf: D, bpattack: X, bpdecay: Y, bpsustain: L, bprelease: x, bandq: N = V("bandq"), channels: F = V("channels"), //phaser phaser: R, phaserdepth: O = V("phaserdepth"), phasersweep: k, phasercenter: we, // coarse: Ve, crush: We, shape: He, shapevol: rn = V("shapevol"), distort: Ne, distortvol: ln = V("distortvol"), pan: Ke, vowel: Ye, delay: Se = V("delay"), delayfeedback: Fe = V("delayfeedback"), delaytime: Re = V("delaytime"), orbit: ze = V("orbit"), room: Me, roomfade: Cn, roomlp: dn, roomdim: un, roomsize: An, ir: re, i: ve = V("i"), velocity: hn = V("velocity"), analyze: De, // analyser wet fft: bn = V("fft"), // fftSize 0 - 10 compressor: Je, compressorRatio: Bn, compressorKnee: fn, compressorAttack: Gn, compressorRelease: mn } = e; a = J(a, 1), F = (Array.isArray(F) ? F : [F]).map((G) => G - 1), a *= hn; let ke = []; const pn = () => { ke.forEach((G) => G?.disconnect()); }; g && c && (c = `${g}_${c}`); let ge; if (s) ge = s(n, e, t); else if (ue(c)) { const { onTrigger: G } = ue(c), j = await G(n, e, pn); j && (ge = j.node, j.stop(n + t)); } else throw new Error(`sound ${c} not found! Is it loaded?`); if (!ge) return; if (o.currentTime > n) { v("[webaudio] skip hap: still loading", o.currentTime - n); return; } const w = []; w.push(ge), w.push(Q(a)); const ce = $n(e.ftype); if (l !== void 0) { let G = () => Ce( o, "lowpass", l, f, u, A, h, b, C, n, n + t, r, ce, d ); w.push(G()), ce === "24db" && w.push(G()); } if (p !== void 0) { let G = () => Ce( o, "highpass", p, H, y, W, S, K, Z, n, n + t, r ); w.push(G()), ce === "24db" && w.push(G()); } if (D !== void 0) { let G = () => Ce( o, "bandpass", D, N, X, Y, L, x, B, n, n + t, r ); w.push(G()), ce === "24db" && w.push(G()); } if (Ye !== void 0) { const G = o.createVowelFilter(Ye); w.push(G); } if (Ve !== void 0 && w.push(E(o, "coarse-processor", { coarse: Ve })), We !== void 0 && w.push(E(o, "crush-processor", { crush: We })), He !== void 0 && w.push(E(o, "shape-processor", { shape: He, postgain: rn })), Ne !== void 0 && w.push(E(o, "distort-processor", { distort: Ne, postgain: ln })), Je !== void 0 && w.push( Sn(o, Je, Bn, fn, Gn, mn) ), Ke !== void 0) { const G = o.createStereoPanner(); G.pan.value = 2 * Ke - 1, w.push(G); } if (R !== void 0 && O > 0) { const G = _n(n, n + t, R, O, we, k); w.push(G); } const te = new GainNode(o, { gain: I }); w.push(te), Xe(te, F); let Te; if (Se > 0 && Re > 0 && Fe > 0) { const G = Pn(ze, Re, Fe, n); Te = be(te, G, Se); } let Le; if (Me > 0) { let G; if (re !== void 0) { let le, P = ue(re); Array.isArray(P) ? le = P.data.samples[ve % P.data.samples.length] : typeof P == "object" && (le = Object.values(P.data.samples).flat()[ve % Object.values(P.data.samples).length]), G = await en(le, o, re, 0); } const j = et(ze, An, Cn, dn, un, G); Le = be(te, j, Me); } let xe; if (De) { const G = nt(De, 2 ** (bn + 5)); xe = be(te, G, 1); } w.slice(1).reduce((G, j) => G.connect(j), w[0]), ke = w.concat([Te, Le, xe]); }, yt = (e, n, t, o) => tt(n, e - t, n.duration / o); let Be = {}; function ot(e, n) { const t = m(); if (Be[e]) return Be[e]; const o = 2 * t.sampleRate, c = t.createBuffer(1, o, t.sampleRate), g = c.getChannelData(0); let s = 0, a, I, i, r, d, l, C; a = I = i = r = d = l = C = 0; for (let u = 0; u < o; u++) if (e === "white") g[u] = Math.random() * 2 - 1; else if (e === "brown") { let A = Math.random() * 2 - 1; g[u] = (s + 0.02 * A) / 1.02, s = g[u]; } else if (e === "pink") { let A = Math.random() * 2 - 1; a = 0.99886 * a + A * 0.0555179, I = 0.99332 * I + A * 0.0750759, i = 0.969 * i + A * 0.153852, r = 0.8665 * r + A * 0.3104856, d = 0.55 * d + A * 0.5329522, l = -0.7616 * l - A * 0.016898, g[u] = a + I + i + r + d + l + C + A * 0.5362, g[u] *= 0.11, C = A * 0.115926; } else if (e === "crackle") { const A = n * 0.01; Math.random() < A ? g[u] = Math.random() * 2 - 1 : g[u] = 0; } return e !== "crackle" && (Be[e] = c), c; } function sn(e = "white", n, t = 0.02) { const c = m().createBufferSource(); return c.buffer = ot(e, t), c.loop = !0, c.start(n), { node: c, stop: (g) => c.stop(g) }; } function gt(e, n, t) { const o = sn("pink", t); return { node: Fn(e, o.node, n), stop: (g) => o?.stop(g) }; } const an = (e) => { let { note: n, freq: t } = e; return n = n || 36, typeof n == "string" && (n = ie(n)), !t && typeof n == "number" && (t = Pe(n)), Number(t); }, ct = ["triangle", "square", "sawtooth", "sine"], st = ["pink", "white", "brown", "crackle"]; function Xt() { [...ct].forEach((e) => { oe( e, (n, t, o) => { const [c, g, s, a] = q( [t.attack, t.decay, t.sustain, t.release], "linear", [1e-3, 0.05, 0.6, 0.01] ); let I = It(e, n, t), { node: i, stop: r, triggerRelease: d } = I; const l = Q(0.3), { duration: C } = t; i.onended = () => { i.disconnect(), l.disconnect(), o(); }; const u = Q(1); let A = i.connect(l).connect(u); const h = n + C; U(A.gain, c, g, s, a, 0, 1, n, h, "linear"); const b = h + a + 0.01; return d?.(b), r(b), { node: A, stop: (f) => { } }; }, { type: "synth", prebake: !0 } ); }), oe( "supersaw", (e, n, t) => { const o = m(); let { duration: c, n: g, unison: s = 5, spread: a = 0.6, detune: I } = n; I = I ?? g ?? 0.18; const i = an(n), [r, d, l, C] = q( [n.attack, n.decay, n.sustain, n.release], "linear", [1e-3, 0.05, 0.6, 0.01] ), u = e + c, A = u + C + 0.01, h = ne(s, 1, 100); let b = h > 1 ? ne(a, 0, 1) : 0, f = E( o, "supersaw-oscillator", { frequency: i, begin: e, end: A, freqspread: I, voices: h, panspread: b }, { outputChannelCount: [2] } ); const Z = 1 / Math.sqrt(h); Ge(f.parameters.get("detune"), n, e, u); const p = me(f.parameters.get("detune"), n, e), y = $e(f.parameters.get("frequency"), n, e); let W = Q(1); return W = f.connect(W), zn( o, () => { f.disconnect(), W.disconnect(), t(), y?.stop(), p?.stop(); }, e, A ), U(W.gain, r, d, l, C, 0, 0.3 * Z, e, u, "linear"), { node: W, stop: (S) => { } }; }, { prebake: !0, type: "synth" } ), [...st].forEach((e) => { oe( e, (n, t, o) => { const [c, g, s, a] = q( [t.attack, t.decay, t.sustain, t.release], "linear", [1e-3, 0.05, 0.6, 0.01] ); let I, { density: i } = t; I = sn(e, n, i); let { node: r, stop: d, triggerRelease: l } = I; const C = Q(0.3), { duration: u } = t; r.onended = () => { r.disconnect(), C.disconnect(), o(); }; const A = Q(1); let h = r.connect(C).connect(A); const b = n + u; U(h.gain, c, g, s, a, 0, 1, n, b, "linear"); const f = b + a + 0.01; return l?.(f), d(f), { node: h, stop: (Z) => { } }; }, { type: "synth", prebake: !0 } ); }); } function at(e, n) { const t = new Float32Array(e + 1), o = new Float32Array(e + 1), c = m(), g = c.createOscillator(), s = { sawtooth: (i) => [0, -1 / i], square: (i) => [0, i % 2 === 0 ? 0 : 1 / i], triangle: (i) => [i % 2 === 0 ? 0 : 1 / (i * i), 0] }; if (!s[n]) throw new Error(`unknown wave type ${n}`); t[0] = 0, o[0] = 0; let a = 1; for (; a <= e; ) { const [i, r] = s[n](a); t[a] = i, o[a] = r, a++; } const I = c.createPeriodicWave(t, o); return g.setPeriodicWave(I), g; } function It(e, n, t) { let { n: o, duration: c, noise: g = 0 } = t, s; !o || e === "sine" ? (s = m().createOscillator(), s.type = e || "triangle") : s = at(o, e), s.frequency.value = an(t), s.start(n); let a = me(s.detune, t, n); Ge(s.detune, t, n, n + c); const I = $e(s.frequency, t, n); let i; return g && (i = gt(s, g, n)), { node: i?.node || s, stop: (r) => { I.stop(r), a?.stop(r), i?.stop(r), s.stop(r); }, triggerRelease: (r) => { } }; } function it(e = 1, n = 0.05, t = 220, o = 0, c = 0, g = 0.1, s = 0, a = 1, I = 0, i = 0, r = 0, d = 0, l = 0, C = 0, u = 0, A = 0, h = 0, b = 1, f = 0, Z = 0) { let p = Math.PI * 2, y = m().sampleRate, W = (O) => O > 0 ? 1 : -1, S = I *= 500 * p / y / y, K = t *= (1 + n * 2 * Math.random() - n) * p / y, H = [], B = 0, D = 0, X = 0, Y = 1, L = 0, x = 0, N = 0, F, R; for (o = o * y + 9, f *= y, c *= y, g *= y, h *= y, i *= 500 * p / y ** 3, u *= p / y, r *= p / y, d *= y, l = l * y | 0, R = o + f + c + g + h | 0; X < R; H[X++] = N) ++x % (A * 100 | 0) || (N = s ? s > 1 ? s > 2 ? s > 3 ? Math.sin((B % p) ** 3) : Math.max(Math.min(Math.tan(B), 1), -1) : 1 - (2 * B / p % 2 + 2) % 2 : 1 - 4 * Math.abs(Math.round(B / p) - B / p) : Math.sin(B), N = (l ? 1 - Z + Z * Math.sin(p * X / l) : 1) * W(N) * Math.abs(N) ** a * // curve 0=square, 2=pointy e * 1 * // envelope (X < o ? X / o : X < o + f ? 1 - (X - o) / f * (1 - b) : X < o + f + c ? b : X < R - h ? (R - X - h) / g * // release falloff b : 0), N = h ? N / 2 + (h > X ? 0 : (X < R - h ? 1 : (R - X) / h) * // release delay H[X - h | 0] / 2) : N), F = (t += I += i) * // frequency Math.cos(u * D++), B += F - F * C * (1 - (Math.sin(X) + 1) * 1e9 % 2), Y && ++Y > d && (t += r, K += r, Y = 0), l && !(++L % l) && (t = K, I = S, Y ||= 1); return H; } const rt = (e, n) => { let { s: t, note: o = 36, freq: c, // zrand: g = 0, attack: s = 0, decay: a = 0, sustain: I = 0.8, release: i = 0.1, curve: r = 1, slide: d = 0, deltaSlide: l = 0, pitchJump: C = 0, pitchJumpTime: u = 0, lfo: A = 0, znoise: h = 0, zmod: b = 0