A programmable version of Neil Thapen's Pink Trombone
Sound is generated in the glottis (at the bottom left), then filtered by the shape of the vocal tract. The voicebox controls the pitch and intensity of the initial sound - Neil Thapen
A programmable version of Neil Thapen's famous and wonderful Pink Trombone
👀 Enabling and Disabling the UI
🎺 Manipulating Vocal Tract Constrictions
Save a local copy of pink-trombone.min.js
and pink-trombone-worklet-processor.min.js
and make sure they're both in the same relative location (the first will import the other as a Audio Worklet Processor)
In your HTML <head></head>
element, insert the file in a script element as a module:
<script src="pink-trombone.min.js" type="module"></script>
<body></body>
element, insert the following custom element:<pink-trombone></pink-trombone>
<pink-trombone></pink-trombone>
element:var pinkTromboneElement = document.querySelector("pink-trombone");
load
eventListener to the pinkTromboneElement
element:pinkTromboneElement.addEventListener("load", myCallback);
"load"
callback, assign an Audio Context using .setAudioContext(myAudioContext)
(if none is specified, an Audio Context instance is created for you):function myCallback(event) {
pinkTromboneElement.setAudioContext(myAudioContext)
}
This method returns a Promise once the AudioWorkletProcessor module is loaded.
<pink-trombone></pink-trombone>
element:function myCallback(event) {
pinkTromboneElement.setAudioContext(myAudioContext)
.then(() => {
const audioContext = pinkTromboneElement.audioContext
pinkTromboneElement.connect(audioContext.destination);
});
}
😃 To start generating sound, run the .start()
method:
pinkTromboneElement.start();
🤐 To stop generating sound, run the .stop()
method:
pinkTromboneElement.stop();
🙂 To show the interactive visualization:
pinkTromboneElement.enableUI();
✍️ To start animating the visualization:
pinkTromboneElement.startUI();
🛑 To stop animating the visualization:
pinkTromboneElement.stopUI();
😊 To hide the interactive visualization:
pinkTromboneElement.disableUI();
The audio parameters of the Pink Trombone audio node can be accessed from the <pink-trombone></pink-trombone>
element's scope:
🎚️ Intensity
pinkTromboneElement.intensity;
🎵 Frequency
pinkTromboneElement.frequency;
👄 Tenseness
pinkTromboneElement.tenseness;
📢 Loudness
pinkTromboneElement.loudness;
〰️ Vibrato
pinkTromboneElement.vibrato.frequency;
pinkTromboneElement.vibrato.gain;
pinkTromboneElement.vibrato.wobble;
👅 Tongue
// 'index' and 'diameter' refer to the tongue's location in the mouth
pinkTromboneElement.tongue.index;
pinkTromboneElement.tongue.diameter;
To change the voiceness between voiced and voiceless, change the .tenseness
and .loudness
audio parameters as follows:
function setVoiceness(voiceness) {
const tenseness = 1 - Math.cos((voiceness) * Math.PI * 0.5);
const loudness = Math.pow(tenseness, 0.25);
pinkTromboneElement.tenseness.value = tenseness;
pinkTromboneElement.loudness.value = loudness;
}
// voiced
setVoiceness(1);
// voiceless
setVoiceness(0);
Later on I may add a .voiceness
audio parameter that automates this - for now I'm just adopting the original version
Vocal Tract constrictions comprise of an object containing .index
and .diameter
Audio Parameter properties that are implicitly connected to the Pink Trombone audio node
To add a vocal tract constriction:
var myConstriction = pinkTromboneElement.newConstriction(indexValue, diameterValue);
To set a vocal tract constriction:
myConstriction.index.value = newIndexValue;
myConstriction.diameter.value = newDiameterValue;
To remove a vocal tract constriction:
pinkTromboneElement.removeConstriction(myConstriction);
For reference, here are some preset index & diameter preset values for some phonemes:
👅 Tongue phonemes:
æ [pat]
ɑ [part]
ɒ [pot]
ɔ [port (rounded)]
ɪ [pit]
i [peat]
e [pet]
ʌ [put]
u [poot (rounded)]
ə [pert]
🎺 Vocal Tract Constriction phonemes: voiced and voiceless consonants share the same values, differing in voiceness
(ʒ, ʃ) ["s" in "pleasure"]
(z, s) ["z" in "zoo"]
(v, f) ["v" in "very"]
(g, k) ["g" in "go"]
(d, t) ["d" in "den"]
(b, p) ["b" in "bad"]
(ŋ) ["ng" in "hang"]
(n) ["n" in "not"]
(m) ["m" in "woman"]
Send us an email at [email protected] if you have a cool application made with our api!
Our time is limited, so we'd greatly appreciate it if you guys could implement some of these ideas: