Seemingly working version of supersaw FM and light cleanup
This commit is contained in:
parent
ed5bf3b3fc
commit
2e8a8b50df
3 changed files with 30 additions and 24 deletions
|
|
@ -83,4 +83,14 @@ export default [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Properties provided by AudioWorkletGlobalScope
|
||||||
|
files: ['packages/superdough/worklets.mjs'],
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
currentTime: 'readonly',
|
||||||
|
sampleRate: 'readonly',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -201,10 +201,7 @@ export function registerSynthSounds() {
|
||||||
const gainAdjustment = 1 / Math.sqrt(voices);
|
const gainAdjustment = 1 / Math.sqrt(voices);
|
||||||
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
|
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
|
||||||
const vibratoOscillator = getVibratoOscillator(o.parameters.get('detune'), value, begin);
|
const vibratoOscillator = getVibratoOscillator(o.parameters.get('detune'), value, begin);
|
||||||
// const fm = applyFM(o.parameters.get('frequency'), value, begin);
|
const fm = applyFM(o.parameters.get('frequency'), value, begin);
|
||||||
// https://codeberg.org/uzu/strudel/issues/1428
|
|
||||||
// if you think about re-enabling this, please test with fm > 1 first
|
|
||||||
// it's like 10x gain, so it's really dangerous
|
|
||||||
let envGain = gainNode(1);
|
let envGain = gainNode(1);
|
||||||
envGain = o.connect(envGain);
|
envGain = o.connect(envGain);
|
||||||
|
|
||||||
|
|
@ -216,7 +213,7 @@ export function registerSynthSounds() {
|
||||||
destroyAudioWorkletNode(o);
|
destroyAudioWorkletNode(o);
|
||||||
envGain.disconnect();
|
envGain.disconnect();
|
||||||
onended();
|
onended();
|
||||||
// fm?.stop();
|
fm?.stop();
|
||||||
vibratoOscillator?.stop();
|
vibratoOscillator?.stop();
|
||||||
},
|
},
|
||||||
begin,
|
begin,
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,27 @@ import FFT from './fft.js';
|
||||||
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
||||||
const _mod = (n, m) => ((n % m) + m) % m;
|
const _mod = (n, m) => ((n % m) + m) % m;
|
||||||
|
|
||||||
|
// Restrict phase to the range [0, maxPhase) via wrapping
|
||||||
|
function wrapPhase(phase, maxPhase = 1) {
|
||||||
|
if (phase >= maxPhase) {
|
||||||
|
phase -= maxPhase;
|
||||||
|
} else if (phase < 0) {
|
||||||
|
phase += maxPhase;
|
||||||
|
}
|
||||||
|
return phase;
|
||||||
|
}
|
||||||
const blockSize = 128;
|
const blockSize = 128;
|
||||||
// adjust waveshape to remove frequencies above nyquist to prevent aliasing
|
// Smooth waveshape near discontinuities to remove frequencies above nyquist and prevent aliasing
|
||||||
// referenced from https://www.kvraudio.com/forum/viewtopic.php?t=375517
|
// referenced from https://www.kvraudio.com/forum/viewtopic.php?t=375517
|
||||||
function polyBlep(phase, dt) {
|
function polyBlep(phase, dt) {
|
||||||
// 0 <= phase < 1
|
// Start of cycle
|
||||||
if (phase < dt) {
|
if (phase < dt) {
|
||||||
phase /= dt;
|
phase /= dt;
|
||||||
// 2 * (phase - phase^2/2 - 0.5)
|
// 2 * (phase - phase^2/2 - 0.5)
|
||||||
return phase + phase - phase * phase - 1;
|
return phase + phase - phase * phase - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -1 < phase < 0
|
// End of cycle
|
||||||
else if (phase > 1 - dt) {
|
else if (phase > 1 - dt) {
|
||||||
phase = (phase - 1) / dt;
|
phase = (phase - 1) / dt;
|
||||||
// 2 * (phase^2/2 + phase + 0.5)
|
// 2 * (phase^2/2 + phase + 0.5)
|
||||||
|
|
@ -115,7 +124,6 @@ class LFOProcessor extends AudioWorkletProcessor {
|
||||||
|
|
||||||
process(inputs, outputs, parameters) {
|
process(inputs, outputs, parameters) {
|
||||||
const begin = parameters['begin'][0];
|
const begin = parameters['begin'][0];
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
if (currentTime >= parameters.end[0]) {
|
if (currentTime >= parameters.end[0]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +151,6 @@ class LFOProcessor extends AudioWorkletProcessor {
|
||||||
if (this.phase == null) {
|
if (this.phase == null) {
|
||||||
this.phase = _mod(time * frequency + phaseoffset, 1);
|
this.phase = _mod(time * frequency + phaseoffset, 1);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const dt = frequency / sampleRate;
|
const dt = frequency / sampleRate;
|
||||||
for (let n = 0; n < blockSize; n++) {
|
for (let n = 0; n < blockSize; n++) {
|
||||||
for (let i = 0; i < output.length; i++) {
|
for (let i = 0; i < output.length; i++) {
|
||||||
|
|
@ -305,7 +312,6 @@ class LadderProcessor extends AudioWorkletProcessor {
|
||||||
const drive = clamp(Math.exp(parameters.drive[0]), 0.1, 2000);
|
const drive = clamp(Math.exp(parameters.drive[0]), 0.1, 2000);
|
||||||
|
|
||||||
let cutoff = parameters.frequency[0];
|
let cutoff = parameters.frequency[0];
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
cutoff = (cutoff * 2 * _PI) / sampleRate;
|
cutoff = (cutoff * 2 * _PI) / sampleRate;
|
||||||
cutoff = cutoff > 1 ? 1 : cutoff;
|
cutoff = cutoff > 1 ? 1 : cutoff;
|
||||||
|
|
||||||
|
|
@ -438,18 +444,14 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
process(input, outputs, params) {
|
process(input, outputs, params) {
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
if (currentTime <= params.begin[0]) {
|
if (currentTime <= params.begin[0]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
if (currentTime >= params.end[0]) {
|
if (currentTime >= params.end[0]) {
|
||||||
// this.port.postMessage({ type: 'onended' });
|
// this.port.postMessage({ type: 'onended' });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let frequency = params.frequency[0];
|
const frequency = applySemitoneDetuneToFrequency(params.frequency[0], params.detune[0] / 100);
|
||||||
//apply detune in cents
|
|
||||||
frequency = frequency * Math.pow(2, params.detune[0] / 1200);
|
|
||||||
|
|
||||||
const output = outputs[0];
|
const output = outputs[0];
|
||||||
const voices = params.voices[0];
|
const voices = params.voices[0];
|
||||||
|
|
@ -470,8 +472,9 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
|
||||||
gainL = gain2;
|
gainL = gain2;
|
||||||
gainR = gain1;
|
gainR = gain1;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-undef
|
// We must wrap this here because it is passed into sawblep below which
|
||||||
const dt = freq / sampleRate;
|
// has domain [0, 1]
|
||||||
|
const dt = wrapPhase(freq / sampleRate);
|
||||||
|
|
||||||
for (let i = 0; i < output[0].length; i++) {
|
for (let i = 0; i < output[0].length; i++) {
|
||||||
this.phase[n] = this.phase[n] ?? Math.random();
|
this.phase[n] = this.phase[n] ?? Math.random();
|
||||||
|
|
@ -480,11 +483,7 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
|
||||||
output[0][i] = output[0][i] + v * gainL;
|
output[0][i] = output[0][i] + v * gainL;
|
||||||
output[1][i] = output[1][i] + v * gainR;
|
output[1][i] = output[1][i] + v * gainR;
|
||||||
|
|
||||||
this.phase[n] += dt;
|
this.phase[n] = wrapPhase(this.phase[n] + dt);
|
||||||
|
|
||||||
if (this.phase[n] > 1.0) {
|
|
||||||
this.phase[n] = this.phase[n] - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -493,7 +492,7 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
|
||||||
|
|
||||||
registerProcessor('supersaw-oscillator', SuperSawOscillatorProcessor);
|
registerProcessor('supersaw-oscillator', SuperSawOscillatorProcessor);
|
||||||
|
|
||||||
// Phase Vocoder sourced from // sourced from https://github.com/olvb/phaze/tree/master?tab=readme-ov-file
|
// Phase Vocoder sourced from https://github.com/olvb/phaze/tree/master?tab=readme-ov-file
|
||||||
const BUFFERED_BLOCK_SIZE = 2048;
|
const BUFFERED_BLOCK_SIZE = 2048;
|
||||||
|
|
||||||
function genHannWindow(length) {
|
function genHannWindow(length) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue