This commit is contained in:
Aria 2025-09-25 01:10:41 -07:00
parent f8f42565ae
commit 8b2c35b7a3
2 changed files with 14 additions and 16 deletions

View file

@ -1,5 +1,5 @@
import { getAudioContext, registerSound } from './index.mjs'; import { getAudioContext, registerSound } from './index.mjs';
import { clamp, getSoundIndex, valueToMidi } from './util.mjs'; import { getSoundIndex, valueToMidi } from './util.mjs';
import { import {
destroyAudioWorkletNode, destroyAudioWorkletNode,
getADSRValues, getADSRValues,
@ -86,28 +86,27 @@ function humanFileSize(bytes, si) {
return bytes.toFixed(1) + ' ' + units[u]; return bytes.toFixed(1) + ' ' + units[u];
} }
export function getTableInfo(hapValue, bank) { export function getTableInfo(hapValue, tableUrls) {
const { wt, n = 0 } = hapValue; const { s, n = 0 } = hapValue;
let midi = valueToMidi(hapValue, 36); let midi = valueToMidi(hapValue, 36);
let transpose = midi - 36; // C3 is middle C; let transpose = midi - 36; // C3 is middle C;
const index = getSoundIndex(n, bank.length); const index = getSoundIndex(n, tableUrls.length);
const tableUrl = bank[index]; const tableUrl = tableUrls[index];
const label = `${wt}:${index}`; const label = `${s}:${index}`;
return { transpose, tableUrl, index, midi, label }; return { transpose, tableUrl, index, midi, label };
} }
const loadBuffer = (url, ac, wt, n = 0) => { const loadBuffer = (url, ac, label) => {
const label = wt ? `table "${wt}:${n}"` : 'table';
url = url.replace('#', '%23'); url = url.replace('#', '%23');
if (!loadCache[url]) { if (!loadCache[url]) {
logger(`[wavetable] load ${label}..`, 'load-table', { url }); logger(`[wavetable] load table ${label}..`, 'load-table', { url });
const timestamp = Date.now(); const timestamp = Date.now();
loadCache[url] = fetch(url) loadCache[url] = fetch(url)
.then((res) => res.arrayBuffer()) .then((res) => res.arrayBuffer())
.then(async (res) => { .then(async (res) => {
const took = Date.now() - timestamp; const took = Date.now() - timestamp;
const size = humanFileSize(res.byteLength); const size = humanFileSize(res.byteLength);
logger(`[wavetable] load ${label}... done! loaded ${size} in ${took}ms`, 'loaded-table', { url }); logger(`[wavetable] load table ${label}... done! loaded ${size} in ${took}ms`, 'loaded-table', { url });
const decoded = await ac.decodeAudioData(res); const decoded = await ac.decodeAudioData(res);
return decoded; return decoded;
}); });
@ -151,7 +150,7 @@ const _processTables = (json, baseUrl, frameLen) => {
}; };
/** /**
* Loads a collection of wavetables to use with `wt` * Loads a collection of wavetables to use with `s`
* *
* @name tables * @name tables
*/ */
@ -167,7 +166,6 @@ export const tables = async (url, frameLen, json) => {
// not a browser // not a browser
return; return;
} }
const base = url.split('/').slice(0, -1).join('/');
if (typeof fetch === 'undefined') { if (typeof fetch === 'undefined') {
// skip fetch when in node / testing // skip fetch when in node / testing
return; return;

View file

@ -474,10 +474,10 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
gainR = gain1; gainR = gain1;
} }
// Individual voice detuning // Individual voice detuning
const voiceFreq = applySemitoneDetuneToFrequency(freq, getUnisonDetune(voices, freqspread, n)); const freqVoice = applySemitoneDetuneToFrequency(freq, getUnisonDetune(voices, freqspread, n));
// We must wrap this here because it is passed into sawblep below which // We must wrap this here because it is passed into sawblep below which
// has domain [0, 1] // has domain [0, 1]
const dt = mod(voiceFreq / sampleRate, 1); const dt = mod(freqVoice / sampleRate, 1);
this.phase[n] = this.phase[n] ?? Math.random(); this.phase[n] = this.phase[n] ?? Math.random();
const v = waveshapes.sawblep(this.phase[n], dt); const v = waveshapes.sawblep(this.phase[n], dt);
@ -1203,14 +1203,14 @@ class WavetableOscillatorProcessor extends AudioWorkletProcessor {
gainL = gain2; gainL = gain2;
gainR = gain1; gainR = gain1;
} }
let fVoice = applySemitoneDetuneToFrequency(f, getUnisonDetune(voices, detune, n)); // voice detune const fVoice = applySemitoneDetuneToFrequency(f, getUnisonDetune(voices, detune, n)); // voice detune
const dPhase = fVoice / sampleRate; const dPhase = fVoice / sampleRate;
const level = this._chooseMip(dPhase); const level = this._chooseMip(dPhase);
const bank = this.tables[level]; const bank = this.tables[level];
// warp phase then sample // warp phase then sample
this.phase[n] = this.phase[n] ?? Math.random() * phaseRand; this.phase[n] = this.phase[n] ?? Math.random() * phaseRand;
let ph = this._warpPhase(this.phase[n], warpAmount, warpMode); const ph = this._warpPhase(this.phase[n], warpAmount, warpMode);
const s0 = this._sampleFrame(bank[fIdx], ph); const s0 = this._sampleFrame(bank[fIdx], ph);
const s1 = this._sampleFrame(bank[Math.min(this.numFrames - 1, fIdx + 1)], ph); const s1 = this._sampleFrame(bank[Math.min(this.numFrames - 1, fIdx + 1)], ph);
let s = s0 + (s1 - s0) * frac; let s = s0 + (s1 - s0) * frac;