/* Smalltalk from Squeak4.5 with VMMaker 4.13.6 translated as JS source on 3 November 2014 1:52:21 pm */ /* Automatically generated by JSPluginCodeGenerator VMMakerJS-bf.15 uuid: fd4e10f2-3773-4e80-8bb5-c4b471a014e5 from KlattSynthesizerPlugin VMMaker-bf.353 uuid: 8ae25e7e-8d2c-451e-8277-598b30e9c002 */ (function Klatt() { "use strict"; var VM_PROXY_MAJOR = 1; var VM_PROXY_MINOR = 11; /*** Functions ***/ function CLASSOF(obj) { return typeof obj === "number" ? interpreterProxy.classSmallInteger() : obj.sqClass } function SIZEOF(obj) { return obj.pointers ? obj.pointers.length : obj.words ? obj.words.length : obj.bytes ? obj.bytes.length : 0 } function BYTESIZEOF(obj) { return obj.bytes ? obj.bytes.length : obj.words ? obj.words.length * 4 : 0 } function DIV(a, b) { return Math.floor(a / b) | 0; } // integer division function MOD(a, b) { return a - DIV(a, b) * b | 0; } // signed modulus function SHL(a, b) { return b > 31 ? 0 : a << b; } // fix JS shift function SHR(a, b) { return b > 31 ? 0 : a >>> b; } // fix JS shift function SHIFT(a, b) { return b < 0 ? (b < -31 ? 0 : a >>> (0-b) ) : (b > 31 ? 0 : a << b); } /*** Constants ***/ var A1v = 46; var A2f = 34; var A2v = 47; var A3f = 35; var A3v = 48; var A4f = 36; var A4v = 49; var A5f = 37; var A6f = 38; var Anv = 45; var Aspiration = 9; var Atv = 50; var B1 = 13; var B2 = 17; var B2f = 40; var B3 = 19; var B3f = 41; var B4 = 21; var B4f = 42; var B5 = 23; var B5f = 43; var B6 = 25; var B6f = 44; var Bnp = 27; var Bnz = 29; var Btp = 31; var Btz = 33; var Bypass = 39; var Diplophonia = 4; var Epsilon = 0.0001; var F0 = 0; var F1 = 12; var F2 = 16; var F3 = 18; var F4 = 20; var F5 = 22; var F6 = 24; var Flutter = 1; var Fnp = 26; var Fnz = 28; var Friction = 10; var Ftp = 30; var Ftz = 32; var Gain = 51; var Jitter = 2; var PI = 3.141592653589793; var R1c = 12; var R1vp = 3; var R2c = 13; var R2fp = 7; var R2vp = 4; var R3c = 14; var R3fp = 8; var R3vp = 5; var R4c = 15; var R4fp = 9; var R4vp = 6; var R5c = 16; var R5fp = 10; var R6c = 17; var R6fp = 11; var R7c = 18; var R8c = 19; var Ra = 7; var Rk = 8; var Rnpc = 20; var Rnpp = 1; var Rnz = 21; var Ro = 6; var Rout = 24; var Rtpc = 22; var Rtpp = 2; var Rtz = 23; var Shimmer = 3; var Turbulence = 11; var Voicing = 5; /*** Variables ***/ var a1 = 0; var a2 = 0; var b1 = 0; var c1 = 0; var cascade = 0; var frame = null; var glast = 0; var interpreterProxy = null; var moduleName = "Klatt 3 November 2014 (e)"; var nlast = 0; var nmod = 0; var nopen = 0; var nper = 0; var periodCount = 0; var pitch = 0; var resonators = null; var samplesCount = 0; var samplesPerFrame = 0; var samplingRate = 0; var seed = 0; var t0 = 0; var vlast = 0; var x1 = 0; var x2 = 0; /* Add diplophonia (bicyclic voice). Change voicing amplitude. */ function addAmplitudeDiplophonia() { if ((MOD(periodCount, 2)) !== 0) { /* x1 must be <= 0 */ x1 = x1 * (1.0 - frame[Diplophonia]); if (x1 > 0) { x1 = 0; } } } /* Add F0 flutter, as specified in: 'Analysis, synthesis and perception of voice quality variations among female and male talkers' D.H. Klatt and L.C. Klatt JASA 87(2) February 1990. Flutter is added by applying a quasi-random element constructed from three slowly varying sine waves. */ function addFlutter() { var asin; var bsin; var csin; var deltaF0; var timeCount; timeCount = samplesCount / samplingRate; asin = Math.sin(((2.0 * PI) * 12.7) * timeCount); bsin = Math.sin(((2.0 * PI) * 7.1) * timeCount); csin = Math.sin(((2.0 * PI) * 4.7) * timeCount); deltaF0 = (((frame[Flutter] * 2.0) * frame[F0]) / 100.0) * ((asin + bsin) + csin); pitch += deltaF0; } /* Add diplophonia (bicyclic voice). Change F0. */ function addFrequencyDiplophonia() { if ((MOD(periodCount, 2)) === 0) { pitch += (frame[Diplophonia] * frame[F0]) * (1.0 - frame[Ro]); } else { pitch -= (frame[Diplophonia] * frame[F0]) * (1.0 - frame[Ro]); } } /* Add jitter (random F0 perturbation). */ function addJitter() { pitch += (((nextRandom() - 32767) * frame[Jitter]) / 32768.0) * frame[F0]; } /* Add shimmer (random voicing amplitude perturbation). */ function addShimmer() { /* x1 must be <= 0 */ x1 += (((nextRandom() - 32767) * frame[Shimmer]) / 32768.0) * x1; if (x1 > 0) { x1 = 0; } } /* Set up an anti-resonator */ function antiResonatorfrequencybandwidth(index, freq, bw) { var a; var arg; var b; var c; var r; arg = ((0.0 - PI) / samplingRate) * bw; r = Math.exp(arg); c = 0.0 - (r * r); arg = ((PI * 2.0) / samplingRate) * freq; b = (r * Math.cos(arg)) * 2.0; a = (1.0 - b) - c; a = 1.0 / a; b = (0.0 - b) * a; c = (0.0 - c) * a; resonatorAput(index, a); resonatorBput(index, b); resonatorCput(index, c); } function antiResonatorvalue(index, aFloat) { var answer; var p1; answer = ((resonatorA(index) * aFloat) + (resonatorB(index) * ((p1 = resonatorP1(index))))) + (resonatorC(index) * resonatorP2(index)); resonatorP2put(index, p1); resonatorP1put(index, aFloat); return answer; } /* Cascade vocal tract, excited by laryngeal sources. Nasal antiresonator, nasal resonator, tracheal antirresonator, tracheal resonator, then formants F8, F7, F6, F5, F4, F3, F2, F1. */ function cascadeBranch(source) { var out; if (!(cascade > 0)) { return 0.0; } out = antiResonatorvalue(Rnz, source); out = resonatorvalue(Rnpc, out); out = antiResonatorvalue(Rtz, out); /* Do not use unless sample rate >= 16000 */ out = resonatorvalue(Rtpc, out); if (cascade >= 8) { out = resonatorvalue(R8c, out); } if (cascade >= 7) { out = resonatorvalue(R7c, out); } if (cascade >= 6) { out = resonatorvalue(R6c, out); } if (cascade >= 5) { out = resonatorvalue(R5c, out); } if (cascade >= 4) { out = resonatorvalue(R4c, out); } if (cascade >= 3) { out = resonatorvalue(R3c, out); } if (cascade >= 2) { out = resonatorvalue(R2c, out); } if (cascade >= 1) { out = resonatorvalue(R1c, out); } return out; } /* Return the first indexable word of oop which is assumed to be variableWordSubclass */ function checkedFloatPtrOf(oop) { interpreterProxy.success(interpreterProxy.isWords(oop)); if (interpreterProxy.failed()) { return 0; } return oop.wordsAsFloat32Array(); } /* Return the first indexable word of oop which is assumed to be variableWordSubclass */ function checkedShortPtrOf(oop) { interpreterProxy.success(interpreterProxy.isWords(oop)); if (interpreterProxy.failed()) { return 0; } return oop.wordsAsInt16Array(); } /* Note: This is hardcoded so it can be run from Squeak. The module name is used for validating a module *after* it is loaded to check if it does really contain the module we're thinking it contains. This is important! */ function getModuleName() { return moduleName; } function glottalSource() { var x0; if (t0 === 0) { return 0; } if (nper < nopen) { x0 = (a1 * x1) + (a2 * x2); x2 = x1; x1 = x0; } else { x0 = (b1 * x1) - c1; x1 = x0; } if (nper >= t0) { nper = 0; pitchSynchronousReset(); } ++nper; return x0; } function halt() { ; } function linearFromdB(aNumber) { return Math.pow(2.0,((aNumber - 87.0) / 6.0)) * 32.767; } function loadFrom(klattOop) { var oop; interpreterProxy.success(SIZEOF(klattOop) === 22); if (interpreterProxy.failed()) { return false; } oop = interpreterProxy.fetchPointerofObject(0, klattOop); resonators = checkedFloatPtrOf(oop); pitch = interpreterProxy.fetchFloatofObject(2, klattOop); t0 = interpreterProxy.fetchIntegerofObject(3, klattOop); nper = interpreterProxy.fetchIntegerofObject(4, klattOop); nopen = interpreterProxy.fetchIntegerofObject(5, klattOop); nmod = interpreterProxy.fetchIntegerofObject(6, klattOop); a1 = interpreterProxy.fetchFloatofObject(7, klattOop); a2 = interpreterProxy.fetchFloatofObject(8, klattOop); x1 = interpreterProxy.fetchFloatofObject(9, klattOop); x2 = interpreterProxy.fetchFloatofObject(10, klattOop); b1 = interpreterProxy.fetchFloatofObject(11, klattOop); c1 = interpreterProxy.fetchFloatofObject(12, klattOop); glast = interpreterProxy.fetchFloatofObject(13, klattOop); vlast = interpreterProxy.fetchFloatofObject(14, klattOop); nlast = interpreterProxy.fetchFloatofObject(15, klattOop); periodCount = interpreterProxy.fetchIntegerofObject(16, klattOop); samplesCount = interpreterProxy.fetchIntegerofObject(17, klattOop); seed = interpreterProxy.fetchIntegerofObject(18, klattOop); cascade = interpreterProxy.fetchIntegerofObject(19, klattOop); samplesPerFrame = interpreterProxy.fetchIntegerofObject(20, klattOop); samplingRate = interpreterProxy.fetchIntegerofObject(21, klattOop); return interpreterProxy.failed() === false; } /* Answer a random number between 0 and 65535. */ function nextRandom() { seed = ((seed * 1309) + 13849) & 65535; return seed; } function normalizeGlottalPulse() { var ingore; var s0; var s1; var s2; s0 = 0.0; s1 = x1; s2 = x2; for (ingore = 1; ingore <= nopen; ingore++) { s0 = (a1 * s1) + (a2 * s2); s2 = s1; s1 = s0; } if (s0 !== 0.0) { x1 = (x1 / s0) * 10000.0; } } /* Friction-excited parallel vocal tract formants F6, F5, F4, F3, F2, outputs added with alternating sign. Sound source for other parallel resonators is friction plus first difference of voicing waveform. */ function parallelFrictionBranch(source) { return (((resonatorvalue(R2fp, source) - resonatorvalue(R3fp, source)) + resonatorvalue(R4fp, source)) - resonatorvalue(R5fp, source)) + resonatorvalue(R6fp, source); } /* Voice-excited parallel vocal tract F1, F2, F3, F4, FNP and FTP. */ function parallelVoicedBranch(source) { return ((((resonatorvalue(R1vp, source) + resonatorvalue(R2vp, source)) + resonatorvalue(R3vp, source)) + resonatorvalue(R4vp, source)) + resonatorvalue(Rnpp, source)) + resonatorvalue(Rtpp, source); } function pitchSynchronousReset() { if (frame[F0] > 0) { voicedPitchSynchronousReset(); periodCount = MOD((periodCount + 1), 65535); } else { t0 = 1; nmod = t0; } } function primitiveSynthesizeFrameIntoStartingAt() { var aKlattFrame; var buffer; var bufferOop; var rcvr; var startIndex; aKlattFrame = checkedFloatPtrOf(interpreterProxy.stackValue(2)); buffer = checkedShortPtrOf((bufferOop = interpreterProxy.stackValue(1))); startIndex = interpreterProxy.stackIntegerValue(0); if (interpreterProxy.failed()) { return null; } rcvr = interpreterProxy.stackObjectValue(3); if (!loadFrom(rcvr)) { return null; } interpreterProxy.success((SIZEOF(bufferOop) * 2) >= samplesPerFrame); if (interpreterProxy.failed()) { return null; } synthesizeFrameintostartingAt(aKlattFrame, buffer, startIndex); if (!saveTo(rcvr)) { return null; } interpreterProxy.pop(3); } function quphicosphisinphirphid(u, phi, cosphi, sinphi, rphid) { var expuphi; expuphi = Math.exp(u * phi); return (expuphi * ((((rphid * ((u * u) + 1.0)) + u) * sinphi) - cosphi)) + 1.0; } /* Convert formant frequencies and bandwidth into resonator difference equation coefficients. */ function resonatorfrequencybandwidth(index, freq, bw) { var a; var arg; var b; var c; var r; arg = ((0.0 - PI) / samplingRate) * bw; r = Math.exp(arg); c = 0.0 - (r * r); arg = ((PI * 2.0) / samplingRate) * freq; b = (r * Math.cos(arg)) * 2.0; a = (1.0 - b) - c; resonatorAput(index, a); resonatorBput(index, b); resonatorCput(index, c); } /* Convert formant frequencies and bandwidth into resonator difference equation coefficients. */ function resonatorfrequencybandwidthgain(index, freq, bw, gain) { resonatorfrequencybandwidth(index, freq, bw); resonatorAput(index, resonatorA(index) * gain); } function resonatorvalue(index, aFloat) { var answer; var p1; /* (p1 between: -100000 and: 100000) ifFalse: [self halt]. (answer between: -100000 and: 100000) ifFalse: [self halt]. */ answer = ((resonatorA(index) * aFloat) + (resonatorB(index) * ((p1 = resonatorP1(index))))) + (resonatorC(index) * resonatorP2(index)); resonatorP2put(index, p1); resonatorP1put(index, answer); return answer; } function resonatorA(index) { return resonators[(index * 5) - 5]; } function resonatorAput(index, aFloat) { resonators[(index * 5) - 5] = aFloat; } function resonatorB(index) { return resonators[(index * 5) - 4]; } function resonatorBput(index, aFloat) { resonators[(index * 5) - 4] = aFloat; } function resonatorC(index) { return resonators[(index * 5) - 3]; } function resonatorCput(index, aFloat) { resonators[(index * 5) - 3] = aFloat; } function resonatorP1(index) { return resonators[(index * 5) - 2]; } function resonatorP1put(index, aFloat) { resonators[(index * 5) - 2] = aFloat; } function resonatorP2(index) { return resonators[(index * 5) - 1]; } function resonatorP2put(index, aFloat) { resonators[(index * 5) - 1] = aFloat; } function rorark(roNumber, raNumber, rkNumber) { var cosphi; var d; var gamma; var gammapwr; var phi; var r; var ra; var rho; var rk; var ro; var rphid; var sinphi; var te; var theta; var u; te = ((t0 * roNumber)|0); ro = te / t0; rk = rkNumber; ra = raNumber; if (ra <= 0.0) { d = 1.0; } else { r = (1.0 - ro) / ra; d = 1.0 - (r / (Math.exp(r) - 1.0)); } phi = PI * (rk + 1.0); cosphi = Math.cos(phi); sinphi = Math.sin(phi); rphid = ((ra / ro) * phi) * d; u = zeroQphicosphisinphirphid(phi, cosphi, sinphi, rphid); theta = phi / te; rho = Math.exp(u * theta); a1 = (2.0 * Math.cos(theta)) * rho; a2 = 0.0 - (rho * rho); x2 = 0.0; x1 = rho * Math.sin(theta); gamma = Math.exp(-1.0 / (ra * t0)); gammapwr = Math.pow(gamma,(t0 - te)); b1 = gamma; c1 = ((1.0 - gamma) * gammapwr) / (1.0 - gammapwr); normalizeGlottalPulse(); } function saveTo(origKlattOop) { var a1Oop; var a2Oop; var b1Oop; var c1Oop; var glastOop; var klattOop; var nlastOop; var pitchOop; var vlastOop; var x1Oop; var x2Oop; interpreterProxy.pushRemappableOop(origKlattOop); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(pitch)); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(a1)); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(a2)); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(x1)); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(x2)); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(b1)); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(c1)); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(glast)); interpreterProxy.pushRemappableOop(interpreterProxy.floatObjectOf(vlast)); nlastOop = interpreterProxy.floatObjectOf(nlast); vlastOop = interpreterProxy.popRemappableOop(); glastOop = interpreterProxy.popRemappableOop(); c1Oop = interpreterProxy.popRemappableOop(); b1Oop = interpreterProxy.popRemappableOop(); x2Oop = interpreterProxy.popRemappableOop(); x1Oop = interpreterProxy.popRemappableOop(); a2Oop = interpreterProxy.popRemappableOop(); a1Oop = interpreterProxy.popRemappableOop(); pitchOop = interpreterProxy.popRemappableOop(); klattOop = interpreterProxy.popRemappableOop(); if (interpreterProxy.failed()) { return false; } interpreterProxy.storePointerofObjectwithValue(2, klattOop, pitchOop); interpreterProxy.storeIntegerofObjectwithValue(3, klattOop, t0); interpreterProxy.storeIntegerofObjectwithValue(4, klattOop, nper); interpreterProxy.storeIntegerofObjectwithValue(5, klattOop, nopen); interpreterProxy.storeIntegerofObjectwithValue(6, klattOop, nmod); interpreterProxy.storePointerofObjectwithValue(7, klattOop, a1Oop); interpreterProxy.storePointerofObjectwithValue(8, klattOop, a2Oop); interpreterProxy.storePointerofObjectwithValue(9, klattOop, x1Oop); interpreterProxy.storePointerofObjectwithValue(10, klattOop, x2Oop); interpreterProxy.storePointerofObjectwithValue(11, klattOop, b1Oop); interpreterProxy.storePointerofObjectwithValue(12, klattOop, c1Oop); interpreterProxy.storePointerofObjectwithValue(13, klattOop, glastOop); interpreterProxy.storePointerofObjectwithValue(14, klattOop, vlastOop); interpreterProxy.storePointerofObjectwithValue(15, klattOop, nlastOop); interpreterProxy.storeIntegerofObjectwithValue(16, klattOop, periodCount); interpreterProxy.storeIntegerofObjectwithValue(17, klattOop, samplesCount); interpreterProxy.storeIntegerofObjectwithValue(18, klattOop, seed); return interpreterProxy.failed() === false; } function setCurrentFrame(aKlattFrame) { var ampF1V; var ampF2F; var ampF2V; var ampF3F; var ampF3V; var ampF4F; var ampF4V; var ampF5F; var ampF6F; var ampFNV; var ampFTV; /* Fudge factors... */ frame = aKlattFrame; /* -4.44 dB */ ampFNV = linearFromdB(frame[Anv]) * 0.6; /* -4.44 dB */ ampFTV = linearFromdB(frame[Atv]) * 0.6; /* -7.96 dB */ ampF1V = linearFromdB(frame[A1v]) * 0.4; /* -16.5 dB */ ampF2V = linearFromdB(frame[A2v]) * 0.15; /* -24.4 dB */ ampF3V = linearFromdB(frame[A3v]) * 0.06; /* -28.0 dB */ ampF4V = linearFromdB(frame[A4v]) * 0.04; /* -16.5 dB */ ampF2F = linearFromdB(frame[A2f]) * 0.15; /* -24.4 dB */ ampF3F = linearFromdB(frame[A3f]) * 0.06; /* -28.0 dB */ ampF4F = linearFromdB(frame[A4f]) * 0.04; /* -33.2 dB */ ampF5F = linearFromdB(frame[A5f]) * 0.022; /* -30.5 dB */ /* Set coefficients of variable cascade resonators */ ampF6F = linearFromdB(frame[A6f]) * 0.03; if (cascade >= 8) { if (samplingRate >= 16000) { /* Inside Nyquist rate? */ resonatorfrequencybandwidth(R8c, 7500, 600); } else { cascade = 6; } } if (cascade >= 7) { if (samplingRate >= 16000) { /* Inside Nyquist rate? */ resonatorfrequencybandwidth(R7c, 6500, 500); } else { cascade = 6; } } if (cascade >= 6) { resonatorfrequencybandwidth(R6c, frame[F6], frame[B6]); } if (cascade >= 5) { resonatorfrequencybandwidth(R5c, frame[F5], frame[B5]); } resonatorfrequencybandwidth(R4c, frame[F4], frame[B4]); resonatorfrequencybandwidth(R3c, frame[F3], frame[B3]); resonatorfrequencybandwidth(R2c, frame[F2], frame[B2]); resonatorfrequencybandwidth(R1c, frame[F1], frame[B1]); resonatorfrequencybandwidth(Rnpc, frame[Fnp], frame[Bnp]); resonatorfrequencybandwidth(Rtpc, frame[Ftp], frame[Btp]); antiResonatorfrequencybandwidth(Rnz, frame[Fnz], frame[Bnz]); antiResonatorfrequencybandwidth(Rtz, frame[Ftz], frame[Btz]); resonatorfrequencybandwidthgain(Rnpp, frame[Fnp], frame[Bnp], ampFNV); resonatorfrequencybandwidthgain(Rtpp, frame[Ftp], frame[Btp], ampFTV); resonatorfrequencybandwidthgain(R1vp, frame[F1], frame[B1], ampF1V); resonatorfrequencybandwidthgain(R2vp, frame[F2], frame[B2], ampF2V); resonatorfrequencybandwidthgain(R3vp, frame[F3], frame[B3], ampF3V); resonatorfrequencybandwidthgain(R4vp, frame[F4], frame[B4], ampF4V); resonatorfrequencybandwidthgain(R2fp, frame[F2], frame[B2f], ampF2F); resonatorfrequencybandwidthgain(R3fp, frame[F3], frame[B3f], ampF3F); resonatorfrequencybandwidthgain(R4fp, frame[F4], frame[B4f], ampF4F); resonatorfrequencybandwidthgain(R5fp, frame[F5], frame[B5f], ampF5F); resonatorfrequencybandwidthgain(R6fp, frame[F6], frame[B6f], ampF6F); } /* Note: This is coded so that is can be run from Squeak. */ function setInterpreter(anInterpreter) { var ok; interpreterProxy = anInterpreter; ok = interpreterProxy.majorVersion() == VM_PROXY_MAJOR; if (ok === false) { return false; } ok = interpreterProxy.minorVersion() >= VM_PROXY_MINOR; return ok; } function synthesizeFrameintostartingAt(aKlattFrame, buffer, startIndex) { var ampGain; var aspiration; var aspirationNoise; var bypass; var friction; var frictionNoise; var gain; var glotout; var index; var noise; var out; var parGlotout; var parVoicing; var source; var temp; var top; var turbulence; var voice; var voicing; setCurrentFrame(aKlattFrame); if (pitch > 0) { voicing = linearFromdB(frame[Voicing] - 7); parVoicing = linearFromdB(frame[Voicing]); turbulence = linearFromdB(frame[Turbulence]) * 0.1; } else { voicing = (parVoicing = (turbulence = 0.0)); } friction = linearFromdB(frame[Friction]) * 0.25; aspiration = linearFromdB(frame[Aspiration]) * 0.05; /* -26.0 dB */ /* Flod overall gain into output resonator (low-pass filter) */ bypass = linearFromdB(frame[Bypass]) * 0.05; gain = frame[Gain] - 3; if (gain <= 0) { gain = 57; } ampGain = linearFromdB(gain); resonatorfrequencybandwidthgain(Rout, 0, samplingRate, ampGain); noise = nlast; index = startIndex; top = (samplesPerFrame + startIndex) - 1; while (index <= top) { /* Get low-passed random number for aspiration and friction noise */ /* radom number between -8196.0 and 8196.0 */ /* Tilt down noise spectrum by soft low-pass filter having a pole near the origin in the z-plane. */ noise = (nextRandom() - 32768) / 4.0; noise += 0.75 * nlast; /* Amplitude modulate noise (reduce noise amplitude during second half of glottal period) if voicing simultaneously present. */ nlast = noise; if (nper > nmod) { noise = noise * 0.5; } /* Compute voicing waveform. */ frictionNoise = friction * noise; voice = glottalSource(); /* Add turbulence during glottal open phase. Use random rather than noise because noise is low-passed. */ vlast = voice; if (nper < nopen) { voice += (turbulence * (nextRandom() - 32768)) / 4.0; } glotout = voicing * voice; /* Compute aspiration amplitude and add to voicing source. */ parGlotout = parVoicing * voice; aspirationNoise = aspiration * noise; glotout += aspirationNoise; /* Cascade vocal tract, excited by laryngeal sources. Nasal antiresonator, nasal resonator, trachearl antirresonator, tracheal resonator, then formants F8, F7, F6, F5, F4, F3, F2, F1. */ parGlotout += aspirationNoise; /* Voice-excited parallel vocal tract F1, F2, F3, F4, FNP and FTP. */ out = cascadeBranch(glotout); /* Source is voicing plus aspiration. */ source = parGlotout; /* Friction-excited parallel vocal tract formants F6, F5, F4, F3, F2, outputs added with alternating sign. Sound source for other parallel resonators is friction plus first difference of voicing waveform. */ out += parallelVoicedBranch(source); source = (frictionNoise + parGlotout) - glast; glast = parGlotout; /* Apply bypas and output low-pass filter */ out = parallelFrictionBranch(source) - out; out = (bypass * source) - out; out = resonatorvalue(Rout, out); temp = ((out * ampGain)|0); if (temp < -32768) { temp = -32768; } if (temp > 32767) { temp = 32767; } buffer[index - 1] = temp; ++index; ++samplesCount; } } /* Set the pitch. */ function voicedPitchSynchronousReset() { /* Add flutter and jitter (F0 perturbations). */ pitch = frame[F0]; addFlutter(); addJitter(); addFrequencyDiplophonia(); if (pitch < 0) { pitch = 0; } /* Duration of period before amplitude modulation. */ t0 = ((samplingRate / pitch)|0); nmod = t0; if (frame[Voicing] > 0) { nmod = nmod >> 1; } /* Set the LF glottal pulse model parameters. */ nopen = ((t0 * frame[Ro])|0); rorark(frame[Ro], frame[Ra], frame[Rk]); addShimmer(); addAmplitudeDiplophonia(); } function zeroQphicosphisinphirphid(phi, cosphi, sinphi, rphid) { var qa; var qb; var qc; var qzero; var ua; var ub; var uc; qzero = quphicosphisinphirphid(0, phi, cosphi, sinphi, rphid); if (qzero > 0) { ua = 0; ub = 1; qa = qzero; qb = quphicosphisinphirphid(ub, phi, cosphi, sinphi, rphid); while (qb > 0) { ua = ub; qa = qb; ub = ub * 2; qb = quphicosphisinphirphid(ub, phi, cosphi, sinphi, rphid); } } else { ua = -1; ub = 0; qa = quphicosphisinphirphid(ua, phi, cosphi, sinphi, rphid); qb = qzero; while (qa < 0) { ub = ua; qb = qa; ua = ua * 2; qa = quphicosphisinphirphid(ua, phi, cosphi, sinphi, rphid); } } while ((ub - ua) > Epsilon) { uc = (ub + ua) / 2.0; qc = quphicosphisinphirphid(uc, phi, cosphi, sinphi, rphid); if (qc > 0) { ua = uc; qa = qc; } else { ub = uc; qb = qc; } } return (ub + ua) / 2.0; } function registerPlugin() { if (typeof Squeak === "object" && Squeak.registerExternalModule) { Squeak.registerExternalModule("Klatt", { setInterpreter: setInterpreter, primitiveSynthesizeFrameIntoStartingAt: primitiveSynthesizeFrameIntoStartingAt, getModuleName: getModuleName, }); } else self.setTimeout(registerPlugin, 100); } registerPlugin(); })(); // Register module/plugin