Click here to Skip to main content
15,884,628 members
Articles / Mobile Apps / iPhone

ESpeakEngine - Objective-C speech synthesizer

Rate me:
Please Sign up or sign in to vote.
4.80/5 (3 votes)
23 Jan 2012BSD2 min read 73.9K   3K   22  
ESpeakEngine - Objective-C speech synthesizer
  • ESpeakTest.zip
    • __MACOSX
    • ESpeakTest
      • .DS_Store
      • .git
        • branches
        • COMMIT_EDITMSG
        • config
        • description
        • HEAD
        • hooks
          • applypatch-msg.sample
          • commit-msg.sample
          • post-commit.sample
          • post-receive.sample
          • post-update.sample
          • pre-applypatch.sample
          • pre-commit.sample
          • prepare-commit-msg.sample
          • pre-rebase.sample
          • update.sample
        • index
        • info
          • exclude
        • logs
          • HEAD
          • refs
            • heads
              • master
        • objects
          • 00
            • e88867c94b8f6728422a4ad099a53a9f392cb7
          • 01
            • 477be5465c04d4cfd46ab95003f17445731d74
          • 02
            • 37597b848a1890bb30ba0ff4102f8107cafdcb
            • 6363f6a3bb9fe78b03b09f4d0fdce472b95e20
            • 69a98a29eb1baf79dd1f6f2bbc9370b9c4c9cb
            • 78ea2136d97866104e3789d7950d39632b5046
          • 03
            • 7b0f820ace631b85715dfb13cc21fe26daa44d
            • dac4f6baff6f5a2b06f5a68b6daa265c16e0a2
            • edde41daf54530ac1fe426e9349a5544b48ccc
          • 05
            • b2d0d21b687b4190600f6ea0206972c960dd1c
          • 06
            • 23379b22e1417ed806ff4c48337afbe9457cdf
          • 0c
            • 2d13a65548266d9c8a6758599c9a86faf53b28
          • 0d
            • 51695daffab058d065e942018f5c56067942fe
            • 6fa2a91273ee3271fb1d3202d7f6ad86379ef7
          • 10
            • e91b22ea1e6c67962cd858e8d03de74e7abf6f
          • 11
            • 8095eb5859b9c2ee14be00adeb87ee66eaec94
          • 12
            • 83826f9250bed7326aed2542a0e3c5b47edbec
            • ce1096a4ef6c4538a43ebd951dcaf2b624b717
          • 13
            • 664a34fe6a3b585603e00df15b17bcef3591e0
            • 93b3551c88468dccede7550726aae27a931555
          • 14
            • 1160885f6955ee4855933ce984bc117649d220
            • 417c1fdfdb3af16ef717d90a078f5c9b8468c3
          • 15
            • 96e3c77205e1688ad5968359106b5ea92d322a
          • 17
            • 004519410f433308228397abc30d2b69e55b26
          • 19
            • 3700525eaa0aa02256a4211c820007bb005995
            • da34a5b9b6e585ece12d4a6ec24341fa98f50c
            • fd69d3bec6857b0d4b29f4f26c03ac0dc727e3
          • 1a
            • 61238c5c772724cb12490eb555630bcc0e7870
            • 9e53b6e584bd1e8245f3fc69751211b7d4e86a
          • 1c
            • 2992dd5455746aef85905cc0293031e3e9ceaa
            • a6f6abadb2e86be2baf2f823a27d16c43d2528
          • 1e
            • 9a757f891fd7ece2ff350dc9225837cb7e70f7
          • 1f
            • 2eb929019174a9b4c2654c1398ed26aca50e2c
          • 20
            • 5e59c21f973ea13de6deab139efee2f171027a
          • 21
            • 4d6f9d708a7691c1abf13b0801ee9a54a44ae6
          • 22
            • a3b80f6954fd663b59f66210e7b658c5db3a3f
            • a95d18a3ead5d0274abab7986121dccafc1842
          • 23
            • 8c69126e18387f9c2b3d059db6d7df1cd91a6f
          • 25
            • 55d5d8bec5ee0524034d96ea5aa95eeb1a90dd
            • 5fe35ca3bf7c8743abf0f95518aae822aac4f0
            • bfdbf47ea384bd8118ed197a8842cb2104eb2a
            • d78c05ca841d2019f204184927282dc69ebd61
          • 28
            • 59e093f75f1f88ca412e0bde9345afc01f15ac
          • 29
            • 91e99d136fe8e13f7c0c99eaa27c8ca397186d
          • 2a
            • 736d4d3f3c3ffe36bea620d6c28b672efc5867
            • fb1adc71b7f4e90bd02355dd8cdb75e8d23870
          • 2e
            • 1534872410e5819a69396cdbb57225baa3a888
            • 9dd1f58881b69e931f3b5a73fef461eb9b838b
          • 30
            • 441d7e239ccd9169d15b04efc59be7a158a4a5
            • dea89200864b8e84dc0fec67850491d460a78d
          • 31
            • 02c9a1a9a5db99cadf90502de610f69c994913
            • bd479a3d5873c8a970de821a84d2addc864839
          • 32
            • 49dd4f8012e94af03784f043478ebab38fd0b7
          • 33
            • 00c360065de4a18e093dd02df3f6419b656f74
            • 430a22c186f11e5cf838e81dacb386a7e4c8d0
            • 8b8c450f3027ea5d3751fc1e0b4bf969cc1afc
          • 35
            • a4a3fc517a71ec8bad8f9d0c71bd9da960c494
          • 36
            • 665314753a98e11162485805608fe1aca7bc1e
            • 669d3f0592eaeb8465b81341b486a4c9c1eb11
            • a4bff6503dfb82fcdc7a160cc36f4cdd9e333d
          • 3a
            • f2aa1af75587b7a29685fa2dbbebbd2b3592c2
          • 3b
            • 105a7fb0f9b3bb28a87a7212dfcef08daf53c0
          • 3d
            • d75260a68d0fb7b88fe70d0e3e73c916b963e5
          • 3e
            • 520ec5c8b88db8f95f6a230273278fd39bfbd6
          • 41
            • 22d96b39bf2bc1025a1c57ef01b8b03936773d
          • 42
            • dbdc5586bc89d681d23851f4a5aafd79b414cb
            • de58882d0c80e94597b575893afc8e99bd431e
          • 46
            • 07dd079dd2748f8e9cde034268e6cd68278644
            • 317618d912082d6070e4e3972809824bd35395
          • 47
            • 7b28ff8f86a3158a71c4934fbd3a2456717d7a
          • 4b
            • 6a9ae550599ea85d77fea7c0f71b4d5aaf1ba8
          • 4c
            • 6239268d21312d311a504ad0d8aeb0e4f1030b
          • 4d
            • ec15997c4e00c7a764156687431ac8c47676a5
          • 4e
            • 2b9d23e84059b93883e1a0c0f7a859a23b087e
          • 4f
            • 1904e5164410f93689beb55d46901b214271fe
            • 8f5e88f436d478b126c5c4eccf3568e398c26f
            • e4188e53b10cc21b50c3bf47e9ef3b2fc4c641
          • 50
            • 1b5a4a8620d5bd9a545c8941cdcbd565fca1c6
          • 52
            • 1be164ce6c87e1d6df58fd82ab160c8f6255db
            • 692c38546eb82aee2a7550c93798f70f02dc9a
            • c5ac93561331143a9caea14d6c0f008216b4e9
          • 53
            • 6957cb8fe03bde580784e6f97537ec3444e9c3
            • 7beb3ba82da8af147f028685e61fc839cad713
            • c2a70482993f53d6df321687b5cc4d9e95abc1
            • cb31446e077a5f159c831e126a0e3f9a2d0ed2
          • 56
            • 9f9d05432267a13b75ca2562beb85e1e1c17db
          • 58
            • 1cd883fed6aa3b84b580a543b6ec8998f4d327
          • 5a
            • 24e11ad4dc2842c79033ad323f02e2e6c2f566
            • 85640ee385afef9b9dc9b7d2889d47b81aa1bd
          • 5c
            • 3583da4700ab6982766d187d1195b37f9a3fb5
          • 5e
            • bb6a35716f489f249db8bb0e9df7dde150eba4
          • 5f
            • 3297d3a2009a6051a8ebc606bc674056ea03fc
          • 61
            • 124ff298a7d392b816cb1a71095ed1ec8ffe6b
          • 65
            • 3c3f5c4a2d2e44b8a188b88b64278085ebde27
          • 68
            • 1cad9627cb3af687a30507f05114c89ef9340f
          • 69
            • cceefb779a5236074db6871d7523d92f8a709f
          • 6a
            • 8d5efd87553a3f0e977636c6b819cddf3a99e7
            • cadba6aea97cd920745428a1c4ccd998581cc7
          • 6c
            • 65e3c6851f204d9c4cd9b616b46a9ff425b3c2
          • 6d
            • 826477b6ee1ecb3e502ffe3c26387d1bce3961
          • 6e
            • 11c93121ab5d535e4f2d50253ee4a527694a9f
          • 71
            • 99341c34f93f5fa5219ff479e82edaee5d7936
            • ecab7197ec9646efdae05bb02b465f5b5e361a
          • 73
            • ac62a4ab12374bbf6f72539b2e104d10d7d394
          • 74
            • 00c07a5c17fbbead0d252a22f1fcdb6e5f15c4
            • 0601d129aa08fd59be839301c923b684361dbe
          • 79
            • 2d8a9f9ef248c4358c36000722ba0c53a76497
          • 7c
            • bdab338114c51e83e0b54c67280b91872211d5
          • 7d
            • 276eb2b779d73c46d8ed97e4be287bec96c828
          • 7e
            • 6c16a2c28e97392d20d4f4c243ecd6f6f40a91
            • f93a5edd61fddc97d982242d7654e5ab07a09e
          • 7f
            • 4631899e208f50b855ad579b726eadea70f67d
            • fccbe6dd68c968e78da5b6265a13c62c1fc639
          • 82
            • 2c9a312addee71797811c17690f2be8746bea4
            • 98f98722e5f5f405e9631eb4a5064d87114424
          • 83
            • 71a46410d32c3f000db4c7b11254f48a3d6055
          • 84
            • 79e658ebe74cdd0b9525a41dededf8b9839858
            • ccc3a6d4681e19dbe6b982ddcee2e760944d55
          • 85
            • ebb03e3089c5055e4f76d272866738a90a7842
          • 88
            • 1634035cad7fbc213a9def0b5e5ef7f15dffa2
            • 48d6820e826b907349234a642535725247f837
          • 89
            • 28f0ff69aa677f7c5f96053ca70589552e17b0
            • e6c82914aa9457a644d5a498fa643f98b9ade3
          • 8f
            • c65d4bab0f132f34e70868a961188deabc55dc
            • d4a63a1a24c8b25eab5ed28c135457a8332e6b
          • 92
            • 3d517415d489cc9b3f91638c14264dd0df55a3
            • a1582817dc2f8256db5a02bed320a05f6e5e43
          • 95
            • 8799c61770d05ba341183cd2d6a107a1ec093c
          • 96
            • 35ac150af1804b398d67cf4703d718a16806a7
          • 97
            • 8ec49ed00c46862d89580efe68f7efd98c93c3
            • a337d34bb9ab89812b5e79c3bc2bb784d48953
          • 98
            • 9f9eab7b5ee98f4b6acf35fe8b4ef86db3a62e
          • 9b
            • 06e0bd24aa4658ed8009be3e2fe7e32ccee54e
            • 280bf8bc106ca904c9b33a90d0822c4c9b03fd
            • 2d891f12030afadc1e737914a1759ab59ef01f
            • a872a49ab896e3d7c6203bedfd2502d8cb6521
            • c60c7cbd38db3307551ae17ef2a8a5d623b3a0
          • 9d
            • e1630d90e22bf6df53a0093c212e9e1d7da9b6
            • eba8432350a07d0ab15189bb124d48b836fb62
          • 9e
            • 9c4e7476f3dce3b6808b0c8ea917a4d8503d7f
          • a3
            • 72fb170d6218ccc7298335f1ea55ff674fb3cc
          • a5
            • 4cb02cd26c7ecc2bd08debb1cfe85c3546c039
            • 504505ef08ce6040091e48eb5c1653a34574b0
          • a6
            • 56d2c7f2e9509fef687b3174282f6ec9b61498
            • e0f46bb57f876255cdb5767729aefccbe3a33e
          • a7
            • a8223dbda4d4cd47ae8796ad2be9bc70e46754
          • a9
            • 09e1af21f9dc9dccf095d02920266ea11fe7f5
            • 0c7b72565da6e015014e343f10ae50197587c9
          • aa
            • 80edaad05f0f16c6195e72a0130d803b58bcbc
          • ae
            • 76a4c4deb77d53e7ee512c3e85f45ba802dd08
            • 9247d41055f6721d3500645539ee00ae29d7e4
            • a3d895c09d5eae5411aec5fb5ecbe82451bd50
          • b0
            • d4979c857d151ef5cd27248926fb112c0c3cee
          • b1
            • a874be65ad7df189c933f4c576475f29d15f67
          • b2
            • 7a8114a03ed27348a40f37428107e02f67acc8
            • fd9d084c6df70da314916ee674421872f9ef50
          • b3
            • 2b6a6660b12a14fc5e8749eff9ba696b7f6061
          • b4
            • 8b1788b979853cdd57bb6cec6b9cc4dd7925bc
          • b7
            • 39a86e488eeec6f5693b7ee2590f84d6c95191
          • b8
            • 519559d3db834193518d4f4c4fed777734c8ee
            • 6f59306a576f4548ff3bd62e344570cc538932
            • f782946f4728a629eda8038e82dd165dadee1d
          • ba
            • 7c42cc48ae095ccfffeb03cf36d519d7cbe5a3
          • bc
            • bb2a0058b7866064b779ae246244c5342a0ccb
          • bd
            • 336a9884877889e2f85ee1849f8a068d2c6279
          • be
            • 1b6246a01d3d9c01dac0f888454369e0b32892
          • c0
            • a5475ece89c3274e62f9132560ec8afdd569d4
          • c2
            • 34f46877a761d5c98fda2cbbeb172dc2efc81a
            • 76bec0dd56b68a8e0ed0062b38dd149422b45d
          • c3
            • 2db3968df0779b3c3a47899085625a7b86339b
          • c6
            • 32e263c2a639311be4ca1512aadee97a91bc9a
          • cb
            • c4fb3a5d3dcc07f26b5ca02eb53a52b897aa80
          • cd
            • 02abedb89d8975a792d73de536d2ce82260553
          • ce
            • 800f70be34d9fba11f7d09b0c329b3f259507b
          • cf
            • 584b7dd3f005be3cffb47d27f1bfe980a6e53b
            • f13bac9dd46f2c2a2fb66db64ce78caffd5b5a
          • d0
            • 2b035cae9b12c66a5e0d5ae9cf57433041ed40
            • 864f3d6209ad6f3e8ab51dc880836e67c96fc5
            • b729579de2537a63cebdb809e8bdfb5a897a33
          • d2
            • 5865608d7d973e77c77d13bbdbe3ae454d864d
          • d3
            • d7720074a2fc7e3bfbc18cc1bacad0f9ea61d2
          • d5
            • 06e7f9f85667d054794f808f9098b2a1625372
            • 9fe79529970f627e83857f9bd516f5474bf685
          • d6
            • 737d787752a799349095b49cf81024dfd00fb6
            • 811d3ae4f710d3eb8a16c690cd42bebc4faf4e
          • d7
            • 59cfdf018f8814d995588d176dadde0820b5ca
          • d8
            • ecd252c04bc00a6dcc6d0b84d64285726b65d4
            • f35efaa2dc2293277365d811c9b6222cfe59b8
          • da
            • c1e4d0643b01e99052f575b5f6add2e10a2143
            • ef5160c9c1500d3a9f6b0eadf434ef702a009f
          • db
            • 63d6ca3d87629e693327a2ba4a719e79847b6c
            • de212341a0b131224b3e123f91d154348070ba
          • dc
            • 51396ce24aad46d1c761e2c96f8aee68d4b622
          • de
            • 4786c94cfa90c84982ca06a2a9623035993dfc
          • df
            • 70f4387ca97d30c66d7dc87d5abca9b0ffa820
            • 7fa77bc23477530674f05f4f619803983d5eb0
          • e0
            • 783ec3b1e38ce0f77b5b018d9b8641a7b924c3
            • ea6d6394ab8409463adfeb753f1632ef09a47f
          • e4
            • 16c6dc5e784243ad8d33000139178fa178de87
            • 1d3105c048e789fe605c780efe2881df833ea8
          • e7
            • 178e4d5666a3b75aa48de33b966f0590665a8e
          • e8
            • 5978c76abd7430436356cd2a126018642d6a2d
          • ea
            • dd707322e08d90e3a2208aef9060706c340799
          • eb
            • d92ffb3ec9499292d1faa7ca60adcc5edac74f
          • ed
            • 05f4240da98a569e3c9f9a5b9e2301d7caa79e
          • ee
            • 3bd233e2bc458aab63eb36f613f853f72e6bf7
          • f2
            • 033dc11fee0a1db4a2cae358c1a808149a5aa2
            • 130ba4f980783f8605eb50387ffc2e54f66b3c
          • f3
            • 10f868efea6408fc49fd4e6d6c293db2098114
            • e97b52355ea6f5384790bb3cda677222be900c
          • f4
            • 3ef84fa6caf08bc6e9e442e15d71eaa8c6962a
            • ede3296c4fb294a58715e61ecef26f74ed898a
          • f5
            • 0e89c905a3e8dd519f415585283757fc85d2d6
          • f9
            • 624b31623b500b57b74e9765ac7a2d9f039c65
          • fa
            • 4eece0b1cc7dababed3d09d560f38e00ea8755
          • fc
            • 377156b487a559efb384ec2b6e551d6c2085c6
            • 60f41672c8fb6fc69c1548552988f046a2aa14
          • fe
            • 7c4d8d002499fbaff530adfaa0543d626536dd
          • ff
            • a94206372e46914dcadeb10c212a9674daf62e
          • info
          • pack
        • refs
          • heads
            • master
          • tags
      • ESpeakTest.xcodeproj
        • project.pbxproj
        • project.xcworkspace
          • contents.xcworkspacedata
          • xcuserdata
            • jozefbozek.xcuserdatad
              • UserInterfaceState.xcuserstate
        • xcuserdata
      • ESpeakTest
      • ESpeakTestTests
  • eSpeak_1.0.zip
