loop_0
1 loop, 0 filters (1 worker, 1 AudioWorklet) tick: 0.000, time: 0.000 (60 bpm)
Whistled Speech
I found out today about whistled languages, and I couldn't resist programming a basic Silbo Gomero reader.
Log in to post a comment.
// Very basic "Silbo Gomero" whistled speech generator/*This program converts a string of lowercase letters (a-z) and spacesinto an audio interpretation in Silbo Gomero whistle speech.Silbo Gomero is a whistled register of Spanish used by inhabitantsof La Gomera in the Canary Islands to communicate across long distances.I've used a very basic mapping from Spanish phonemes intocorresponding whistled ones, and the audio is generated usinga sine wave that is modulated in frequency and amplitude.Some information on the phonetics of the Silbo languagecan be found in:https://en.wikipedia.org/wiki/Silbo_Gomerohttp://silbo-gomero.com/Meyer-English.pdfhttp://silbo-gomero.com/wlanguages.pdfhttps://www.cambridge.org/core/services/aop-cambridge-core/content/view/A2829FE674349AD9A836982A23AA74B7/S0952675705000552a.pdf/phonological_and_phonetic_aspects_of_whistled_languages.pdf*/let sentence = "el silbo gomero es un lenguaje silbado practicado por algunos habitantes de canarias para comunicarse a traves de barrancos y valles";//let sentence = "como estas";//let sentence = "hola estas alli si estoy aqi esta jose alli no el no esta aqi";ditty.bpm = 60; // 1 tick = 1 secondfunction nsin(a) {// Not quite a sinusoidlet x = a - (~~a);//return Math.sin(2*Math.PI*x);return x*(x-1)*(x-0.5)*20.785;//x -= 0.5; x *= 2 * 3.0786; return x - x**3/6 + x**5/(1*2*3*4*5) - x**7/(1*2*3*4*5*6*7);}const chirpSynth = synth.def( class {constructor(o) {this.p = 0;this.f = o.f;this.g = 0; // gain}process(n,e,t,o) {let a0 = clamp01(ditty.dt / o.dt);this.f += a0 * (o.f - this.f);this.g = clamp01(this.g + 1.5*a0 * (2*o.g-1));this.p += this.f * ditty.dt;return nsin(this.p) * this.g;}}, {f: 1400, g:1, dt:0.12, env:one, amp:0.1});function rn(a) {// Random number between -a and +areturn 2*a*(Math.random()-0.5);}function rrn(a) {// Relative random number between exp(-a) and exp(+a)return Math.exp(rn(a));}function getFreq(char) {// Get frequency corresponding to a given character sound// Vowelsif(char == "u") {return 1450 + rn(50);} else if (char == "o") {return 1600+rn(120);} else if (char == "a") {return 1700+rn(100);} else if (char == "e") {return 2200+rn(300);} else if (char == "i") {return 2700+rn(120);// Consonants} else if (["d","j","l","n","r","s","t","y","z"].includes(char)) {return 3100+rn(100);} else if (["b","c","f","g","k","m","p","q","v","w","x"].includes(char)) {return 800+rn(50);}return null;}function getGain(char) {if("abdefgijlmnorsuvwyz".includes(char)) {return 1;}return 0;}function getDur(char) {if(char == " ") {return 0.5;} else if("aeiou".includes(char)) {return 0.4;} else if("stlckqj".includes(char)) {return 0.05;}return 0.12;}loop( () => {let prevdur = 1000;let s = chirpSynth.play({f:1400, g:0});for(let i=0; i<sentence.length; i++) {let char = sentence.charAt(i);let freq = getFreq(char);if(freq) {s.options.f = freq;}let gain = getGain(char);s.options.g = gain;let dur = getDur(char);s.options.dt = Math.min(dur, prevdur);sleep(dur);prevdur = dur;}s.options.g = 0;sleep(1000);});
1557 chars