1import { releaseAudioNode } from './helpers.mjs';

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}