1import { releaseAudioNode } from './helpers.mjs'; 2 3// credits to webdirt: https://github.com/dktr0/WebDirt/blob/41342e81d6ad694a2310d491fef7b7e8b0929efe/js-src/Graph.js#L597 4export var vowelFormant = { 5 a: { freqs: [660, 1120, 2750, 3000, 3350], gains: [1, 0.5012, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, 6 e: { freqs: [440, 1800, 2700, 3000, 3300], gains: [1, 0.1995, 0.1259, 0.1, 0.1], qs: [70, 80, 100, 120, 120] }, 7 i: { freqs: [270, 1850, 2900, 3350, 3590], gains: [1, 0.0631, 0.0631, 0.0158, 0.0158], qs: [40, 90, 100, 120, 120] }, 8 o: { freqs: [430, 820, 2700, 3000, 3300], gains: [1, 0.3162, 0.0501, 0.0794, 0.01995], qs: [40, 80, 100, 120, 120] }, 9 u: { freqs: [370, 630, 2750, 3000, 3400], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, 10 ae: { freqs: [650, 1515, 2400, 3000, 3350], gains: [1, 0.5, 0.1008, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, 11 aa: { freqs: [560, 900, 2570, 3000, 3300], gains: [1, 0.5, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, 12 oe: { freqs: [500, 1430, 2300, 3000, 3300], gains: [1, 0.2, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, 13 ue: { freqs: [250, 1750, 2150, 3200, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, 14 y: { freqs: [400, 1460, 2400, 3000, 3300], gains: [1, 0.2, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, 15 uh: { freqs: [600, 1250, 2100, 3100, 3500], gains: [1, 0.3, 0.0608, 0.0316, 0.01995], qs: [40, 70, 100, 120, 130] }, 16 un: { freqs: [500, 1240, 2280, 3000, 3500], gains: [1, 0.1, 0.1708, 0.0216, 0.02995], qs: [40, 60, 100, 120, 120] }, 17 en: { freqs: [600, 1480, 2450, 3200, 3300], gains: [1, 0.15, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, 18 an: { freqs: [700, 1050, 2500, 3000, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, 19 on: { freqs: [500, 1080, 2350, 3000, 3300], gains: [1, 0.1, 0.0708, 0.0316, 0.02995], qs: [40, 60, 100, 120, 120] }, 20 get æ() { 21 return this.ae; 22 }, 23 get ø() { 24 return this.oe; 25 }, 26 get ɑ() { 27 return this.aa; 28 }, 29 get å() { 30 return this.aa; 31 }, 32 get ö() { 33 return this.oe; 34 }, 35 get ü() { 36 return this.ue; 37 }, 38 get ı() { 39 return this.y; 40 }, 41}; 42if (typeof GainNode !== 'undefined') { 43 class VowelNode extends GainNode { 44 constructor(ac, letter) { 45 super(ac); 46 if (!vowelFormant[letter]) { 47 throw new Error('vowel: unknown vowel ' + letter); 48 } 49 const { gains, qs, freqs } = vowelFormant[letter]; 50 this.makeupGain = ac.createGain(); 51 this.filters = []; 52 this.gains = []; 53 for (let i = 0; i < 5; i++) { 54 const gain = ac.createGain(); 55 gain.gain.value = gains[i]; 56 const filter = ac.createBiquadFilter(); 57 filter.type = 'bandpass'; 58 filter.Q.value = qs[i]; 59 filter.frequency.value = freqs[i]; 60 super.connect(filter); 61 filter.connect(gain); 62 this.filters.push(filter); 63 gain.connect(this.makeupGain); 64 this.gains.push(gain); 65 } 66 this.makeupGain.gain.value = 8; // how much makeup gain to add? 67 return this; 68 } 69 connect(target) { 70 this.makeupGain.connect(target); 71 } 72 disconnect() { 73 releaseAudioNode(this.makeupGain); 74 this.filters.forEach(releaseAudioNode); 75 this.gains.forEach(releaseAudioNode); 76 super.disconnect(); 77 this.makeupGain = null; 78 this.filters = null; 79 this.gains = null; 80 } 81 } 82 83 BaseAudioContext.prototype.createVowelFilter = function (letter) { 84 return new VowelNode(this, letter); 85 }; 86}