import flash.media.Sound; /* babblebot Copyright (C) 2008 Alex McLean This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . The formant filter is by alex@smartelectronix.com, taken from http://www.musicdsp.org/ . Thanks! */ class Synth { static var samplesPerCall : Int = 2048; static var delay : Array = new Array(); static var delayPos : Int = 0; static var gain:Float; static var prev:Float; static var input : Array = new Array(); static var letterQueue : Array = new Array(); static var wordQueue : Array = new Array(); static var wordPos = 0; static var maxDelaySz : Int = 512; static var delaySz : Int = Math.floor(maxDelaySz / 2); static var switcheroo : Float = 0; static var vowels : Hash = new Hash(); static var consonants : Hash = new Hash(); static var samples : Int = 0; static var letterSpeed : Int = 1000; static var wordSpeed : Int = 11000; static var coeff : Array>; static var formant_history : Array = new Array(); static var vowelnum = 0; static var jsCnx; static function initLetters() { consonants.set("b", 0); consonants.set("c", 0.04); consonants.set("d", 0.09); consonants.set("f", 0.14); consonants.set("g", 0.19); consonants.set("h", 0.23); consonants.set("j", 0.28); consonants.set("k", 0.33); consonants.set("l", 0.38); consonants.set("m", 0.42); consonants.set("n", 0.47); consonants.set("p", 0.52); consonants.set("q", 0.57); consonants.set("r", 0.61); consonants.set("s", 0.66); consonants.set("t", 0.71); consonants.set("v", 0.76); consonants.set("w", 0.80); consonants.set("x", 0.85); consonants.set("y", 0.9); consonants.set("z", 0.95); vowels.set("a", 0.4); vowels.set("e", 0.8); vowels.set("i", 0.5); vowels.set("o", 0.9); vowels.set("u", 0.7); } static function main() { //trace(flash.system.Capabilities.version); initLetters(); initCoeff(); var i; prev = 0; gain = 0.5; var ctx = new haxe.remoting.Context(); ctx.addObject("Synth",Synth); jsCnx = haxe.remoting.ExternalConnection.jsConnect("default",ctx); var buffer = new Sound(); for (i in 0 ... maxDelaySz) { delay.push(0.0); } buffer.addEventListener("sampleData", onSamplesCallback); buffer.play(); } static function play(dur : Null) { for (i in 0 ... dur) { input.push((Math.random() - 0.5) * gain); } } static function setDelaySz(sz : Null) { if (sz > 1) { sz = 1; } if (sz < 0) { sz = 0; } var foo = Math.floor(sz * maxDelaySz); if (foo < delaySz) { for (i in foo ... delaySz) { delay[i] = 0.0; } } delaySz = foo; } static function setSwitcheroo(i : Float) { if (i > 1) { i = 1; } else if (i < 0) { i = 0; } switcheroo = i; } static function playWord(n: Int) { var w = wordQueue[n].toLowerCase(); jsCnx.JsClient.playingWord.call([n, wordQueue]); for (i in 0 ... w.length) { var c : String = w.charAt(i); letterQueue.push(c); } } static function playSentence(s : String) { var r : EReg = ~/([a-zA-Z]+|-)/g; wordQueue = new Array(); while (r.match(s)) { wordQueue.push(r.matched(1)); } } static function playNextLetter() { var c = letterQueue.shift(); if (c == '-') { // a rest - do nothing } else if (consonants.exists(c)) { setSwitcheroo(consonants.get(c)); play(50); } else if (vowels.exists(c)) { setDelaySz(vowels.get(c)); if (c == 'a') { vowelnum = 0; } else if (c == 'e') { vowelnum = 1; } else if (c == 'i') { vowelnum = 2; } else if (c == 'o') { vowelnum = 3; } else if (c == 'u') { vowelnum = 4; } } else { // unknown glyph } } static function onSamplesCallback(event) { for (i in 0 ... (samplesPerCall)) { var sample = delay[delayPos]; var tmp = prev; prev = sample; sample = (tmp + sample) * 0.5; var output = formant_filter(sample); event.data.writeFloat(output); // left event.data.writeFloat(output); // right sample = sample * 0.99; if (input.length > 0) { sample += input.shift(); } if (switcheroo > 0 && (Math.random() < switcheroo)) { sample = 0 - sample; } delay[delayPos] = sample; if (++delayPos >= delaySz) { delayPos = 0; } if (samples % letterSpeed == 0 && letterQueue.length > 0) { playNextLetter(); } if (samples % wordSpeed == 0 && wordQueue.length > 0) { playWord(wordPos % wordQueue.length); wordPos++; } samples++; } } static function initCoeff() { coeff = new Array>(); coeff[0] = [3.11044e-06, 8.943665402, -36.83889529, 92.01697887, -154.337906, 181.6233289, -151.8651235, 89.09614114, -35.10298511, 8.388101016, -0.923313471 ]; coeff[1] = [4.36215e-06, 8.90438318, -36.55179099, 91.05750846, -152.422234, 179.1170248, -149.6496211, 87.78352223, -34.60687431, 8.282228154, -0.914150747 ]; coeff[2] = [3.33819e-06, 8.893102966, -36.49532826, 90.96543286, -152.4545478, 179.4835618, -150.315433, 88.43409371, -34.98612086, 8.407803364, -0.932568035 ]; coeff[3] = [1.13572e-06, 8.994734087, -37.2084849, 93.22900521, -156.6929844, 184.596544, -154.3755513, 90.49663749, -35.58964535, 8.478996281, -0.929252233 ]; coeff[4] = [4.09431e-07, 8.997322763, -37.20218544, 93.11385476, -156.2530937, 183.7080141, -153.2631681, 89.59539726, -35.12454591, 8.338655623, -0.910251753 ]; for (i in 0 ... 11) { formant_history.push(0.0); } } static function formant_filter(s : Float) { var res : Float; res = ( coeff[vowelnum][0] * s + coeff[vowelnum][1] * formant_history[0] + coeff[vowelnum][2] * formant_history[1] + coeff[vowelnum][3] * formant_history[2] + coeff[vowelnum][4] * formant_history[3] + coeff[vowelnum][5] * formant_history[4] + coeff[vowelnum][6] * formant_history[5] + coeff[vowelnum][7] * formant_history[6] + coeff[vowelnum][8] * formant_history[7] + coeff[vowelnum][9] * formant_history[8] + coeff[vowelnum][10] * formant_history[9] ); formant_history[9] = formant_history[8]; formant_history[8] = formant_history[7]; formant_history[7] = formant_history[6]; formant_history[6] = formant_history[5]; formant_history[5] = formant_history[4]; formant_history[4] = formant_history[3]; formant_history[3] = formant_history[2]; formant_history[2] = formant_history[1]; formant_history[1] = formant_history[0]; formant_history[0] = res; return res; } }