From 4406dd88d1f3f4313149216f3e4cd3d55d2381cb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 15 Sep 2022 20:09:07 +0200 Subject: [PATCH] add vowel --- packages/webaudio/vowel.mjs | 37 ++++++++++++++++++++++++++++++++++ packages/webaudio/webaudio.mjs | 3 +++ 2 files changed, 40 insertions(+) create mode 100644 packages/webaudio/vowel.mjs diff --git a/packages/webaudio/vowel.mjs b/packages/webaudio/vowel.mjs new file mode 100644 index 00000000..c35b1ebd --- /dev/null +++ b/packages/webaudio/vowel.mjs @@ -0,0 +1,37 @@ +// credits to webdirt: https://github.com/dktr0/WebDirt/blob/41342e81d6ad694a2310d491fef7b7e8b0929efe/js-src/Graph.js#L597 +export var vowelFormant = { + a: { freqs: [660, 1120, 2750, 3000, 3350], gains: [1, 0.5012, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, + e: { freqs: [440, 1800, 2700, 3000, 3300], gains: [1, 0.1995, 0.1259, 0.1, 0.1], qs: [70, 80, 100, 120, 120] }, + i: { freqs: [270, 1850, 2900, 3350, 3590], gains: [1, 0.0631, 0.0631, 0.0158, 0.0158], qs: [40, 90, 100, 120, 120] }, + o: { freqs: [430, 820, 2700, 3000, 3300], gains: [1, 0.3162, 0.0501, 0.0794, 0.01995], qs: [40, 80, 100, 120, 120] }, + u: { freqs: [370, 630, 2750, 3000, 3400], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, +}; + +class VowelNode extends GainNode { + constructor(ac, letter) { + super(ac); + if (!vowelFormant[letter]) { + throw new Error('vowel: unknown vowel ' + letter); + } + const { gains, qs, freqs } = vowelFormant[letter]; + const makeupGain = ac.createGain(); + for (let i = 0; i < 5; i++) { + const gain = ac.createGain(); + gain.gain.value = gains[i]; + const filter = ac.createBiquadFilter(); + filter.type = 'bandpass'; + filter.Q.value = qs[i]; + filter.frequency.value = freqs[i]; + this.connect(filter); + filter.connect(gain); + gain.connect(makeupGain); + } + makeupGain.gain.value = 8; // how much makeup gain to add? + this.connect = (target) => makeupGain.connect(target); + return this; + } +} + +AudioContext.prototype.createVowelFilter = function (letter) { + return new VowelNode(this, letter); +}; diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 2a6d39d0..18186118 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -9,6 +9,7 @@ import * as strudel from '@strudel.cycles/core'; import { fromMidi, toMidi } from '@strudel.cycles/core'; import { loadBuffer } from './sampler.mjs'; const { Pattern } = strudel; +import './vowel.mjs'; // export const getAudioContext = () => Tone.getContext().rawContext; @@ -158,6 +159,7 @@ Pattern.prototype.out = function () { speed = 1, // sample playback speed begin = 0, end = 1, + vowel, } = hap.value; const { velocity = 1 } = hap.context; gain *= velocity; // legacy fix for velocity @@ -258,6 +260,7 @@ Pattern.prototype.out = function () { cutoff !== undefined && chain.push(getFilter('lowpass', cutoff, resonance)); hcutoff !== undefined && chain.push(getFilter('highpass', hcutoff, hresonance)); bandf !== undefined && chain.push(getFilter('bandpass', bandf, bandq)); + vowel !== undefined && chain.push(ac.createVowelFilter(vowel)); // TODO vowel // TODO delay / delaytime / delayfeedback // panning