/***************************************************************************
 *   Copyright (C) 2008 by Jonathan Duddington                             *
 *   email: jonsd@users.sourceforge.net                                    *
 *                                                                         *
 *   Based on a re-implementation by:                                      *
 *   (c) 1993,94 Jon Iles and Nick Ing-Simmons                             *
 *   of the Klatt cascade-parallel formant synthesizer                     *
 *                                                                         *
 *   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:                                 *
 *               <http://www.gnu.org/licenses/>.                           *
 ***************************************************************************/

// See URL: ftp://svr-ftp.eng.cam.ac.uk/pub/comp.speech/synthesis/klatt.3.04.tar.gz  

#include "StdAfx.h"

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#include "speak_lib.h"
#include "speech.h"
#include "klatt.h"
#include "phoneme.h"
#include "synthesize.h"
#include "voice.h"

#ifdef INCLUDE_KLATT    // conditional compilation for the whole file

extern unsigned char *out_ptr;   // **JSD
extern unsigned char *out_start;
extern unsigned char *out_end;
extern WGEN_DATA wdata;
static int nsamples;
static int sample_count;


#ifdef _MSC_VER
#define getrandom(min,max) ((rand()%(int)(((max)+1)-(min)))+(min))
#else
#define getrandom(min,max) ((rand()%(long)(((max)+1)-(min)))+(min))
#endif


