mirror of
https://github.com/eliasstepanik/strudel.git
synced 2026-01-11 13:48:40 +00:00
pwm
This commit is contained in:
parent
530339ed8f
commit
c7ee90922f
@ -133,6 +133,66 @@ export function registerSynthSounds() {
|
|||||||
{ prebake: true, type: 'synth' },
|
{ prebake: true, type: 'synth' },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
registerSound(
|
||||||
|
'pwm',
|
||||||
|
(begin, value, onended) => {
|
||||||
|
const ac = getAudioContext();
|
||||||
|
let { duration, n } = value;
|
||||||
|
const frequency = getFrequencyFromValue(value);
|
||||||
|
|
||||||
|
const [attack, decay, sustain, release] = getADSRValues(
|
||||||
|
[value.attack, value.decay, value.sustain, value.release],
|
||||||
|
'linear',
|
||||||
|
[0.001, 0.05, 0.6, 0.01],
|
||||||
|
);
|
||||||
|
|
||||||
|
const holdend = begin + duration;
|
||||||
|
const end = holdend + release + 0.01;
|
||||||
|
|
||||||
|
let o = getWorklet(
|
||||||
|
ac,
|
||||||
|
'pwm-oscillator',
|
||||||
|
{
|
||||||
|
frequency,
|
||||||
|
begin,
|
||||||
|
end,
|
||||||
|
pulsewidth: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
outputChannelCount: [2],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
|
||||||
|
// const vibratoOscillator = getVibratoOscillator(o.parameters.get('detune'), value, begin);
|
||||||
|
const fm = applyFM(o.parameters.get('frequency'), value, begin);
|
||||||
|
let envGain = gainNode(1);
|
||||||
|
envGain = o.connect(envGain);
|
||||||
|
|
||||||
|
webAudioTimeout(
|
||||||
|
ac,
|
||||||
|
() => {
|
||||||
|
o.disconnect();
|
||||||
|
envGain.disconnect();
|
||||||
|
onended();
|
||||||
|
fm?.stop();
|
||||||
|
// vibratoOscillator?.stop();
|
||||||
|
},
|
||||||
|
begin,
|
||||||
|
end,
|
||||||
|
);
|
||||||
|
|
||||||
|
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 0.3, begin, holdend, 'linear');
|
||||||
|
|
||||||
|
return {
|
||||||
|
node: envGain,
|
||||||
|
stop: (time) => {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ prebake: true, type: 'synth' },
|
||||||
|
);
|
||||||
|
|
||||||
[...noises].forEach((s) => {
|
[...noises].forEach((s) => {
|
||||||
registerSound(
|
registerSound(
|
||||||
s,
|
s,
|
||||||
|
|||||||
@ -648,3 +648,99 @@ class PhaseVocoderProcessor extends OLAProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
registerProcessor('phase-vocoder-processor', PhaseVocoderProcessor);
|
registerProcessor('phase-vocoder-processor', PhaseVocoderProcessor);
|
||||||
|
|
||||||
|
// SelfPMpwmWorklet.js
|
||||||
|
|
||||||
|
class PwmOscillatorProcessor extends AudioWorkletProcessor {
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.pi = _PI;
|
||||||
|
this.phi = -this.pi; // phase
|
||||||
|
this.Y0 = 0; // feedback memories
|
||||||
|
this.Y1 = 0;
|
||||||
|
this.PW = this.pi; // pulse width
|
||||||
|
this.B = 2.3; // feedback coefficient
|
||||||
|
this.dphif = 0; // filtered phase increment
|
||||||
|
this.envf = 0; // filtered envelope
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static get parameterDescriptors() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'begin',
|
||||||
|
defaultValue: 0,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
min: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'end',
|
||||||
|
defaultValue: 0,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
min: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'frequency',
|
||||||
|
defaultValue: 440,
|
||||||
|
min: Number.EPSILON,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'pulsewidth',
|
||||||
|
defaultValue: 1,
|
||||||
|
min: 0,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
process(inputs, outputs, params) {
|
||||||
|
if (currentTime <= params.begin[0]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (currentTime >= params.end[0]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const output = outputs[0];
|
||||||
|
let env = 1, dphi;
|
||||||
|
let freq = params.frequency[0]
|
||||||
|
let pw = params.pulsewidth[0] * _PI
|
||||||
|
|
||||||
|
for (let i = 0; i < (output[0].length ?? 0); i++) {
|
||||||
|
dphi = freq * (this.pi / (sampleRate * .5)); // phase increment
|
||||||
|
this.dphif += 0.1 * (dphi - this.dphif);
|
||||||
|
|
||||||
|
env *= 0.9998; // exponential decay envelope
|
||||||
|
this.envf += 0.1 * (env - this.envf);
|
||||||
|
|
||||||
|
// Feedback coefficient control
|
||||||
|
this.B = 2.3 * (1 - 0.0001 * freq); // feedback limitation
|
||||||
|
if (this.B < 0) this.B = 0;
|
||||||
|
|
||||||
|
// Waveform generation (half-Tomisawa oscillators)
|
||||||
|
this.phi += this.dphif; // phase increment
|
||||||
|
if (this.phi >= this.pi) this.phi -= 2 * this.pi; // phase wrapping
|
||||||
|
|
||||||
|
// First half-Tomisawa generator
|
||||||
|
let out0 = Math.cos(this.phi + this.B * this.Y0); // self-phase modulation
|
||||||
|
this.Y0 = 0.5 * (out0 + this.Y0); // anti-hunting filter
|
||||||
|
|
||||||
|
// Second half-Tomisawa generator (with phase offset for pulse width)
|
||||||
|
let out1 = Math.cos(this.phi + this.B * this.Y1 + pw);
|
||||||
|
this.Y1 = 0.5 * (out1 + this.Y1); // anti-hunting filter
|
||||||
|
|
||||||
|
for (let o = 0; o < output.length; o++) {
|
||||||
|
// Combination of both oscillators with envelope applied
|
||||||
|
output[o][i] = 0.15 * (out0 - out1) * this.envf;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // keep the audio processing going
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerProcessor('pwm-oscillator', PwmOscillatorProcessor);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user