buffers can now be repitched (still with aliasing)

This commit is contained in:
Felix Roos
2025-06-08 14:43:23 +02:00
parent 356d4360ec
commit 55aef18851
3 changed files with 21 additions and 17 deletions
+3 -3
View File
@@ -10,10 +10,10 @@ class DoughProcessor extends AudioWorkletProcessor {
if (event.data.spawn) {
this.dough.scheduleSpawn(event.data.spawn);
} else if (event.data.sample) {
this.dough.loadSample(event.data.sample, event.data.channels);
this.dough.loadSample(event.data.sample, event.data.channels, event.data.sampleRate);
} else if (event.data.samples) {
event.data.samples.forEach(([name, channels]) => {
this.dough.loadSample(name, channels);
event.data.samples.forEach(([name, channels, sampleRate]) => {
this.dough.loadSample(name, channels, sampleRate);
});
} else {
console.log('unrecognized event type', event.data);
+14 -8
View File
@@ -385,14 +385,16 @@ export class Distort {
export class BufferPlayer {
static samples = new Map();
channels = [];
buffer; // { channels: Float32Array, sampleRate: number }
pos = 0;
sampleFreq = 261.626; // middle c
update(freq, channel = 0) {
if (this.pos >= this.channels[channel].length) {
if (this.pos >= this.buffer.channels[channel].length) {
return 0;
}
let s = this.channels[channel][this.pos];
this.pos++;
const speed = ((freq / this.sampleFreq) * this.buffer.sampleRate) / SAMPLE_RATE;
let s = this.buffer.channels[channel][Math.floor(this.pos)];
this.pos = this.pos + speed;
return s;
}
}
@@ -576,7 +578,8 @@ export class DoughVoice {
this._sound = new SourceClass();
} else if (BufferPlayer.samples.has(this.s)) {
this._sample = new BufferPlayer();
this._sample.channels = BufferPlayer.samples.get(this.s);
const buffer = BufferPlayer.samples.get(this.s);
this._sample.buffer = buffer;
} else {
console.warn('sound not found', this.s);
}
@@ -738,7 +741,10 @@ export class DoughVoice {
const env = this._adsr.update(t, gate, this.attack, this.decay, this.sustain, this.release);
s = s * env;
s = s * this.postgain * 0.2;
s = s * this.postgain;
if (!this._sample) {
s = s * 0.2; // turn down waveforms
}
if (this.pan === 0.5) {
this.l = this.r = s; // mono
@@ -770,8 +776,8 @@ export class Dough {
this._delayL = new Delay();
this._delayR = new Delay();
}
loadSample(name, channels) {
BufferPlayer.samples.set(name, channels);
loadSample(name, channels, sampleRate) {
BufferPlayer.samples.set(name, { channels, sampleRate });
}
scheduleSpawn(value) {
if (value._begin === undefined) {
+4 -6
View File
@@ -118,7 +118,7 @@ let samples = {
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/7.wav',
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/numbers/8.wav',
],
piano: ['https://raw.githubusercontent.com/felixroos/dough-samples/refs/heads/main/piano/A3v8.mp3'],
piano: ['https://raw.githubusercontent.com/felixroos/dough-samples/refs/heads/main/piano/C3v8.mp3'],
flute: ['https://raw.githubusercontent.com/felixroos/samples/refs/heads/main/flute/c4.mp3'],
bd: [
'https://raw.githubusercontent.com/geikha/tidal-drum-machines/15eac73c5e878550f91d864a4863e014799403f1/machines/RolandTR909/rolandtr909-bd/Bassdrum-01.wav',
@@ -126,7 +126,7 @@ let samples = {
};
// for some reason, only piano and flute work.. is it because mp3??
async function loadSampleChannels(url) {
async function loadSampleChannels(key, url) {
const buffer = await fetch(url)
.then((res) => res.arrayBuffer())
.then((buf) => getAudioContext().decodeAudioData(buf));
@@ -134,7 +134,7 @@ async function loadSampleChannels(url) {
for (let i = 0; i < buffer.numberOfChannels; i++) {
channels.push(buffer.getChannelData(i));
}
return channels;
return [key, channels, buffer.sampleRate];
}
let loaded = false;
@@ -147,9 +147,7 @@ export async function doughsample() {
const sampleMap = await Promise.all(
Object.entries(samples).map(async ([key, url]) => {
url = url[0];
const channels = await loadSampleChannels(url);
// console.log(key, 'url', url, channels);
return [key, channels];
return loadSampleChannels(key, url);
}),
);
console.log('sampleMap', sampleMap);