Merge remote-tracking branch 'upstream/main' into sampler

This commit is contained in:
Felix Roos 2023-09-17 07:31:21 +02:00
commit d0258756e5
19 changed files with 1008 additions and 159 deletions

View file

@ -1,4 +1,5 @@
import { getAudioContext } from './superdough.mjs';
import { clamp } from './util.mjs';
export function gainNode(value) {
const node = getAudioContext().createGain();
@ -66,10 +67,48 @@ export const getADSR = (attack, decay, sustain, release, velocity, begin, end) =
return gainNode;
};
export const getFilter = (type, frequency, Q) => {
const filter = getAudioContext().createBiquadFilter();
filter.type = type;
filter.frequency.value = frequency;
filter.Q.value = Q;
return filter;
export const getParamADSR = (param, attack, decay, sustain, release, min, max, begin, end) => {
const range = max - min;
const peak = min + range;
const sustainLevel = min + sustain * range;
param.setValueAtTime(min, begin);
param.linearRampToValueAtTime(peak, begin + attack);
param.linearRampToValueAtTime(sustainLevel, begin + attack + decay);
param.setValueAtTime(sustainLevel, end);
param.linearRampToValueAtTime(min, end + Math.max(release, 0.1));
};
export function createFilter(
context,
type,
frequency,
Q,
attack,
decay,
sustain,
release,
fenv,
start,
end,
fanchor = 0.5,
) {
const filter = context.createBiquadFilter();
filter.type = type;
filter.Q.value = Q;
filter.frequency.value = frequency;
// Apply ADSR to filter frequency
if (!isNaN(fenv) && fenv !== 0) {
const offset = fenv * fanchor;
const min = clamp(2 ** -offset * frequency, 0, 20000);
const max = clamp(2 ** (fenv - offset) * frequency, 0, 20000);
// console.log('min', min, 'max', max);
getParamADSR(filter.frequency, attack, decay, sustain, release, min, max, start, end);
return filter;
}
return filter;
}

View file

@ -1,6 +1,6 @@
{
"name": "superdough",
"version": "0.9.6",
"version": "0.9.7",
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
"main": "index.mjs",
"type": "module",

View file

@ -9,7 +9,7 @@ import './reverb.mjs';
import './vowel.mjs';
import { clamp } from './util.mjs';
import workletsUrl from './worklets.mjs?url';
import { getFilter, gainNode } from './helpers.mjs';
import { createFilter, gainNode } from './helpers.mjs';
import { map } from 'nanostores';
import { logger } from './logger.mjs';
@ -177,14 +177,32 @@ export const superdough = async (value, deadline, hapDuration) => {
bank,
source,
gain = 0.8,
// filters
ftype = '12db',
fanchor = 0.5,
// low pass
cutoff,
lpenv,
lpattack = 0.01,
lpdecay = 0.01,
lpsustain = 1,
lprelease = 0.01,
resonance = 1,
// high pass
hpenv,
hcutoff,
hpattack = 0.01,
hpdecay = 0.01,
hpsustain = 1,
hprelease = 0.01,
hresonance = 1,
// band pass
bpenv,
bandf,
bpattack = 0.01,
bpdecay = 0.01,
bpsustain = 1,
bprelease = 0.01,
bandq = 1,
//
coarse,
@ -239,11 +257,76 @@ export const superdough = async (value, deadline, hapDuration) => {
// gain stage
chain.push(gainNode(gain));
// filters
cutoff !== undefined && chain.push(getFilter('lowpass', cutoff, resonance));
hcutoff !== undefined && chain.push(getFilter('highpass', hcutoff, hresonance));
bandf !== undefined && chain.push(getFilter('bandpass', bandf, bandq));
vowel !== undefined && chain.push(ac.createVowelFilter(vowel));
if (cutoff !== undefined) {
let lp = () =>
createFilter(
ac,
'lowpass',
cutoff,
resonance,
lpattack,
lpdecay,
lpsustain,
lprelease,
lpenv,
t,
t + hapDuration,
fanchor,
);
chain.push(lp());
if (ftype === '24db') {
chain.push(lp());
}
}
if (hcutoff !== undefined) {
let hp = () =>
createFilter(
ac,
'highpass',
hcutoff,
hresonance,
hpattack,
hpdecay,
hpsustain,
hprelease,
hpenv,
t,
t + hapDuration,
fanchor,
);
chain.push(hp());
if (ftype === '24db') {
chain.push(hp());
}
}
if (bandf !== undefined) {
let bp = () =>
createFilter(
ac,
'bandpass',
bandf,
bandq,
bpattack,
bpdecay,
bpsustain,
bprelease,
bpenv,
t,
t + hapDuration,
fanchor,
);
chain.push(bp());
if (ftype === '24db') {
chain.push(bp());
}
}
if (vowel !== undefined) {
const vowelFilter = ac.createVowelFilter(vowel);
chain.push(vowelFilter);
}
// effects
coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse }));