diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index b8edd51c5..33f03fd22 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -134,7 +134,8 @@ const generic_params = [ * */ [['fmi', 'fmh'], 'fm'], - + ['amh'], + ['ami'], /** * Select the sound bank to use. To be used together with `s`. The bank name (+ "_") will be prepended to the value of `s`. * diff --git a/packages/superdough/helpers.mjs b/packages/superdough/helpers.mjs index 7cc54c8d0..78bcaeca9 100644 --- a/packages/superdough/helpers.mjs +++ b/packages/superdough/helpers.mjs @@ -68,3 +68,17 @@ export const getFilter = (type, frequency, Q) => { filter.Q.value = Q; return filter; }; + +export const getAM = (freq, harmonicityRatio, amount, wave = 'sine') => { + const carrfreq = freq; + const modfreq = carrfreq * harmonicityRatio; + const { node: modulator, stop } = mod(modfreq, amount, wave); + const g = gainNode(1); + modulator.connect(g.gain); + return g;/* + const c = 1 / 1 ** amount; + console.log('c', c); + const compensate = gainNode(1/amount); + g.connect(compensate); + return compensate; */ +}; diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 1279000c0..769f26c61 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th import './feedbackdelay.mjs'; import './reverb.mjs'; import './vowel.mjs'; -import { clamp } from './util.mjs'; +import { clamp, getFrequency } from './util.mjs'; import workletsUrl from './worklets.mjs?url'; import { getFilter, gainNode } from './helpers.mjs'; import { map } from 'nanostores'; @@ -167,6 +167,8 @@ export const superdough = async (value, deadline, hapDuration) => { room, size = 2, velocity = 1, + amh, // amplitude modulation harmonicity + ami = 4, // amplitude modulation index } = value; gain *= velocity; // legacy fix for velocity let toDisconnect = []; // audio nodes that will be disconnected when the source has ended @@ -205,6 +207,7 @@ export const superdough = async (value, deadline, hapDuration) => { // gain stage chain.push(gainNode(gain)); + amh !== undefined && chain.push(getAM(getFrequency(value), amh, ami)); // filters cutoff !== undefined && chain.push(getFilter('lowpass', cutoff, resonance)); hcutoff !== undefined && chain.push(getFilter('highpass', hcutoff, hresonance)); diff --git a/packages/superdough/synth.mjs b/packages/superdough/synth.mjs index 573171336..19aa763f6 100644 --- a/packages/superdough/synth.mjs +++ b/packages/superdough/synth.mjs @@ -2,7 +2,7 @@ import { midiToFreq, noteToMidi } from './util.mjs'; import { registerSound, getAudioContext } from './superdough.mjs'; import { getOscillator, gainNode, getEnvelope } from './helpers.mjs'; -const mod = (freq, range = 1, type = 'sine') => { +export const mod = (freq, range = 1, type = 'sine') => { const ctx = getAudioContext(); const osc = ctx.createOscillator(); osc.type = type; diff --git a/packages/superdough/util.mjs b/packages/superdough/util.mjs index db0563764..2e2d55943 100644 --- a/packages/superdough/util.mjs +++ b/packages/superdough/util.mjs @@ -51,3 +51,21 @@ export const valueToMidi = (value, fallbackValue) => { } return fallbackValue; }; + +export const getFrequency = (value) => { + // if value is number => interpret as midi number as long as its not marked as frequency + if (typeof value === 'object') { + if (value.freq) { + return value.freq; + } + return getFreq(value.note || value.n || value.value || 36); + } + if (typeof value === 'number' && context.type !== 'frequency') { + value = midiToFreq(hap.value); + } else if (typeof value === 'string' && isNote(value)) { + value = midiToFreq(noteToMidi(hap.value)); + } else if (typeof value !== 'number') { + throw new Error('not a note or frequency: ' + value); + } + return value; +};