Skip to content
This repository was archived by the owner on Jun 19, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
483843b
begin supradough
felixroos Jun 1, 2025
5336569
proper lpf mapping + remove redundant worklet params,
felixroos Jun 1, 2025
5129fa6
fix click
daslyfe Jun 3, 2025
ff4b7ca
fix volume
daslyfe Jun 4, 2025
930dabe
dough as a singleton worklet with voice allocation
felixroos Jun 5, 2025
2cbd35f
refactor: make webaudio glue as minimal as possible
felixroos Jun 5, 2025
f0e6c54
handle invalid spawns + remove logs
felixroos Jun 5, 2025
ccec7e7
poc: render pattern audio with node script
felixroos Jun 5, 2025
87598e1
coarse
felixroos Jun 6, 2025
0cc18a6
crush (might be wrong)
felixroos Jun 6, 2025
623bf93
panning
felixroos Jun 6, 2025
9ed690c
pulse osc + velocity
felixroos Jun 6, 2025
794bf86
distort
felixroos Jun 6, 2025
6cf0b6f
hpf + bpf
felixroos Jun 6, 2025
e4cd5dc
rough filter envelope implementation
felixroos Jun 6, 2025
998a010
better filter envelopes
felixroos Jun 6, 2025
ccc90d5
ignore dough-export to fix checks
felixroos Jun 6, 2025
43c05cb
move supradough to separate package
felixroos Jun 6, 2025
49f38ae
remove log
felixroos Jun 6, 2025
1dac696
feedback delay (still hard coded feedback / time values)
felixroos Jun 7, 2025
d743570
set delay time and feedback from voice
felixroos Jun 7, 2025
e54449f
white brown pink noise + crackle alias for dust
felixroos Jun 7, 2025
77463a1
add square alias for pulse
felixroos Jun 7, 2025
b000f22
fm
felixroos Jun 7, 2025
2f2bf5b
fix: note2midi for notes without octave
felixroos Jun 7, 2025
5988e3d
fix: hot reloading for dough.mjs (see comment)
felixroos Jun 7, 2025
ab052ce
fix: polyblepped sawtooth + fm = death
felixroos Jun 7, 2025
ac7ee37
pitch envelope
felixroos Jun 7, 2025
0f2aa95
half working samples
felixroos Jun 8, 2025
356d436
fix: scheduling + sample playback
felixroos Jun 8, 2025
55aef18
buffers can now be repitched (still with aliasing)
felixroos Jun 8, 2025
ec9109d
exponential lerp
daslyfe Jun 8, 2025
1167fdb
Merge branch 'supradough' of https://github.com/tidalcycles/strudel i…
daslyfe Jun 8, 2025
181e51e
adjustable envelope curves
daslyfe Jun 8, 2025
73ef43d
move things around in init
felixroos Jun 8, 2025
1081fc6
refactor: stereo sample support + channelwise fx
felixroos Jun 9, 2025
d1b6b6b
fix: hpf
felixroos Jun 9, 2025
3ac0fdf
rudimentary sample map loading (doughsamples)
felixroos Jun 9, 2025
aeaed50
gaincurve
daslyfe Jun 9, 2025
3d30007
supersaw
daslyfe Jun 9, 2025
e825473
apply speed to synths and samples + add normalize flag (for fit)
felixroos Jun 9, 2025
c9f494d
fix: node export
felixroos Jun 9, 2025
e99adff
vibrato
felixroos Jun 9, 2025
3963b80
fix: calling doughsamples multiple times
felixroos Jun 9, 2025
7e8206d
pitched delay
daslyfe Jun 10, 2025
43504d1
add chorus
daslyfe Jun 10, 2025
bbd7ed0
lazy sample loading
felixroos Jun 12, 2025
5cbd38a
improve filter performance making it accept hz directly
felixroos Jun 12, 2025
3caf08e
up latency
felixroos Jun 12, 2025
14193ab
improve export: add stereo + measure performance + add bigger pattern…
felixroos Jun 12, 2025
30f7127
Merge remote-tracking branch 'origin/main' into supradough
felixroos Jun 12, 2025
8363ba5
format
felixroos Jun 12, 2025
239987a
snapshot
felixroos Jun 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default [
'**/hydra.mjs',
'**/jsdoc-synonyms.js',
'packages/hs2js/src/hs2js.mjs',
'packages/supradough/dough-export.mjs',
'**/samples',
],
},
Expand Down
8 changes: 7 additions & 1 deletion packages/superdough/superdough.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,17 @@ export function getAudioContextCurrentTime() {
return getAudioContext().currentTime;
}