/* function prototypes for functions private to this file */

static void flutter(klatt_frame_ptr);
static double sampled_source (void);
static double impulsive_source (void);
static double natural_source (void);
static void pitch_synch_par_reset (klatt_frame_ptr); 
static double gen_noise (double);
static double DBtoLIN (long);
static void frame_init (klatt_frame_ptr); 
static void setabc (long,long,resonator_ptr);
static void setzeroabc (long,long,resonator_ptr);

static klatt_frame_t  kt_frame;
static klatt_global_t kt_globals;

/*
function RESONATOR

This is a generic resonator function. Internal memory for the resonator
is stored in the globals structure.
*/

static double resonator(resonator_ptr r, double input)
{
	double x;
	
	x = (double) ((double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2);
	r->p2 = (double)r->p1;
	r->p1 = (double)x;

	return (double)x;
}

static double resonator2(resonator_ptr r, double input)
{
	double x;
	
	x = (double) ((double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2);
	r->p2 = (double)r->p1;
	r->p1 = (double)x;
	
	r->a += r->a_inc;
	r->b += r->b_inc;
	r->c += r->c_inc;
	return (double)x;
}



/* 
function ANTIRESONATOR

This is a generic anti-resonator function. The code is the same as resonator 
except that a,b,c need to be set with setzeroabc() and we save inputs in 
p1/p2 rather than outputs. There is currently only one of these - "rnz"
Output = (rnz.a * input) + (rnz.b * oldin1) + (rnz.c * oldin2) 
*/

#ifdef deleted
static double antiresonator(resonator_ptr r, double input)
{
	register double x = (double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2;
	r->p2 = (double)r->p1;
	r->p1 = (double)input;
	return (double)x;
}
#endif

static double antiresonator2(resonator_ptr r, double input)
{
	register double x = (double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2;
	r->p2 = (double)r->p1;
	r->p1 = (double)input;
	
	r->a += r->a_inc;
	r->b += r->b_inc;
	r->c += r->c_inc;
	return (double)x;
}



/*
function FLUTTER

This function adds 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.
*/

static void flutter(klatt_frame_ptr frame)
{
	static int time_count;
	double delta_f0;
	double fla,flb,flc,fld,fle;
	
	fla = (double) kt_globals.f0_flutter / 50;
	flb = (double) kt_globals.original_f0 / 100;
//	flc = sin(2*PI*12.7*time_count);
//	fld = sin(2*PI*7.1*time_count);
//	fle = sin(2*PI*4.7*time_count);
	flc = sin(PI*12.7*time_count);  // because we are calling flutter() more frequently, every 2.9mS
	fld = sin(PI*7.1*time_count);
	fle = sin(PI*4.7*time_count);
	delta_f0 =  fla * flb * (flc + fld + fle) * 10;
	frame->F0hz10 = frame->F0hz10 + (long) delta_f0;
	time_count++;
}



/*
function SAMPLED_SOURCE

Allows the use of a glottal excitation waveform sampled from a real
voice.
*/

static double sampled_source()
{
	int itemp;
	double ftemp;
	double result;
	double diff_value;
	int current_value;
	int next_value;
	double temp_diff;
	
	if(kt_globals.T0!=0)
	{
		ftemp = (double) kt_globals.nper;
		ftemp = ftemp / kt_globals.T0;
		ftemp = ftemp * kt_globals.num_samples;
		itemp = (int) ftemp;
	
		temp_diff = ftemp - (double) itemp;
	
		current_value = kt_globals.natural_samples[itemp];
		next_value = kt_globals.natural_samples[itemp+1];
	
		diff_value = (double) next_value - (double) current_value;
		diff_value = diff_value * temp_diff;
	
		result = kt_globals.natural_samples[itemp] + diff_value;
		result = result * kt_globals.sample_factor;
	}
	else
	{
		result = 0;
	}
	return(result);
}




/* 
function PARWAVE

Converts synthesis parameters to a waveform.
*/


static int parwave(klatt_frame_ptr frame) 
{
	double temp;
	int value;
	double outbypas;
	double out;
	long n4;
	double frics;
	double glotout;
	double aspiration;
	double casc_next_in;
	double par_glotout;
	static double noise;
	static double voice;
	static double vlast;
	static double glotlast;
	static double sourc;
	int ix;

	flutter(frame);  /* add f0 flutter */

#ifdef LOG_FRAMES
if(option_log_frames)
{
	FILE *f;
	f=fopen("log-klatt","a");
	fprintf(f,"%4dhz %2dAV %4d %3d, %4d %3d, %4d %3d, %4d %3d, %4d, %3d, FNZ=%3d TLT=%2d\n",frame->F0hz10,frame->AVdb,
	frame->Fhz[1],frame->Bhz[1],frame->Fhz[2],frame->Bhz[2],frame->Fhz[3],frame->Bhz[3],frame->Fhz[4],frame->Bhz[4],frame->Fhz[5],frame->Bhz[5],frame->Fhz[0],frame->TLTdb);
	fclose(f);
}
#endif

	/* MAIN LOOP, for each output sample of current frame: */

	for (kt_globals.ns=0; kt_globals.ns<kt_globals.nspfr; kt_globals.ns++) 
	{
		/* Get low-passed random number for aspiration and frication noise */
		noise = gen_noise(noise);

		/*
		Amplitude modulate noise (reduce noise amplitude during
		second half of glottal period) if voicing simultaneously present.
		*/
	
		if (kt_globals.nper > kt_globals.nmod) 
		{
			noise *= (double) 0.5;
		}
	
		/* Compute frication noise */
		frics = kt_globals.amp_frica * noise;
	
		/*
			Compute voicing waveform. Run glottal source simulation at 4 
			times normal sample rate to minimize quantization noise in 
			period of female voice.
		*/
	
		for (n4=0; n4<4; n4++) 
		{
			switch(kt_globals.glsource)
			{
			case IMPULSIVE:
				voice = impulsive_source();
				break;
			case NATURAL:
				voice = natural_source();	
				break;
			case SAMPLED:
				voice = sampled_source();
				break;
			}
	
			/* Reset period when counter 'nper' reaches T0 */
			if (kt_globals.nper >= kt_globals.T0) 
			{
				kt_globals.nper = 0;
				pitch_synch_par_reset(frame);
			}
	
			/*
			Low-pass filter voicing waveform before downsampling from 4*samrate
			to samrate samples/sec.  Resonator f=.09*samrate, bw=.06*samrate 
			*/
	
			voice = resonator(&(kt_globals.rsn[RLP]),voice);
	
			/* Increment counter that keeps track of 4*samrate samples per sec */
			kt_globals.nper++;
		}
	
		/*
			Tilt spectrum of voicing source down by soft low-pass filtering, amount
			of tilt determined by TLTdb
		*/
	
		voice = (voice * kt_globals.onemd) + (vlast * kt_globals.decay);
		vlast = voice;
	
		/* 
			Add breathiness during glottal open phase. Amount of breathiness 
			determined by parameter Aturb Use nrand rather than noise because 
			noise is low-passed. 
		*/
	
	
		if (kt_globals.nper < kt_globals.nopen) 
		{
			voice += kt_globals.amp_breth * kt_globals.nrand;
		}
	
		/* Set amplitude of voicing */
		glotout = kt_globals.amp_voice * voice;
		par_glotout = kt_globals.par_amp_voice * voice;
	
		/* Compute aspiration amplitude and add to voicing source */
		aspiration = kt_globals.amp_aspir * noise;
		glotout += aspiration;
	
		par_glotout += aspiration;
	
		/*  
			Cascade vocal tract, excited by laryngeal sources.
			Nasal antiresonator, then formants FNP, F5, F4, F3, F2, F1 
		*/

		out=0;
		if(kt_globals.synthesis_model != ALL_PARALLEL)
		{
			casc_next_in = antiresonator2(&(kt_globals.rsn[Rnz]),glotout);
			casc_next_in = resonator(&(kt_globals.rsn[Rnpc]),casc_next_in);
			casc_next_in = resonator(&(kt_globals.rsn[R8c]),casc_next_in);
			casc_next_in = resonator(&(kt_globals.rsn[R7c]),casc_next_in);
			casc_next_in = resonator(&(kt_globals.rsn[R6c]),casc_next_in);
			casc_next_in = resonator2(&(kt_globals.rsn[R5c]),casc_next_in);
			casc_next_in = resonator2(&(kt_globals.rsn[R4c]),casc_next_in);
			casc_next_in = resonator2(&(kt_globals.rsn[R3c]),casc_next_in);
			casc_next_in = resonator2(&(kt_globals.rsn[R2c]),casc_next_in);
			out = resonator2(&(kt_globals.rsn[R1c]),casc_next_in);
		}
	
		/* Excite parallel F1 and FNP by voicing waveform */
		sourc = par_glotout;        /* Source is voicing plus aspiration */

		/*
			Standard parallel vocal tract Formants F6,F5,F4,F3,F2, 
			outputs added with alternating sign. Sound source for other 
			parallel resonators is frication plus first difference of 
			voicing waveform. 
		*/
	
		out += resonator(&(kt_globals.rsn[R1p]),sourc);
		out += resonator(&(kt_globals.rsn[Rnpp]),sourc);
	
		sourc = frics + par_glotout - glotlast;
		glotlast = par_glotout;

		for(ix=R2p; ix<=R6p; ix++)
		{
			out = resonator(&(kt_globals.rsn[ix]),sourc) - out;
		}
	
		outbypas = kt_globals.amp_bypas * sourc;
	
		out = outbypas - out;

#ifdef deleted
// for testing
		if (kt_globals.outsl != 0) 
		{
			switch(kt_globals.outsl)
			{
			case 1:
				out = voice;
				break;
			case 2:
				out = aspiration;
				break;
			case 3: 
				out = frics;
				break;
			case 4:
				out = glotout;
				break;
			case 5:
				out = par_glotout;
				break;
			case 6:
				out = outbypas;
				break;
			case 7:
				out = sourc;
				break;
			}
		}
#endif

		out = resonator(&(kt_globals.rsn[Rout]),out);
		temp = (int)(out * wdata.amplitude * kt_globals.amp_gain0) ;   /* Convert back to integer */


		// mix with a recorded WAV if required for this phoneme
		{
			int z2;
			signed char c;
			int sample;
	
			z2 = 0;
			if(wdata.mix_wavefile_ix < wdata.n_mix_wavefile)
			{
				if(wdata.mix_wave_scale == 0)
				{
					// a 16 bit sample
					c = wdata.mix_wavefile[wdata.mix_wavefile_ix+1];
					sample = wdata.mix_wavefile[wdata.mix_wavefile_ix] + (c * 256);
					wdata.mix_wavefile_ix += 2;
				}
				else
				{
					// a 8 bit sample, scaled
					sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_ix++] * wdata.mix_wave_scale;
				}
				z2 = sample * wdata.amplitude_v / 1024;
				z2 = (z2 * wdata.mix_wave_amp)/40;
				temp += z2;
			}
		}

		// if fadeout is set, fade to zero over 64 samples, to avoid clicks at end of synthesis
		if(kt_globals.fadeout > 0)
		{
			kt_globals.fadeout--;
			temp = (temp * kt_globals.fadeout) / 64;
		}

		value = (int)temp + ((echo_buf[echo_tail++]*echo_amp) >> 8);
		if(echo_tail >= N_ECHO_BUF)
			echo_tail=0;

		if (value < -32768)
		{
			value = -32768;
		}
	
		if (value > 32767)
		{
			value =  32767;
		}

		*out_ptr++ = value;
		*out_ptr++ = value >> 8;

		echo_buf[echo_head++] = value;
		if(echo_head >= N_ECHO_BUF)
			echo_head = 0;

		sample_count++;
		if(out_ptr >= out_end)
		{
			return(1);
		}
	}
	return(0);
}  //  end of parwave





void KlattReset(int control)
{
	int r_ix;

	if(control == 2)
	{
		//Full reset
		kt_globals.FLPhz = (950 * kt_globals.samrate) / 10000;
		kt_globals.BLPhz = (630 * kt_globals.samrate) / 10000;
		kt_globals.minus_pi_t = -PI / kt_globals.samrate;
		kt_globals.two_pi_t = -2.0 * kt_globals.minus_pi_t;
		setabc(kt_globals.FLPhz,kt_globals.BLPhz,&(kt_globals.rsn[RLP]));

	}

	if(control > 0)
	{
		kt_globals.nper = 0;
		kt_globals.T0 = 0;
		kt_globals.nopen = 0;
		kt_globals.nmod = 0;

		for(r_ix=RGL; r_ix < N_RSN; r_ix++)
		{
			kt_globals.rsn[r_ix].p1 = 0;
			kt_globals.rsn[r_ix].p2 = 0;
		}

	}

	for(r_ix=0; r_ix <= R6p; r_ix++)
	{
		kt_globals.rsn[r_ix].p1 = 0;
		kt_globals.rsn[r_ix].p2 = 0;
	}
}


/* 
function FRAME_INIT

Use parameters from the input frame to set up resonator coefficients.
*/

static void frame_init(klatt_frame_ptr frame) 
{
	double amp_par[7];
	static double amp_par_factor[7] = {0.6, 0.4, 0.15, 0.06, 0.04, 0.022, 0.03};
	long Gain0_tmp;
	int ix;

	kt_globals.original_f0 = frame->F0hz10 / 10;
	
	frame->AVdb_tmp  = frame->AVdb - 7;
	if (frame->AVdb_tmp < 0)
	{
		frame->AVdb_tmp = 0;
	}
	
	kt_globals.amp_aspir = DBtoLIN(frame->ASP) * 0.05;
	kt_globals.amp_frica = DBtoLIN(frame->AF) * 0.25;
	kt_globals.par_amp_voice = DBtoLIN(frame->AVpdb);
	kt_globals.amp_bypas = DBtoLIN(frame->AB) * 0.05;

	for(ix=0; ix <= 6; ix++)
	{
		// parallel amplitudes F1 to F6, and parallel nasal pole
		amp_par[ix] = DBtoLIN(frame->Ap[ix]) * amp_par_factor[ix];
	}

	Gain0_tmp = frame->Gain0 - 3;
	if (Gain0_tmp <= 0) 
	{
		Gain0_tmp = 57;
	}
	kt_globals.amp_gain0 = DBtoLIN(Gain0_tmp) / kt_globals.scale_wav;
	
	/* Set coefficients of variable cascade resonators */
	for(ix=1; ix<=9; ix++)
	{
		// formants 1 to 8, plus nasal pole
		setabc(frame->Fhz[ix],frame->Bhz[ix],&(kt_globals.rsn[ix]));

		if(ix <= 5)
		{
			setabc(frame->Fhz_next[ix],frame->Bhz_next[ix],&(kt_globals.rsn_next[ix]));
	
			kt_globals.rsn[ix].a_inc = (kt_globals.rsn_next[ix].a - kt_globals.rsn[ix].a) / 64.0;
			kt_globals.rsn[ix].b_inc = (kt_globals.rsn_next[ix].b - kt_globals.rsn[ix].b) / 64.0;
			kt_globals.rsn[ix].c_inc = (kt_globals.rsn_next[ix].c - kt_globals.rsn[ix].c) / 64.0;
		}
	}

	// nasal zero anti-resonator
	setzeroabc(frame->Fhz[F_NZ],frame->Bhz[F_NZ],&(kt_globals.rsn[Rnz]));
	setzeroabc(frame->Fhz_next[F_NZ],frame->Bhz_next[F_NZ],&(kt_globals.rsn_next[Rnz]));
	kt_globals.rsn[F_NZ].a_inc = (kt_globals.rsn_next[F_NZ].a - kt_globals.rsn[F_NZ].a) / 64.0;
	kt_globals.rsn[F_NZ].b_inc = (kt_globals.rsn_next[F_NZ].b - kt_globals.rsn[F_NZ].b) / 64.0;
	kt_globals.rsn[F_NZ].c_inc = (kt_globals.rsn_next[F_NZ].c - kt_globals.rsn[F_NZ].c) / 64.0;

	
	/* Set coefficients of parallel resonators, and amplitude of outputs */
	
	for(ix=0; ix<=6; ix++)
	{
		setabc(frame->Fhz[ix],frame->Bphz[ix],&(kt_globals.rsn[Rparallel+ix]));
		kt_globals.rsn[Rparallel+ix].a *= amp_par[ix];
	}
	
	/* output low-pass filter */
	
	setabc((long)0.0,(long)(kt_globals.samrate/2),&(kt_globals.rsn[Rout]));
	
}



/*
function IMPULSIVE_SOURCE

Generate a low pass filtered train of impulses as an approximation of 
a natural excitation waveform. Low-pass filter the differentiated impulse 
with a critically-damped second-order filter, time constant proportional 
to Kopen.
*/


static double impulsive_source() 
{
	static double doublet[] = {0.0,13000000.0,-13000000.0};
	static double vwave;
	
	if (kt_globals.nper < 3) 
	{
		vwave = doublet[kt_globals.nper];
	}
	else 
	{
		vwave = 0.0;
	}
	
	return(resonator(&(kt_globals.rsn[RGL]),vwave));
}



/*
function NATURAL_SOURCE

Vwave is the differentiated glottal flow waveform, there is a weak
spectral zero around 800 Hz, magic constants a,b reset pitch synchronously.
*/

static double natural_source() 
{
	double lgtemp;
	static double vwave;
	
	if (kt_globals.nper < kt_globals.nopen) 
	{
		kt_globals.pulse_shape_a -= kt_globals.pulse_shape_b;
		vwave += kt_globals.pulse_shape_a;
		lgtemp=vwave * 0.028;
	
		return(lgtemp);
	}
	else 
	{
		vwave = 0.0;
		return(0.0);
	}
}





/*
function PITCH_SYNC_PAR_RESET

Reset selected parameters pitch-synchronously.


Constant B0 controls shape of glottal pulse as a function
of desired duration of open phase N0
(Note that N0 is specified in terms of 40,000 samples/sec of speech)

Assume voicing waveform V(t) has form: k1 t**2 - k2 t**3

  If the radiation characterivative, a temporal derivative
  is folded in, and we go from continuous time to discrete
  integers n:  dV/dt = vwave[n]
                        = sum over i=1,2,...,n of { a - (i * b) }
                        = a n  -  b/2 n**2

  where the  constants a and b control the detailed shape
  and amplitude of the voicing waveform over the open
  potion of the voicing cycle "nopen".

  Let integral of dV/dt have no net dc flow --> a = (b * nopen) / 3
 
  Let maximum of dUg(n)/dn be constant --> b = gain / (nopen * nopen)
  meaning as nopen gets bigger, V has bigger peak proportional to n

  Thus, to generate the table below for 40 <= nopen <= 263:
  
  B0[nopen - 40] = 1920000 / (nopen * nopen)
*/

static void pitch_synch_par_reset(klatt_frame_ptr frame) 
{
	long temp;
	double temp1;
	static long skew;
	static short B0[224] = 
	{
		1200,1142,1088,1038, 991, 948, 907, 869, 833, 799, 768, 738, 710, 683, 658,
		634, 612, 590, 570, 551, 533, 515, 499, 483, 468, 454, 440, 427, 415, 403,
		391, 380, 370, 360, 350, 341, 332, 323, 315, 307, 300, 292, 285, 278, 272,
		265, 259, 253, 247, 242, 237, 231, 226, 221, 217, 212, 208, 204, 199, 195,
		192, 188, 184, 180, 177, 174, 170, 167, 164, 161, 158, 155, 153, 150, 147,
		145, 142, 140, 137, 135, 133, 131, 128, 126, 124, 122, 120, 119, 117, 115, 
		113,111, 110, 108, 106, 105, 103, 102, 100, 99, 97, 96, 95, 93, 92, 91, 90,
		88, 87, 86, 85, 84, 83, 82, 80, 79, 78, 77, 76, 75, 75, 74, 73, 72, 71,
		70, 69, 68, 68, 67, 66, 65, 64, 64, 63, 62, 61, 61, 60, 59, 59, 58, 57, 
		57, 56, 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48,
		47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 41, 41, 40, 40,
		39, 39, 38, 38, 38, 38, 37, 37, 36, 36, 36, 36, 35, 35, 35, 35, 34, 34,33,
		33, 33, 33, 32, 32, 32, 32, 31, 31, 31, 31, 30, 30, 30, 30, 29, 29, 29, 29,
		28, 28, 28, 28, 27, 27
	};
	
	if (frame->F0hz10 > 0) 
	{
		/* T0 is 4* the number of samples in one pitch period */
	
		kt_globals.T0 = (40 * kt_globals.samrate) / frame->F0hz10;
	
	
		kt_globals.amp_voice = DBtoLIN(frame->AVdb_tmp);
	
		/* Duration of period before amplitude modulation */
	
		kt_globals.nmod = kt_globals.T0;
		if (frame->AVdb_tmp > 0) 
		{
			kt_globals.nmod >>= 1;
		}
	
		/* Breathiness of voicing waveform */
	
		kt_globals.amp_breth = DBtoLIN(frame->Aturb) * 0.1;
	
		/* Set open phase of glottal period where  40 <= open phase <= 263 */
	
		kt_globals.nopen = 4 * frame->Kopen;
	
		if ((kt_globals.glsource == IMPULSIVE) && (kt_globals.nopen > 263))
		{
			kt_globals.nopen = 263;
		}
	
		if (kt_globals.nopen >= (kt_globals.T0-1)) 
		{
//	printf("Warning: glottal open period cannot exceed T0, truncated\n");
			kt_globals.nopen = kt_globals.T0 - 2;
		}
	
		if (kt_globals.nopen < 40) 
		{
			/* F0 max = 1000 Hz */
//	printf("Warning: minimum glottal open period is 10 samples.\n");
//	printf("truncated, nopen = %d\n",kt_globals.nopen);
			kt_globals.nopen = 40;
		}
	
	
		/* Reset a & b, which determine shape of "natural" glottal waveform */
	
		kt_globals.pulse_shape_b = B0[kt_globals.nopen-40];
		kt_globals.pulse_shape_a = (kt_globals.pulse_shape_b * kt_globals.nopen) * 0.333;
	
		/* Reset width of "impulsive" glottal pulse */
	
		temp = kt_globals.samrate / kt_globals.nopen;
	
		setabc((long)0,temp,&(kt_globals.rsn[RGL]));
	
		/* Make gain at F1 about constant */
	
		temp1 = kt_globals.nopen *.00833;
		kt_globals.rsn[RGL].a *= temp1 * temp1;
		
		/*
		Truncate skewness so as not to exceed duration of closed phase
		of glottal period.
		*/
	
	
		temp = kt_globals.T0 - kt_globals.nopen;
		if (frame->Kskew > temp) 
		{
//	printf("Kskew duration=%d > glottal closed period=%d, truncate\n", frame->Kskew, kt_globals.T0 - kt_globals.nopen);
			frame->Kskew = temp;
		}
		if (skew >= 0) 
		{
			skew = frame->Kskew;
		}
		else 
		{
			skew = - frame->Kskew;
		}
	
		/* Add skewness to closed portion of voicing period */
		kt_globals.T0 = kt_globals.T0 + skew;
		skew = - skew;
	}
	else 
	{
		kt_globals.T0 = 4;                     /* Default for f0 undefined */
		kt_globals.amp_voice = 0.0;
		kt_globals.nmod = kt_globals.T0;
		kt_globals.amp_breth = 0.0;
		kt_globals.pulse_shape_a = 0.0;
		kt_globals.pulse_shape_b = 0.0;
	}
	
	/* Reset these pars pitch synchronously or at update rate if f0=0 */
	
	if ((kt_globals.T0 != 4) || (kt_globals.ns == 0)) 
	{
		/* Set one-pole low-pass filter that tilts glottal source */
	
		kt_globals.decay = (0.033 * frame->TLTdb);
	
		if (kt_globals.decay > 0.0) 
		{
			kt_globals.onemd = 1.0 - kt_globals.decay;
		}
		else 
		{
			kt_globals.onemd = 1.0;
		}
	}
}



/*
function SETABC

Convert formant freqencies and bandwidth into resonator difference 
equation constants.
*/


static void setabc(long int f, long int bw, resonator_ptr rp)
{
	double r;
	double arg;
	
	/* Let r  =  exp(-pi bw t) */
	arg = kt_globals.minus_pi_t * bw;
	r = exp(arg);
	
	/* Let c  =  -r**2 */
	rp->c = -(r * r);
	
	/* Let b = r * 2*cos(2 pi f t) */
	arg = kt_globals.two_pi_t * f;
	rp->b = r * cos(arg) * 2.0;
	
	/* Let a = 1.0 - b - c */
	rp->a = 1.0 - rp->b - rp->c;
}


/*
function SETZEROABC

Convert formant freqencies and bandwidth into anti-resonator difference 
equation constants.
*/

static void setzeroabc(long int f, long int bw, resonator_ptr rp)
{
	double r;
	double arg;
	
	f = -f;
	
	if(f>=0)
	{
		f = -1;
	}
	
	/* First compute ordinary resonator coefficients */
	/* Let r  =  exp(-pi bw t) */
	arg = kt_globals.minus_pi_t * bw;
	r = exp(arg);
	
	/* Let c  =  -r**2 */
	rp->c = -(r * r);
	
	/* Let b = r * 2*cos(2 pi f t) */
	arg = kt_globals.two_pi_t * f;
	rp->b = r * cos(arg) * 2.;
	
	/* Let a = 1.0 - b - c */
	rp->a = 1.0 - rp->b - rp->c;
	
	/* Now convert to antiresonator coefficients (a'=1/a, b'=b/a, c'=c/a) */
	rp->a = 1.0 / rp->a;
	rp->c *= -rp->a;
	rp->b *= -rp->a;
}


/* 
function GEN_NOISE

Random number generator (return a number between -8191 and +8191) 
Noise spectrum is tilted down by soft low-pass filter having a pole near 
the origin in the z-plane, i.e. output = input + (0.75 * lastoutput) 
*/


static double gen_noise(double noise) 
{
	long temp;
	static double nlast;
	
	temp = (long) getrandom(-8191,8191);
	kt_globals.nrand = (long) temp;
	
	noise = kt_globals.nrand + (0.75 * nlast);
	nlast = noise;
	
	return(noise);
}


/*
function DBTOLIN

Convert from decibels to a linear scale factor


Conversion table, db to linear, 87 dB --> 32767
                                86 dB --> 29491 (1 dB down = 0.5**1/6)
                                 ...
                                81 dB --> 16384 (6 dB down = 0.5)
                                 ...
                                 0 dB -->     0
 
The just noticeable difference for a change in intensity of a vowel
is approximately 1 dB.  Thus all amplitudes are quantized to 1 dB
steps.
*/


static double DBtoLIN(long dB) 
{
	static short amptable[88] = 
	{
		0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   6,   7,
      8,   9,   10,  11,  13,  14,  16,  18,  20,  22,  25,  28,  32,
		35,  40,  45,  51,  57,  64,  71,  80,  90,  101,  114,  128,
		142,  159,  179,  202,  227,  256,  284,  318,  359,  405,
		455,  512,  568,  638,  719,  881,  911,  1024,  1137,  1276,
		1438,  1622,  1823,  2048,  2273,  2552,  2875,  3244,  3645,
		4096,  4547,  5104,  5751,  6488,  7291,  8192,  9093,  10207,
		11502,  12976,  14582,  16384,  18350,  20644,  23429,
		26214,  29491,  32767 };
	
	if ((dB < 0) || (dB > 87))
	{
		return(0);
	}
	
	return((double)(amptable[dB]) * 0.001);
}





extern voice_t *wvoice;
static klatt_peaks_t peaks[N_PEAKS];
static int end_wave;
static int klattp[N_KLATTP];
static double klattp1[N_KLATTP];
static double klattp_inc[N_KLATTP];

static int scale_wav_tab[] = {45,38,45,45};   // scale output from different voicing sources



int Wavegen_Klatt(int resume)
{//==========================
	int pk;
	int x;
	int ix;
	int fade;

	if(resume==0)
	{
		sample_count = 0;
	}

	while(sample_count < nsamples)
	{
		kt_frame.F0hz10 = (wdata.pitch * 10) / 4096;

		// formants F6,F7,F8 are fixed values for cascade resonators, set in KlattInit()
		// but F6 is used for parallel resonator
		// F0 is used for the nasal zero
		for(ix=0; ix < 6; ix++)
		{
			kt_frame.Fhz[ix] = peaks[ix].freq;
			if(ix < 4)
			{
				kt_frame.Bhz[ix] = peaks[ix].bw;
			}
		}
		for(ix=1; ix < 7; ix++)
		{
			kt_frame.Ap[ix] = 0;
		}

		kt_frame.AVdb = klattp[KLATT_AV];
		kt_frame.AVpdb = klattp[KLATT_AVp];
		kt_frame.AF = klattp[KLATT_Fric];
		kt_frame.AB = klattp[KLATT_FricBP];
		kt_frame.ASP = klattp[KLATT_Aspr];
		kt_frame.Aturb = klattp[KLATT_Turb];
		kt_frame.Kskew = klattp[KLATT_Skew];
		kt_frame.TLTdb = klattp[KLATT_Tilt];
		kt_frame.Kopen = klattp[KLATT_Kopen];

		// advance formants
		for(pk=0; pk<N_PEAKS; pk++)
		{
			peaks[pk].freq1 += peaks[pk].freq_inc;
			peaks[pk].freq = (int)peaks[pk].freq1;
			peaks[pk].bw1 += peaks[pk].bw_inc;
			peaks[pk].bw = (int)peaks[pk].bw1;
			peaks[pk].bp1 += peaks[pk].bp_inc;
			peaks[pk].bp = (int)peaks[pk].bp1;
			peaks[pk].ap1 += peaks[pk].ap_inc;
			peaks[pk].ap = (int)peaks[pk].ap1;
		}

		// advance other parameters
		for(ix=0; ix < N_KLATTP; ix++)
		{
			klattp1[ix] += klattp_inc[ix];
			klattp[ix] = (int)klattp1[ix];
		}

		for(ix=0; ix<=6; ix++)
		{
			kt_frame.Fhz_next[ix] = peaks[ix].freq;
			if(ix < 4)
			{
				kt_frame.Bhz_next[ix] = peaks[ix].bw;
			}
		}

		// advance the pitch
		wdata.pitch_ix += wdata.pitch_inc;
		if((ix = wdata.pitch_ix>>8) > 127) ix = 127;
		x = wdata.pitch_env[ix] * wdata.pitch_range;
		wdata.pitch = (x>>8) + wdata.pitch_base;

		kt_globals.nspfr = (nsamples - sample_count);
		if(kt_globals.nspfr > STEPSIZE)
			kt_globals.nspfr = STEPSIZE;

		frame_init(&kt_frame);  /* get parameters for next frame of speech */

		if(parwave(&kt_frame) == 1)
		{
			return(1);    // output buffer is full
		}
	}

	if(end_wave > 0)
	{
#ifdef deleted
		if(end_wave == 2)
		{
		fade = (kt_globals.T0 - kt_globals.nper)/4;  // samples until end of current cycle
		if(fade < 64)
			fade = 64;
		}
		else
#endif
		{
			fade = 64;   // not followd by formant synthesis
		}

		// fade out to avoid a click
		kt_globals.fadeout = fade;
		end_wave = 0;
		sample_count -= fade;
		kt_globals.nspfr = fade;
		if(parwave(&kt_frame) == 1)
		{
			return(1);    // output buffer is full
		}
	}

	return(0);
}


void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v, int control)
{//===========================================================================================
	int ix;
	DOUBLEX next;
	int qix;
	int cmd;
	frame_t *fr3;
	static frame_t prev_fr;

	if(wvoice != NULL)
	{
		if((wvoice->klattv[0] > 0) && (wvoice->klattv[0] <=3 ))
		{
			kt_globals.glsource = wvoice->klattv[0];
			kt_globals.scale_wav = scale_wav_tab[kt_globals.glsource];
		}
		kt_globals.f0_flutter = wvoice->flutter/32;
	}

	end_wave = 0;
	if(control & 2)
	{
		end_wave = 1;   // fadeout at the end
	}
	if(control & 1)
	{
		end_wave = 1;
		for(qix=wcmdq_head+1;;qix++)
		{
			if(qix >= N_WCMDQ) qix = 0;
			if(qix == wcmdq_tail) break;
	
			cmd = wcmdq[qix][0];
			if(cmd==WCMD_KLATT)
			{
				end_wave = 0;  // next wave generation is from another spectrum

				fr3 = (frame_t *)wcmdq[qix][2];
				for(ix=1; ix<6; ix++)
				{
					if(fr3->ffreq[ix] != fr2->ffreq[ix])
					{
						// there is a discontinuity in formants
						end_wave = 2;
						break;
					}
				}
				break;
			}
			if((cmd==WCMD_WAVE) || (cmd==WCMD_PAUSE))
				break;   // next is not from spectrum, so continue until end of wave cycle
		}
	}

#ifdef LOG_FRAMES
if(option_log_frames)
{
	FILE *f_log;
	f_log=fopen("log-espeakedit","a");
	if(f_log != NULL)
	{
		fprintf(f_log,"K %3dmS  %3d %3d %4d %4d %4d %4d (%2d)  to  %3d %3d %4d %4d %4d %4d (%2d)\n",length*1000/samplerate,
			fr1->klattp[KLATT_FNZ]*2,fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3],fr1->ffreq[4],fr1->ffreq[5], fr1->klattp[KLATT_AV],
			fr2->klattp[KLATT_FNZ]*2,fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3],fr1->ffreq[4],fr1->ffreq[5], fr2->klattp[KLATT_AV] );
		fclose(f_log);
	}
	f_log=fopen("log-klatt","a");
	if(f_log != NULL)
	{
		fprintf(f_log,"K %3dmS  %3d %3d %4d %4d (%2d)  to  %3d %3d %4d %4d (%2d)\n",length*1000/samplerate,
			fr1->klattp[KLATT_FNZ]*2,fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3], fr1->klattp[KLATT_AV],
			fr2->klattp[KLATT_FNZ]*2,fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3], fr2->klattp[KLATT_AV] );
	
		fclose(f_log);
	}
}
#endif

	if(control & 1)
	{
		for(ix=1; ix<6; ix++)
		{
			if(prev_fr.ffreq[ix] != fr1->ffreq[ix])
			{
				// Discontinuity in formants.
				// end_wave was set in SetSynth_Klatt() to fade out the previous frame
				KlattReset(0);
				break;
			}
		}
		memcpy(&prev_fr,fr2,sizeof(prev_fr));
	}

	for(ix=0; ix<N_KLATTP; ix++)
	{
		if((ix >= 5) && ((fr1->frflags & FRFLAG_KLATT) == 0))
		{
			klattp1[ix] = klattp[ix] = 0;
			klattp_inc[ix] = 0;
		}
		else
		{
			klattp1[ix] = klattp[ix] = fr1->klattp[ix];
			klattp_inc[ix] = (double)((fr2->klattp[ix] - klattp[ix]) * STEPSIZE)/length;
		}

		// get klatt parameter adjustments for the voice
//		if((ix>0) && (ix < KLATT_AVp))
//			klattp1[ix] = klattp[ix] = (klattp[ix] + wvoice->klattv[ix]);
	}

	nsamples = length;

	for(ix=1; ix < 6; ix++)
	{
		peaks[ix].freq1 = (fr1->ffreq[ix] * v->freq[ix] / 256.0) + v->freqadd[ix];
		peaks[ix].freq = (int)peaks[ix].freq1;
		next = (fr2->ffreq[ix] * v->freq[ix] / 256.0) + v->freqadd[ix];
		peaks[ix].freq_inc =  ((next - peaks[ix].freq1) * STEPSIZE) / length;

		if(ix < 4)
		{
			// klatt bandwidth for f1, f2, f3 (others are fixed)
			peaks[ix].bw1 = fr1->bw[ix] * 2;
			peaks[ix].bw = (int)peaks[ix].bw1;
			next = fr2->bw[ix] * 2;
			peaks[ix].bw_inc =  ((next - peaks[ix].bw1) * STEPSIZE) / length;
		}
	}

	// nasal zero frequency
	peaks[0].freq1 = fr1->klattp[KLATT_FNZ] * 2;
	if(peaks[0].freq1 == 0)
		peaks[0].freq1 = kt_frame.Fhz[F_NP];   // if no nasal zero, set it to same freq as nasal pole

	peaks[0].freq = (int)peaks[0].freq1;
	next = fr2->klattp[KLATT_FNZ] * 2;
	if(next == 0)
		next = kt_frame.Fhz[F_NP];

	peaks[0].freq_inc = ((next - peaks[0].freq1) * STEPSIZE) / length;

	peaks[0].bw1 = 89;
	peaks[0].bw = 89;
	peaks[0].bw_inc = 0;

	if(fr1->frflags & FRFLAG_KLATT)
	{
		// the frame contains additional parameters for parallel resonators
		for(ix=1; ix < 7; ix++)
		{
			peaks[ix].bp1 = fr1->klatt_bp[ix] * 4;  // parallel bandwidth
			peaks[ix].bp = (int)peaks[ix].bp1;
			next = fr2->klatt_bp[ix] * 2;
			peaks[ix].bp_inc =  ((next - peaks[ix].bp1) * STEPSIZE) / length;

			peaks[ix].ap1 = fr1->klatt_ap[ix];   // parallal amplitude
			peaks[ix].ap = (int)peaks[ix].ap1;
			next = fr2->klatt_ap[ix] * 2;
			peaks[ix].ap_inc =  ((next - peaks[ix].ap1) * STEPSIZE) / length;
		}
	}
}  // end of SetSynth_Klatt


