Spaces:
Running
Running
/* 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() { | |
; | |
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 | |