let externalWorklets = [];
export function registerWorklet(url) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've added this to be able to register worklets from the outside without depending on them from superdough

externalWorklets.push(url);
}

let workletsLoading;
function loadWorklets() {
if (!workletsLoading) {
const audioCtx = getAudioContext();
workletsLoading = audioCtx.audioWorklet.addModule(workletsUrl);
const allWorkletURLs = externalWorklets.concat([workletsUrl]);
workletsLoading = Promise.all(allWorkletURLs.map((workletURL) => audioCtx.audioWorklet.addModule(workletURL)));
}

return workletsLoading;
Expand Down
1 change: 1 addition & 0 deletions packages/supradough/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pattern.wav
3 changes: 3 additions & 0 deletions packages/supradough/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# supradough

platform agnostic synth and sampler intended for live coding. a reimplementation of superdough.
61 changes: 61 additions & 0 deletions packages/supradough/dough-export.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// this is a poc of how a pattern can be rendered as a wav file using node
// run via: node dough-export.mjs
import fs from 'node:fs';
import WavEncoder from 'wav-encoder';
import { evalScope } from '@strudel/core';
import { miniAllStrings } from '@strudel/mini';
import { Dough } from './dough.mjs';

await evalScope(
import('@strudel/core'),
import('@strudel/mini'),
import('@strudel/tonal'),
// import('@strudel/tonal'),
);

miniAllStrings(); // allows using single quotes for mini notation / skip transpilation

let sampleRate = 48000,
cps = 0.5;

let pat = note('[c e g b]*3')
.add(note(7))
.lpf(sine.rangex(200, 4000).slow(2))
.lpq(0.3)
.s('<pulse saw tri>*2')
.att(0.01)
.rel(0.2)
.clip(2)
.delay(0.5)
.jux(rev)
.sometimes(add(note(12)))
.gain(0.25)
.slow(1 / cps);

let cycles = 4;
let seconds = cycles + 1; // 1s release tail
const haps = pat.queryArc(0, cycles);

const dough = new Dough(sampleRate);

console.log('spawn voices...');
haps.forEach((hap) => {
hap.value._begin = Number(hap.whole.begin);
hap.value._duration = hap.duration / cps;
dough.scheduleSpawn(hap.value);
});
console.log(`render ${seconds}s long buffer...`);
const buffer = new Float32Array(seconds * sampleRate);
while (dough.t <= buffer.length) {
buffer[dough.t] = dough.update();
}
console.log('done!');

const patternAudio = {
sampleRate,
channelData: [buffer],
};

WavEncoder.encode(patternAudio).then((buffer) => {
fs.writeFileSync('pattern.wav', new Float32Array(buffer));
});
39 changes: 39 additions & 0 deletions packages/supradough/dough-worklet.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Dough } from './dough.mjs';

const clamp = (num, min, max) => Math.min(Math.max(num, min), max);

class DoughProcessor extends AudioWorkletProcessor {
constructor() {
super();
this.dough = new Dough(sampleRate, currentTime);
this.port.onmessage = (event) => {
if (event.data.spawn) {
this.dough.scheduleSpawn(event.data.spawn);
} else if (event.data.sample) {
this.dough.loadSample(event.data.sample, event.data.channels, event.data.sampleRate);
} else if (event.data.samples) {
event.data.samples.forEach(([name, channels, sampleRate]) => {
this.dough.loadSample(name, channels, sampleRate);
});
} else {
console.log('unrecognized event type', event.data);
}
};
}
process(inputs, outputs, params) {
if (this.disconnected) {
return false;
}
const output = outputs[0];
for (let i = 0; i < output[0].length; i++) {
this.dough.update();
for (let c = 0; c < output.length; c++) {
//prevent speaker blowout via clipping if threshold exceeds
output[c][i] = clamp(this.dough.channels[c], -1, 1);
}
}
return true; // keep the audio processing going
}
}

registerProcessor('dough-processor', DoughProcessor);
Loading
Loading