control osc partial count with n

This commit is contained in:
Felix Roos 2023-08-24 12:21:29 +02:00
parent f20c5a1bcb
commit 5cbe30095b
2 changed files with 53 additions and 18 deletions

View File

@ -6,17 +6,6 @@ export function gainNode(value) {
return node;
}
export const getOscillator = ({ s, freq, t }) => {
// make oscillator
const o = getAudioContext().createOscillator();
o.type = s || 'triangle';
o.frequency.value = Number(freq);
o.start(t);
//o.stop(t + duration + release);
const stop = (time) => o.stop(time);
return { node: o, stop };
};
// alternative to getADSR returning the gain node and a stop handle to trigger the release anytime in the future
export const getEnvelope = (attack, decay, sustain, release, velocity, begin) => {
const gainNode = getAudioContext().createGain();

View File

@ -1,6 +1,6 @@
import { midiToFreq, noteToMidi } from './util.mjs';
import { registerSound, getAudioContext } from './superdough.mjs';
import { getOscillator, gainNode, getEnvelope } from './helpers.mjs';
import { gainNode, getEnvelope } from './helpers.mjs';
const mod = (freq, range = 1, type = 'sine') => {
const ctx = getAudioContext();
@ -36,17 +36,17 @@ export function registerSynthSounds() {
} = value;
let { n, note, freq } = value;
// with synths, n and note are the same thing
n = note || n || 36;
if (typeof n === 'string') {
n = noteToMidi(n); // e.g. c3 => 48
note = note || 36;
if (typeof note === 'string') {
note = noteToMidi(note); // e.g. c3 => 48
}
// get frequency
if (!freq && typeof n === 'number') {
freq = midiToFreq(n); // + 48);
if (!freq && typeof note === 'number') {
freq = midiToFreq(note); // + 48);
}
// maybe pull out the above frequency resolution?? (there is also getFrequency but it has no default)
// make oscillator
const { node: o, stop } = getOscillator({ t, s: wave, freq });
const { node: o, stop } = getOscillator({ t, s: wave, freq, partials: n });
let stopFm;
if (fmModulationIndex) {
@ -76,3 +76,49 @@ export function registerSynthSounds() {
);
});
}
export function waveformN(partials, type) {
const real = new Float32Array(partials + 1);
const imag = new Float32Array(partials + 1);
const ac = getAudioContext();
const osc = ac.createOscillator();
const amplitudes = {
sawtooth: (n) => 1 / n,
square: (n) => (n % 2 === 0 ? 0 : 1 / n),
triangle: (n) => (n % 2 === 0 ? 0 : 1 / (n * n)),
};
if (!amplitudes[type]) {
throw new Error(`unknown wave type ${type}`);
}
real[0] = 0; // dc offset
imag[0] = 0;
let n = 1;
while (n <= partials) {
real[n] = amplitudes[type](n);
imag[n] = 0;
n++;
}
const wave = ac.createPeriodicWave(real, imag);
osc.setPeriodicWave(wave);
return osc;
}
export function getOscillator({ s, freq, t, partials }) {
// make oscillator
let o;
if (!partials || s === 'sine') {
o = getAudioContext().createOscillator();
o.type = s || 'triangle';
} else {
o = waveformN(partials, s);
}
o.frequency.value = Number(freq);
o.start(t);
//o.stop(t + duration + release);
const stop = (time) => o.stop(time);
return { node: o, stop };
}