mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-22 13:13:10 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a37b4825a |
+23
-13
@@ -551,6 +551,28 @@ export const { tremoloshape } = registerControl('tremoloshape', 'tremshape');
|
|||||||
|
|
||||||
export const { drive } = registerControl('drive');
|
export const { drive } = registerControl('drive');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* waveshaping distortion with selectable algorithms
|
||||||
|
*
|
||||||
|
* @name shape
|
||||||
|
* @param {number | Pattern} amount
|
||||||
|
* @example
|
||||||
|
* $: s("909bd").beat("0,4,8,11,14",16).shape("<2 4 1>").shapetype("<0 1 2>*2")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const { shape } = registerControl(['shape', 'shapevol', 'shapetype']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filter overdrive for supported filter types
|
||||||
|
*
|
||||||
|
* @name shapetype
|
||||||
|
* @param {number | Pattern} type
|
||||||
|
* @example
|
||||||
|
* $: s("909bd").beat("0,4,8,11,14",16).shape("2").shapetype("<0 1 2>")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const { shapeType } = registerControl('shapetype');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create byte beats with custom expressions
|
* Create byte beats with custom expressions
|
||||||
*
|
*
|
||||||
@@ -1510,19 +1532,7 @@ export const { roomsize, size, sz, rsize } = registerControl('roomsize', 'size',
|
|||||||
// ['sclap'],
|
// ['sclap'],
|
||||||
// ['sclaves'],
|
// ['sclaves'],
|
||||||
// ['scrash'],
|
// ['scrash'],
|
||||||
/**
|
|
||||||
* (Deprecated) Wave shaping distortion. WARNING: can suddenly get unpredictably loud.
|
|
||||||
* Please use distort instead, which has a more predictable response curve
|
|
||||||
* second option in optional array syntax (ex: ".9:.5") applies a postgain to the output
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @name shape
|
|
||||||
* @param {number | Pattern} distortion between 0 and 1
|
|
||||||
* @example
|
|
||||||
* s("bd sd [~ bd] sd,hh*8").shape("<0 .2 .4 .6 .8>")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { shape } = registerControl(['shape', 'shapevol']);
|
|
||||||
/**
|
/**
|
||||||
* Wave shaping distortion. CAUTION: it can get loud.
|
* Wave shaping distortion. CAUTION: it can get loud.
|
||||||
* Second option in optional array syntax (ex: ".9:.5") applies a postgain to the output.
|
* Second option in optional array syntax (ex: ".9:.5") applies a postgain to the output.
|
||||||
|
|||||||
@@ -277,3 +277,18 @@ export function applyFM(param, value, begin) {
|
|||||||
}
|
}
|
||||||
return { stop };
|
return { stop };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const saturationAlgos = [
|
||||||
|
(x, k) => ((1 + k) * x) / (1 + k * Math.abs(x)), //S Curve sourced from: https://www.nickwritesablog.com/sound-design-in-web-audio-neurofunk-bass-part-1/
|
||||||
|
(x, k) => Math.tanh(x * k),
|
||||||
|
];
|
||||||
|
|
||||||
|
export function makeSaturationCurve(amount, n_samples, algo = 0) {
|
||||||
|
const k = typeof amount === 'number' ? amount : 50;
|
||||||
|
const curve = new Float32Array(n_samples);
|
||||||
|
for (let i = 0; i < n_samples; i++) {
|
||||||
|
const x = (i * 2) / n_samples - 1;
|
||||||
|
curve[i] = saturationAlgos[algo % saturationAlgos.length]?.(x, amount);
|
||||||
|
}
|
||||||
|
return curve;
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import './reverb.mjs';
|
|||||||
import './vowel.mjs';
|
import './vowel.mjs';
|
||||||
import { clamp, nanFallback, _mod, cycleToSeconds, secondsToCycle } from './util.mjs';
|
import { clamp, nanFallback, _mod, cycleToSeconds, secondsToCycle } from './util.mjs';
|
||||||
import workletsUrl from './worklets.mjs?audioworklet';
|
import workletsUrl from './worklets.mjs?audioworklet';
|
||||||
import { createFilter, gainNode, getCompressor, getWorklet } from './helpers.mjs';
|
import { createFilter, gainNode, getCompressor, getWorklet, makeSaturationCurve } from './helpers.mjs';
|
||||||
import { map } from 'nanostores';
|
import { map } from 'nanostores';
|
||||||
import { logger } from './logger.mjs';
|
import { logger } from './logger.mjs';
|
||||||
import { loadBuffer } from './sampler.mjs';
|
import { loadBuffer } from './sampler.mjs';
|
||||||
@@ -147,6 +147,7 @@ let defaultDefaultValues = {
|
|||||||
phaserdepth: 0.75,
|
phaserdepth: 0.75,
|
||||||
shapevol: 1,
|
shapevol: 1,
|
||||||
distortvol: 1,
|
distortvol: 1,
|
||||||
|
saturatevol: 1,
|
||||||
delay: 0,
|
delay: 0,
|
||||||
byteBeatExpression: '0',
|
byteBeatExpression: '0',
|
||||||
delayfeedback: 0.5,
|
delayfeedback: 0.5,
|
||||||
@@ -573,6 +574,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
crush,
|
crush,
|
||||||
shape,
|
shape,
|
||||||
shapevol = getDefaultValue('shapevol'),
|
shapevol = getDefaultValue('shapevol'),
|
||||||
|
shapetype,
|
||||||
distort,
|
distort,
|
||||||
distortvol = getDefaultValue('distortvol'),
|
distortvol = getDefaultValue('distortvol'),
|
||||||
pan,
|
pan,
|
||||||
@@ -676,6 +678,14 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
// gain stage
|
// gain stage
|
||||||
chain.push(gainNode(gain));
|
chain.push(gainNode(gain));
|
||||||
|
|
||||||
|
if (shape != null) {
|
||||||
|
const shaper = new WaveShaperNode(ac);
|
||||||
|
shaper.curve = makeSaturationCurve(shape, ac.sampleRate, shapetype);
|
||||||
|
const shapeGain = new GainNode(ac, { gain: shapevol });
|
||||||
|
chain.push(shaper);
|
||||||
|
chain.push(shapeGain);
|
||||||
|
}
|
||||||
|
|
||||||
//filter
|
//filter
|
||||||
const ftype = getFilterType(value.ftype);
|
const ftype = getFilterType(value.ftype);
|
||||||
if (cutoff !== undefined) {
|
if (cutoff !== undefined) {
|
||||||
@@ -741,7 +751,6 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
// effects
|
// effects
|
||||||
coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse }));
|
coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse }));
|
||||||
crush !== undefined && chain.push(getWorklet(ac, 'crush-processor', { crush }));
|
crush !== undefined && chain.push(getWorklet(ac, 'crush-processor', { crush }));
|
||||||
shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape, postgain: shapevol }));
|
|
||||||
distort !== undefined && chain.push(getWorklet(ac, 'distort-processor', { distort, postgain: distortvol }));
|
distort !== undefined && chain.push(getWorklet(ac, 'distort-processor', { distort, postgain: distortvol }));
|
||||||
|
|
||||||
if (tremolosync != null) {
|
if (tremolosync != null) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
getVibratoOscillator,
|
getVibratoOscillator,
|
||||||
webAudioTimeout,
|
webAudioTimeout,
|
||||||
getWorklet,
|
getWorklet,
|
||||||
|
makeSaturationCurve,
|
||||||
} from './helpers.mjs';
|
} from './helpers.mjs';
|
||||||
import { getNoiseMix, getNoiseOscillator } from './noise.mjs';
|
import { getNoiseMix, getNoiseOscillator } from './noise.mjs';
|
||||||
|
|
||||||
@@ -42,17 +43,6 @@ const waveformAliases = [
|
|||||||
];
|
];
|
||||||
const noises = ['pink', 'white', 'brown', 'crackle'];
|
const noises = ['pink', 'white', 'brown', 'crackle'];
|
||||||
|
|
||||||
function makeSaturationCurve(amount, n_samples) {
|
|
||||||
const k = typeof amount === 'number' ? amount : 50;
|
|
||||||
const curve = new Float32Array(n_samples);
|
|
||||||
|
|
||||||
for (let i = 0; i < n_samples; i++) {
|
|
||||||
const x = (i * 2) / n_samples - 1;
|
|
||||||
curve[i] = Math.tanh(x * k);
|
|
||||||
}
|
|
||||||
return curve;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function registerSynthSounds() {
|
export function registerSynthSounds() {
|
||||||
[...waveforms].forEach((s) => {
|
[...waveforms].forEach((s) => {
|
||||||
registerSound(
|
registerSound(
|
||||||
@@ -124,7 +114,7 @@ export function registerSynthSounds() {
|
|||||||
|
|
||||||
const sat = new WaveShaperNode(ctx);
|
const sat = new WaveShaperNode(ctx);
|
||||||
// tri to sine diode shaper emulation
|
// tri to sine diode shaper emulation
|
||||||
sat.curve = makeSaturationCurve(2, ctx.sampleRate);
|
sat.curve = makeSaturationCurve(2, ctx.sampleRate, 1);
|
||||||
|
|
||||||
const mix = gainNode(mixGain);
|
const mix = gainNode(mixGain);
|
||||||
|
|
||||||
|
|||||||
@@ -8612,54 +8612,51 @@ exports[`runs examples > example "setcpm" example index 0 1`] = `
|
|||||||
|
|
||||||
exports[`runs examples > example "shape" example index 0 1`] = `
|
exports[`runs examples > example "shape" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | s:hh shape:0 ]",
|
"[ 0/1 → 1/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 0/1 → 1/4 | s:bd shape:0 ]",
|
"[ 1/4 → 5/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 1/8 → 1/4 | s:hh shape:0 ]",
|
"[ 1/2 → 9/16 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 1/4 → 3/8 | s:hh shape:0 ]",
|
"[ 11/16 → 3/4 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 1/4 → 1/2 | s:sd shape:0 ]",
|
"[ 7/8 → 15/16 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 3/8 → 1/2 | s:hh shape:0 ]",
|
"[ 1/1 → 17/16 | s:909bd shape:4 shapetype:2 ]",
|
||||||
"[ 1/2 → 5/8 | s:hh shape:0 ]",
|
"[ 5/4 → 21/16 | s:909bd shape:4 shapetype:2 ]",
|
||||||
"[ 5/8 → 3/4 | s:bd shape:0 ]",
|
"[ 3/2 → 25/16 | s:909bd shape:4 shapetype:0 ]",
|
||||||
"[ 5/8 → 3/4 | s:hh shape:0 ]",
|
"[ 27/16 → 7/4 | s:909bd shape:4 shapetype:0 ]",
|
||||||
"[ 3/4 → 7/8 | s:hh shape:0 ]",
|
"[ 15/8 → 31/16 | s:909bd shape:4 shapetype:0 ]",
|
||||||
"[ 3/4 → 1/1 | s:sd shape:0 ]",
|
"[ 2/1 → 33/16 | s:909bd shape:1 shapetype:1 ]",
|
||||||
"[ 7/8 → 1/1 | s:hh shape:0 ]",
|
"[ 9/4 → 37/16 | s:909bd shape:1 shapetype:1 ]",
|
||||||
"[ 1/1 → 9/8 | s:hh shape:0.2 ]",
|
"[ 5/2 → 41/16 | s:909bd shape:1 shapetype:2 ]",
|
||||||
"[ 1/1 → 5/4 | s:bd shape:0.2 ]",
|
"[ 43/16 → 11/4 | s:909bd shape:1 shapetype:2 ]",
|
||||||
"[ 9/8 → 5/4 | s:hh shape:0.2 ]",
|
"[ 23/8 → 47/16 | s:909bd shape:1 shapetype:2 ]",
|
||||||
"[ 5/4 → 11/8 | s:hh shape:0.2 ]",
|
"[ 3/1 → 49/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 5/4 → 3/2 | s:sd shape:0.2 ]",
|
"[ 13/4 → 53/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 11/8 → 3/2 | s:hh shape:0.2 ]",
|
"[ 7/2 → 57/16 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 3/2 → 13/8 | s:hh shape:0.2 ]",
|
"[ 59/16 → 15/4 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 13/8 → 7/4 | s:bd shape:0.2 ]",
|
"[ 31/8 → 63/16 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 13/8 → 7/4 | s:hh shape:0.2 ]",
|
]
|
||||||
"[ 7/4 → 15/8 | s:hh shape:0.2 ]",
|
`;
|
||||||
"[ 7/4 → 2/1 | s:sd shape:0.2 ]",
|
|
||||||
"[ 15/8 → 2/1 | s:hh shape:0.2 ]",
|
exports[`runs examples > example "shapetype" example index 0 1`] = `
|
||||||
"[ 2/1 → 17/8 | s:hh shape:0.4 ]",
|
[
|
||||||
"[ 2/1 → 9/4 | s:bd shape:0.4 ]",
|
"[ 0/1 → 1/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 17/8 → 9/4 | s:hh shape:0.4 ]",
|
"[ 1/4 → 5/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 9/4 → 19/8 | s:hh shape:0.4 ]",
|
"[ 1/2 → 9/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 9/4 → 5/2 | s:sd shape:0.4 ]",
|
"[ 11/16 → 3/4 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 19/8 → 5/2 | s:hh shape:0.4 ]",
|
"[ 7/8 → 15/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 5/2 → 21/8 | s:hh shape:0.4 ]",
|
"[ 1/1 → 17/16 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 21/8 → 11/4 | s:bd shape:0.4 ]",
|
"[ 5/4 → 21/16 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 21/8 → 11/4 | s:hh shape:0.4 ]",
|
"[ 3/2 → 25/16 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 11/4 → 23/8 | s:hh shape:0.4 ]",
|
"[ 27/16 → 7/4 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 11/4 → 3/1 | s:sd shape:0.4 ]",
|
"[ 15/8 → 31/16 | s:909bd shape:2 shapetype:1 ]",
|
||||||
"[ 23/8 → 3/1 | s:hh shape:0.4 ]",
|
"[ 2/1 → 33/16 | s:909bd shape:2 shapetype:2 ]",
|
||||||
"[ 3/1 → 25/8 | s:hh shape:0.6 ]",
|
"[ 9/4 → 37/16 | s:909bd shape:2 shapetype:2 ]",
|
||||||
"[ 3/1 → 13/4 | s:bd shape:0.6 ]",
|
"[ 5/2 → 41/16 | s:909bd shape:2 shapetype:2 ]",
|
||||||
"[ 25/8 → 13/4 | s:hh shape:0.6 ]",
|
"[ 43/16 → 11/4 | s:909bd shape:2 shapetype:2 ]",
|
||||||
"[ 13/4 → 27/8 | s:hh shape:0.6 ]",
|
"[ 23/8 → 47/16 | s:909bd shape:2 shapetype:2 ]",
|
||||||
"[ 13/4 → 7/2 | s:sd shape:0.6 ]",
|
"[ 3/1 → 49/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 27/8 → 7/2 | s:hh shape:0.6 ]",
|
"[ 13/4 → 53/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 7/2 → 29/8 | s:hh shape:0.6 ]",
|
"[ 7/2 → 57/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 29/8 → 15/4 | s:bd shape:0.6 ]",
|
"[ 59/16 → 15/4 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 29/8 → 15/4 | s:hh shape:0.6 ]",
|
"[ 31/8 → 63/16 | s:909bd shape:2 shapetype:0 ]",
|
||||||
"[ 15/4 → 31/8 | s:hh shape:0.6 ]",
|
|
||||||
"[ 15/4 → 4/1 | s:sd shape:0.6 ]",
|
|
||||||
"[ 31/8 → 4/1 | s:hh shape:0.6 ]",
|
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user