int Wavegen_Klatt2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2)
{//===================================================================================
	if(resume==0)
		SetSynth_Klatt(length, modulation, fr1, fr2, wvoice, 1);

	return(Wavegen_Klatt(resume));
}



void KlattInit()
{
#define NUMBER_OF_SAMPLES 100

	static short natural_samples[NUMBER_OF_SAMPLES]=
	{
		-310,-400,530,356,224,89,23,-10,-58,-16,461,599,536,701,770,
		605,497,461,560,404,110,224,131,104,-97,155,278,-154,-1165,
		-598,737,125,-592,41,11,-247,-10,65,92,80,-304,71,167,-1,122,
		233,161,-43,278,479,485,407,266,650,134,80,236,68,260,269,179,
		53,140,275,293,296,104,257,152,311,182,263,245,125,314,140,44,
		203,230,-235,-286,23,107,92,-91,38,464,443,176,98,-784,-2449,
		-1891,-1045,-1600,-1462,-1384,-1261,-949,-730
	};
	static short formant_hz[10] = {280,688,1064,2806,3260,3700,6500,7000,8000,280};
	static short bandwidth[10] = {89,160,70,160,200,200,500,500,500,89};
	static short parallel_amp[10] = { 0,59,59,59,59,59,59,0,0,0};
	static short parallel_bw[10] = {59,59,89,149,200,200,500,0,0,0};

	int ix;

	sample_count=0;

	kt_globals.synthesis_model = CASCADE_PARALLEL;
	kt_globals.samrate = 22050;

	kt_globals.glsource = IMPULSIVE; // IMPULSIVE, NATURAL, SAMPLED
	kt_globals.scale_wav = scale_wav_tab[kt_globals.glsource];
	kt_globals.natural_samples = natural_samples;
	kt_globals.num_samples = NUMBER_OF_SAMPLES;
	kt_globals.sample_factor = 3.0;
	kt_globals.nspfr = (kt_globals.samrate * 10) / 1000;
	kt_globals.outsl = 0;
	kt_globals.f0_flutter = 20;

	KlattReset(2);

	// set default values for frame parameters
	for(ix=0; ix<=9; ix++)
	{
		kt_frame.Fhz[ix] = formant_hz[ix];
		kt_frame.Bhz[ix] = bandwidth[ix];
		kt_frame.Ap[ix] = parallel_amp[ix];
		kt_frame.Bphz[ix] = parallel_bw[ix];
	}
	kt_frame.Bhz_next[F_NZ] = bandwidth[F_NZ];

	kt_frame.F0hz10 = 1000;
	kt_frame.AVdb = 59;  // 59
	kt_frame.ASP = 0;
	kt_frame.Kopen = 40;  // 40
	kt_frame.Aturb = 0;
	kt_frame.TLTdb = 0;
	kt_frame.AF =50;
	kt_frame.Kskew = 0;
	kt_frame.AB = 0;
	kt_frame.AVpdb = 0;
	kt_frame.Gain0 = 62;   // 60
}  // end of KlattInit

#endif  // INCLUDE_KLATT

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
CEO bring-it-together s.r.o.
Slovakia Slovakia
Jozef Božek is currently a software engineer at bring-it-together s.r.o. in area of large scale infomation systems and mobile applications development.
He has been developing in C++ nearly full time since 2000, in Java since 2004 and in Objective-C since 2009. He is programming using Java EE SDK, iOS SDK, COM/DCOM, MFC, ATL, STL and so on Smile | :)

Comments and Discussions