scratch0-5 / plugins /Klatt.js
soiz1's picture
Upload folder using huggingface_hub
8f3f8db verified
/* 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