Skip to content
This repository was archived by the owner on Jun 19, 2025. It is now read-only.

Commit 0f2aa95

Browse files
committed
half working samples
1 parent ac7ee37 commit 0f2aa95

File tree

4 files changed

+182
-12
lines changed

4 files changed

+182
-12
lines changed

packages/supradough/dough-worklet.mjs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,19 @@ class DoughProcessor extends AudioWorkletProcessor {
66
constructor() {
77
super();
88
this.dough = new Dough(sampleRate, currentTime);
9-
this.port.onmessage = (event) => this.dough.scheduleSpawn(event.data);
9+
this.port.onmessage = (event) => {
10+
if (event.data.spawn) {
11+
this.dough.scheduleSpawn(event.data.spawn);
12+
} else if (event.data.sample) {
13+
this.dough.loadSample(event.data.sample, event.data.channels);
14+
} else if (event.data.samples) {
15+
event.data.samples.forEach(([name, channels]) => {
16+
this.dough.loadSample(name, channels);
17+
});
18+
} else {
19+
console.log('unrecognized event type', event.data);
20+
}
21+
};
1022
}
1123
process(inputs, outputs, params) {
1224
if (this.disconnected) {

packages/supradough/dough.mjs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,19 @@ export class Distort {
383383
}
384384
// distortion could be expressed as a function, because it's stateless
385385

386+
export class BufferPlayer {
387+
channels = [];
388+
pos = 0;
389+
update(freq, channel = 0) {
390+
if (this.pos >= this.channels[channel].length) {
391+
return 0;
392+
}
393+
let s = this.channels[channel][this.pos];
394+
this.pos++;
395+
return s;
396+
}
397+
}
398+
386399
export function _rangex(sig, min, max) {
387400
let logmin = Math.log(min);
388401
let range = Math.log(max) - logmin;
@@ -403,7 +416,7 @@ export const getADSRValues = (params, curve = 'linear', defaultValues) => {
403416
return [Math.max(a ?? 0, envmin), Math.max(d ?? 0, envmin), Math.min(sustain, envmax), Math.max(r ?? 0, releaseMin)];
404417
};
405418

406-
let oscillators = {
419+
let shapes = {
407420
sine: SineOsc,
408421
saw: SawOsc,
409422
zaw: ZawOsc,
@@ -553,11 +566,20 @@ export class DoughVoice {
553566
this._holdEnd = this._begin + this._duration; // needed for gate
554567
this._end = this._holdEnd + this.release + 0.01; // needed for despawn
555568

569+
this.s ??= 'triangle';
556570
if (this.s === 'saw' || this.s === 'sawtooth') {
557571
this.s = 'zaw'; // polyblepped saw when fm is applied
558572
}
559-
const SourceClass = oscillators[this.s] ?? TriOsc;
560-
this._sound = new SourceClass();
573+
if (shapes[this.s]) {
574+
const SourceClass = shapes[this.s];
575+
this._sound = new SourceClass();
576+
} else if (value.samples.has(this.s)) {
577+
this._sample = new BufferPlayer();
578+
this._sample.channels = value.samples.get(this.s);
579+
this._sample.pos = 0;
580+
} else {
581+
console.warn('sound not found', this.s);
582+
}
561583

562584
if (this.penv) {
563585
this._penv = new ADSR();
@@ -642,7 +664,7 @@ export class DoughVoice {
642664
return 1 - Math.log(c) * this.eighthOverLogHalf;
643665
}
644666
update(t) {
645-
if (!this._sound) {
667+
if (!this._sound && !this._sample) {
646668
return 0;
647669
}
648670
let s = 0;
@@ -666,10 +688,12 @@ export class DoughVoice {
666688
}
667689

668690
// sound source
669-
if (this.s === 'pulse') {
691+
if (this._sound && this.s === 'pulse') {
670692
s = this._sound.update(freq, this.pw ?? 0.5);
671-
} else {
693+
} else if (this._sound) {
672694
s = this._sound.update(freq);
695+
} else if (this._sample) {
696+
s = this._sample.update(freq, 0); // tbd: stereo samples...
673697
}
674698
s = s * this.gain * this.velocity;
675699

@@ -738,6 +762,7 @@ export class Dough {
738762
delaysend = [0, 0];
739763
delaytime = getDefaultValue('delaytime');
740764
delayfeedback = getDefaultValue('delayfeedback');
765+
samples = new Map();
741766
t = 0;
742767
// sampleRate: number, currentTime: number (seconds)
743768
constructor(sampleRate = 48000, currentTime = 0) {
@@ -747,6 +772,9 @@ export class Dough {
747772
this._delayL = new Delay();
748773
this._delayR = new Delay();
749774
}
775+
loadSample(name, channels) {
776+
this.samples.set(name, channels);
777+
}
750778
scheduleSpawn(value) {
751779
if (value._begin === undefined) {
752780
throw new Error('[dough]: scheduleSpawn expected _begin to be set');
@@ -760,6 +788,7 @@ export class Dough {
760788
}
761789
spawn(value) {
762790
value.id = this.vid++;
791+
value.samples = this.samples;
763792
const voice = new DoughVoice(value);
764793
this.voices.push(voice);
765794
// console.log('spawn', voice.id, 'voices:', this.voices.length);

packages/webaudio/index.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ This program is free software: you can redistribute it and/or modify it under th
77
export * from './webaudio.mjs';
88
export * from './scope.mjs';
99
export * from './spectrum.mjs';
10+
export * from './supradough.mjs';
1011
export * from 'superdough';

packages/webaudio/supradough.mjs

Lines changed: 133 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,138 @@ Pattern.prototype.supradough = function () {
2020
return this.onTrigger((_, hap, __, cps, begin) => {
2121
hap.value._begin = begin;
2222
hap.value._duration = hap.duration / cps;
23-
24-
if (!doughWorklet) {
25-
initDoughWorklet();
26-
}
27-
doughWorklet.port.postMessage(hap.value);
23+
!doughWorklet && initDoughWorklet();
24+
doughWorklet.port.postMessage({ spawn: hap.value });
2825
}, 1);
2926
};
27+
28+
async function loadSampleChannels(url) {
29+
const buffer = await fetch(url)
30+
.then((res) => res.arrayBuffer())
31+
.then((buf) => getAudioContext().decodeAudioData(buf));
32+
// console.log('buffer', buffer, buffer.numberOfChannels);
33+
let channels = [];
34+
for (let i = 0; i < buffer.numberOfChannels; i++) {
35+
channels.push(buffer.getChannelData(i));
36+
}
37+
return channels;
38+
}
39+
40+
let samples = {
41+
casio: [
42+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/casio/high.wav',
43+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/casio/low.wav',
44+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/casio/noise.wav',
45+
],
46+
crow: [
47+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/crow/000_crow.wav',
48+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/crow/001_crow2.wav',
49+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/crow/002_crow3.wav',
50+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/crow/003_crow4.wav',
51+
],
52+
insect: [
53+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/insect/000_everglades_conehead.wav',
54+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/insect/001_robust_shieldback.wav',
55+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/insect/002_seashore_meadow_katydid.wav',
56+
],
57+
wind: [
58+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/000_wind1.wav',
59+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/001_wind10.wav',
60+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/002_wind2.wav',
61+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/003_wind3.wav',
62+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/004_wind4.wav',
63+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/005_wind5.wav',
64+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/006_wind6.wav',
65+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/007_wind7.wav',
66+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/008_wind8.wav',
67+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/wind/009_wind9.wav',
68+
],
69+
jazz: [
70+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/jazz/000_BD.wav',
71+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/jazz/001_CB.wav',
72+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/jazz/002_FX.wav',
73+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/jazz/003_HH.wav',
74+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/jazz/004_OH.wav',
75+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/jazz/005_P1.wav',
76+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/jazz/006_P2.wav',
77+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/jazz/007_SN.wav',
78+
],
79+
metal: [
80+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/000_0.wav',
81+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/001_1.wav',
82+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/002_2.wav',
83+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/003_3.wav',
84+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/004_4.wav',
85+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/005_5.wav',
86+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/006_6.wav',
87+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/007_7.wav',
88+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/008_8.wav',
89+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/metal/009_9.wav',
90+
],
91+
east: [
92+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/000_nipon_wood_block.wav',
93+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/001_ohkawa_mute.wav',
94+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/002_ohkawa_open.wav',
95+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/003_shime_hi.wav',
96+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/004_shime_hi_2.wav',
97+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/005_shime_mute.wav',
98+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/006_taiko_1.wav',
99+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/007_taiko_2.wav',
100+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/east/008_taiko_3.wav',
101+
],
102+
space: [
103+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/000_0.wav',
104+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/001_1.wav',
105+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/002_11.wav',
106+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/003_12.wav',
107+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/004_13.wav',
108+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/005_14.wav',
109+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/006_15.wav',
110+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/007_16.wav',
111+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/008_17.wav',
112+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/009_18.wav',
113+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/010_2.wav',
114+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/011_3.wav',
115+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/012_4.wav',
116+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/013_5.wav',
117+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/014_6.wav',
118+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/015_7.wav',
119+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/016_8.wav',
120+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/space/017_9.wav',
121+
],
122+
numbers: [
123+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/0.wav',
124+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/1.wav',
125+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/2.wav',
126+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/3.wav',
127+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/4.wav',
128+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/5.wav',
129+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/6.wav',
130+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/7.wav',
131+
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/8.wav',
132+
],
133+
piano: ['https://raw.githubusercontent.com/felixroos/dough-samples/refs/heads/main/piano/A3v8.mp3'],
134+
flute: ['https://raw.githubusercontent.com/felixroos/samples/refs/heads/main/flute/c4.mp3'],
135+
bd: [
136+
'https://raw.githubusercontent.com/geikha/tidal-drum-machines/15eac73c5e878550f91d864a4863e014799403f1/machines/RolandTR909/rolandtr909-bd/Bassdrum-01.wav',
137+
],
138+
};
139+
// for some reason, only piano and flute work.. is it because mp3??
140+
141+
let loaded = false;
142+
export async function doughsample() {
143+
!doughWorklet && initDoughWorklet();
144+
if (loaded) {
145+
return;
146+
}
147+
loaded = true;
148+
const sampleMap = await Promise.all(
149+
Object.entries(samples).map(async ([key, url]) => {
150+
url = url[0];
151+
console.log(key, 'url', url);
152+
return [key, await loadSampleChannels(url)];
153+
}),
154+
);
155+
console.log('sampleMap', sampleMap);
156+
doughWorklet.port.postMessage({ samples: sampleMap });
157+
}

0 commit comments

Comments
 (0)