Click here to Skip to main content
15,891,981 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 74.7K   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) 2005 to 2007 by Jonathan Duddington                     *
 *   email: jonsd@users.sourceforge.net                                    *
 *                                                                         *
 *   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, write see:                           *
 *               <http://www.gnu.org/licenses/>.                           *
 ***************************************************************************/

#include "StdAfx.h"

#include <stdlib.h>
#include <stdio.h>
#include <wctype.h>

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

extern int GetAmplitude(void);


// convert from words-per-minute to internal speed factor
// Use this to calibrate speed for wpm 80-350
static unsigned char speed_lookup[] = {
 255, 255, 255, 255, 255,   // 80
 253, 249, 245, 242, 238,   // 85
 235, 232, 228, 225, 222,   // 90
 218, 216, 213, 210, 207,   // 95
 204, 201, 198, 196, 193,   // 100
 191, 188, 186, 183, 181,   // 105
 179, 176, 174, 172, 169,   // 110
 168, 165, 163, 161, 159,   // 115
 158, 155, 153, 152, 150,   // 120
 148, 146, 145, 143, 141,   // 125
 139, 137, 136, 135, 133,   // 130
 131, 130, 129, 127, 126,   // 135
 124, 123, 122, 120, 119,   // 140
 118, 117, 115, 114, 113,   // 145
 112, 111, 110, 109, 107,   // 150
 106, 105, 104, 103, 102,   // 155
 101, 100,  99,  98,  97,   // 160
  96,  95,  94,  93,  92,   // 165
  91,  90,  89,  89,  88,   // 170
  87,  86,  85,  84,  83,   // 175
  82,  82,  81,  80,  80,   // 180
  79,  78,  77,  76,  76,   // 185
  75,  75,  74,  73,  72,   // 190
  71,  71,  70,  69,  69,   // 195
  68,  67,  67,  66,  66,   // 200
  65,  64,  64,  63,  62,   // 205
  62,  61,  61,  60,  59,   // 210
  59,  58,  58,  57,  57,   // 215
  56,  56,  55,  54,  54,   // 220
  53,  53,  52,  52,  52,   // 225
  51,  50,  50,  49,  49,   // 230
  48,  48,  47,  47,  46,   // 235
  46,  46,  45,  45,  44,   // 240
  44,  44,  43,  43,  42,   // 245
  41,  40,  40,  40,  39,   // 250
  39,  39,  38,  38,  38,   // 255
  37,  37,  37,  36,  36,   // 260
  35,  35,  35,  35,  34,   // 265
  34,  34,  33,  33,  33,   // 270
  32,  32,  31,  31,  31,   // 275
  30,  30,  30,  29,  29,   // 280
  29,  29,  28,  28,  27,   // 285
  27,  27,  27,  26,  26,   // 290
  26,  26,  25,  25,  25,   // 295
  24,  24,  24,  24,  23,   // 300
  23,  23,  23,  22,  22,   // 305
  22,  21,  21,  21,  21,   // 310
  20,  20,  20,  20,  19,   // 315
  19,  19,  18,  18,  17,   // 320
  17,  17,  16,  16,  16,   // 325
  16,  16,  16,  15,  15,   // 330
  15,  15,  14,  14,  14,   // 335
  13,  13,  13,  12,  12,   // 340
  12,  12,  11,  11,  11,   // 345
  11,  10,  10,  10,   9,   // 350
   9,   9,   8,   8,   8,   // 355
};


// speed_factor1 adjustments for speeds 350 to 374: pauses
static unsigned char pause_factor_350[] = {
22,22,22,22,22,22,22,21,21,21,  // 350
21,20,20,19,19,18,17,16,15,15,  // 360
15,15,15,15,15};                // 370

// wav_factor adjustments for speeds 350 to 450
// Use this to calibrate speed for wpm 350-450 
static unsigned char wav_factor_350[] = {
 120, 121, 120, 119, 119,   // 350
 118, 118, 117, 116, 116,   // 355
 115, 114, 113, 112, 112,   // 360
 111, 111, 110, 109, 108,   // 365
 107, 106, 106, 104, 103,   // 370
 103, 102, 102, 102, 101,   // 375
 101,  99,  98,  98,  97,   // 380
  96,  96,  95,  94,  93,   // 385
  91,  90,  91,  90,  89,   // 390
  88,  86,  85,  86,  85,   // 395
  85,  84,  82,  81,  80,   // 400
  79,  77,  78,  78,  76,   // 405
  77,  75,  75,  74,  73,   // 410
  71,  72,  70,  69,  69,   // 415
  69,  67,  65,  64,  63,   // 420
  63,  63,  61,  61,  59,   // 425
  59,  59,  58,  56,  57,   // 430
  58,  56,  54,  53,  52,   // 435
  52,  53,  52,  52,  50,   // 440
  48,  47,  47,  45,  46,   // 445
  45};   // 450

static int speed1 = 130;
static int speed2 = 121;
static int speed3 = 118;



//#define TEST_SPEED

void SetSpeed(int control)
{//=======================
	int x;
	int s1;
	int wpm;
	int wpm2;

	speed.loud_consonants = 0;
	speed.min_sample_len = 450;
	speed.lenmod_factor = 110;   // controls the effect of FRFLAG_LEN_MOD reduce length change
	speed.lenmod2_factor = 100;

	wpm = embedded_value[EMBED_S];
	if(control == 2)
		wpm = embedded_value[EMBED_S2];

#ifdef TEST_SPEED
	if(wpm > 1000)
	{
		// TESTING
//		test = wpm / 1000;
		wpm = wpm % 1000;
	}
#endif

	if(voice->speed_percent > 0)
	{
		wpm = (wpm * voice->speed_percent)/100;
	}
	if(wpm > 450)
		wpm = 450;

	if(wpm > 360)
	{
		speed.loud_consonants = (wpm - 360) / 8;
	}

	wpm2 = wpm;
	if(wpm > 359) wpm2 = 359;
	if(wpm < 80) wpm2 = 80;
	x = speed_lookup[wpm2-80];

	if(wpm >= 380)
		x = 7;
	if(wpm >= 400)
		x = 6;

	if(control & 1)
	{
		// set speed factors for different syllable positions within a word
		// these are used in CalcLengths()
		speed1 = (x * voice->speedf1)/256;
		speed2 = (x * voice->speedf2)/256;
		speed3 = (x * voice->speedf3)/256;

		if(x <= 7)
		{
			speed1 = x;
			speed2 = speed3 = x - 1;
		}
	}

	if(control & 2)
	{
		// these are used in synthesis file

		if(wpm > 350)
		{
			speed.lenmod_factor = 85 - (wpm - 350) / 3;
			speed.lenmod2_factor = 60 - (wpm - 350) / 8;
		}
		else
		if(wpm > 250)
		{
			speed.lenmod_factor = 110 - (wpm - 250)/4;
			speed.lenmod2_factor = 110 - (wpm - 250)/2;
		}

		s1 = (x * voice->speedf1)/256;

		if(wpm >= 170)
			speed.wav_factor = 110 + (150*s1)/128;  // reduced speed adjustment, used for playing recorded sounds
		else
			speed.wav_factor = 128 + (128*s1)/130;  // = 215 at 170 wpm

		if(wpm >= 350)
		{
			speed.wav_factor = wav_factor_350[wpm-350];
		}

		if(wpm >= 390)
		{
			speed.min_sample_len = 450 - (wpm - 400)/2;
			if(wpm > 440)
				speed.min_sample_len = 420 - (wpm - 440);
		}

		speed.pause_factor = (256 * s1)/115;      // full speed adjustment, used for pause length
		speed.clause_pause_factor = 0;

		if(wpm > 430)
		{
			speed.pause_factor = 12;
//			speed.clause_pause_factor = 15;
		}
		else
		if(wpm > 400)
		{
			speed.pause_factor = 13;
//			speed.clause_pause_factor = 15;
		}
		else
		if(wpm > 374)
		{
			speed.pause_factor = 14;
		}
		else
		if(wpm > 350)
		{
			speed.pause_factor = pause_factor_350[wpm - 350];
		}

		if(speed.clause_pause_factor == 0)
		{
			// restrict the reduction of pauses between clauses
			if((speed.clause_pause_factor = speed.pause_factor) < 16)
				speed.clause_pause_factor = 16;
		}

		if(wpm >= 370)
		{
			// TESTING
			// use experimental fast settings if they have been specified in the Voice
			if(speed.fast_settings[0] > 0)
				speed.pause_factor = speed.fast_settings[0];
			if(speed.fast_settings[1] > 0)
				speed.wav_factor = speed.fast_settings[1];
			if(speed.fast_settings[2] > 0)
				speed.lenmod_factor = speed.lenmod2_factor = speed.fast_settings[2];
		}
	}

#ifdef TEST_SPEED
//if(control==3)
printf("%3d: speedf %d %d %d   pause=%d %d   wav=%d  lenmod=%d %d\n",wpm,speed1,speed2,speed3, speed.pause_factor,speed.clause_pause_factor, speed.wav_factor,speed.lenmod_factor,speed.lenmod2_factor);
#endif
}  //  end of SetSpeed


#ifdef deleted
void SetAmplitude(int amp)
{//=======================
	static unsigned char amplitude_factor[] = {0,5,6,7,9,11,14,17,21,26, 32, 38,44,50,56,63,70,77,84,91,100 };

	if((amp >= 0) && (amp <= 20))
	{
		option_amplitude = (amplitude_factor[amp] * 480)/256; 
	}
}
#endif



void SetParameter(int parameter, int value, int relative)
{//======================================================
// parameter: reset-all, amp, pitch, speed, linelength, expression, capitals, number grouping
// relative 0=absolute  1=relative

	int new_value = value;
	int default_value;

	if(relative)
	{
		if(parameter < 5)
		{
			default_value = param_defaults[parameter];
			new_value = default_value + (default_value * value)/100;
		}
	}
	param_stack[0].parameter[parameter] = new_value;

	switch(parameter)
	{
	case espeakRATE:
		embedded_value[EMBED_S] = new_value;
		embedded_value[EMBED_S2] = new_value;
		SetSpeed(3);
		break;

	case espeakVOLUME:
		embedded_value[EMBED_A] = new_value;
		GetAmplitude();
		break;

	case espeakPITCH:
		if(new_value > 99) new_value = 99;
		if(new_value < 0) new_value = 0;
		embedded_value[EMBED_P] = new_value;
		break;

	case espeakRANGE:
		if(new_value > 99) new_value = 99;
		embedded_value[EMBED_R] = new_value;
		break;

	case espeakLINELENGTH:
		option_linelength = new_value;
		break;

	case espeakWORDGAP:
		option_wordgap = new_value;
		break;

	case espeakINTONATION:
		if((new_value & 0xff) != 0)
			translator->langopts.intonation_group = new_value & 0xff;
		option_tone_flags = new_value;
		break;

	default:
		break;
	}
}  // end of SetParameter



static void DoEmbedded2(int *embix)
{//================================
	// There were embedded commands in the text at this point

	unsigned int word;

	do {
		word = embedded_list[(*embix)++];

		if((word & 0x1f) == EMBED_S)
		{
			// speed
			SetEmbedded(word & 0x7f, word >> 8);   // adjusts embedded_value[EMBED_S]
			SetSpeed(1);
		}
	} while((word & 0x80) == 0);
}


void CalcLengths(Translator *tr)
{//==============================
	int ix;
	int ix2;
	PHONEME_LIST *prev;
	PHONEME_LIST *next;
	PHONEME_LIST *next2;
	PHONEME_LIST *next3;
	PHONEME_LIST *p;
	PHONEME_LIST *p2;

	int  stress;
	int  type;
	static int  more_syllables=0;
	int  pre_sonorant=0;
	int  pre_voiced=0;
	int  last_pitch = 0;
	int  pitch_start;
	int  length_mod;
	int  len;
	int  env2;
	int  end_of_clause;
	int  embedded_ix = 0;
	int  min_drop;
	int  pitch1;
	int emphasized;
	int  tone_mod;
	unsigned char *pitch_env=NULL;
	PHONEME_DATA phdata_tone;

	for(ix=1; ix<n_phoneme_list; ix++)
	{
		prev = &phoneme_list[ix-1];
		p = &phoneme_list[ix];
		stress = p->stresslevel & 0x7;
		emphasized = p->stresslevel & 0x8;

		next = &phoneme_list[ix+1];

		if(p->synthflags & SFLAG_EMBEDDED)
		{
			DoEmbedded2(&embedded_ix);
		}

		type = p->type;
		if(p->synthflags & SFLAG_SYLLABLE)
			type = phVOWEL;

		switch(type)
		{
		case phPAUSE:
			last_pitch = 0;
			break;
			
		case phSTOP:
			last_pitch = 0;
			if(prev->type == phFRICATIVE)
				p->prepause = 25;
			else
			if((more_syllables > 0) || (stress < 4))
				p->prepause = 48;
			else
				p->prepause = 60;

			if(prev->type == phSTOP)
				p->prepause = 60;

			if((tr->langopts.word_gap & 0x10) && (p->newword))
				p->prepause = 60;

			if(p->ph->phflags & phLENGTHENSTOP)
				p->prepause += 30;

			if(p->synthflags & SFLAG_LENGTHEN)
				p->prepause += tr->langopts.long_stop;
			break;

		case phVFRICATIVE:
		case phFRICATIVE:
			if(p->newword)
			{
				if((prev->type == phVOWEL) && (p->ph->phflags & phNOPAUSE))
				{
				}
				else
				{
					p->prepause = 15;
				}
			}

			if(next->type==phPAUSE && prev->type==phNASAL && !(p->ph->phflags&phFORTIS))
				p->prepause = 25;

			if(prev->ph->phflags & phBRKAFTER)
				p->prepause = 30;

			if((tr->langopts.word_gap & 0x10) && (p->newword))
				p->prepause = 30;

			if((p->ph->phflags & phSIBILANT) && next->type==phSTOP && !next->newword)
			{
				if(prev->type == phVOWEL)
					p->length = 200;      // ?? should do this if it's from a prefix
				else
					p->length = 150;
			}
			else
				p->length = 256;

			if(type == phVFRICATIVE)
			{
				if(next->type==phVOWEL)
				{
					pre_voiced = 1;
				}
				if((prev->type==phVOWEL) || (prev->type == phLIQUID))
				{
					p->length = (255 + prev->length)/2;
				}
			}
			break;

		case phVSTOP:
			if(prev->type==phVFRICATIVE || prev->type==phFRICATIVE || (prev->ph->phflags & phSIBILANT) || (prev->type == phLIQUID))
				p->prepause = 30;

			if(next->type==phVOWEL || next->type==phLIQUID)
			{
				if((next->type==phVOWEL) || !next->newword)
					pre_voiced = 1;

				p->prepause = 40;

				if((prev->type == phPAUSE) || (prev->type == phVOWEL)) // || (prev->ph->mnemonic == ('/'*256+'r')))
					p->prepause = 0;
				else
				if(p->newword==0)
				{
					if(prev->type==phLIQUID)
						p->prepause = 20;
					if(prev->type==phNASAL)
						p->prepause = 12;

					if(prev->type==phSTOP && !(prev->ph->phflags & phFORTIS))
						p->prepause = 0;
				}
			}
			if((tr->langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20))
				p->prepause = 20;

			break;

		case phLIQUID:
		case phNASAL:
			p->amp = tr->stress_amps[0];  // unless changed later
			p->length = 256;  //  TEMPORARY
			min_drop = 0;
			
			if(p->newword)
			{
				if(prev->type==phLIQUID)
					p->prepause = 25;
				if(prev->type==phVOWEL)
				{
					if(!(p->ph->phflags & phNOPAUSE))
						p->prepause = 12;
				}
			}

			if(next->type==phVOWEL)
			{
				pre_sonorant = 1;
			}
			else
			{
				p->pitch2 = last_pitch;

				if((prev->type==phVOWEL) || (prev->type == phLIQUID))
				{
					p->length = prev->length;
					
					if(p->type == phLIQUID)
					{
						p->length = speed1;
					}
	
					if(next->type == phVSTOP)
					{
						p->length = (p->length * 160)/100;
					}
					if(next->type == phVFRICATIVE)
					{
						p->length = (p->length * 120)/100;
					}
				}
				else
				{
					for(ix2=ix; ix2<n_phoneme_list; ix2++)
					{
						if(phoneme_list[ix2].type == phVOWEL)
						{
							p->pitch2 = phoneme_list[ix2].pitch2;
							break;
						}
					}
				}

				p->pitch1 = p->pitch2-16;
				if(p->pitch2 < 16)
				{
					p->pitch1 = 0;
				}
				p->env = PITCHfall;
				pre_voiced = 0;
			}
			break;

		case phVOWEL:
			min_drop = 0;
			next2 = &phoneme_list[ix+2];
			next3 = &phoneme_list[ix+3];

			if(stress > 7) stress = 7;

if(stress <= 1)
{
  stress = stress ^ 1;  // swap diminished and unstressed (until we swap stress_amps,stress_lengths in tr_languages)
}
			if(pre_sonorant)
				p->amp = tr->stress_amps[stress]-1;
			else
				p->amp = tr->stress_amps[stress];

			if(emphasized)
				p->amp = 25;

			if(ix >= (n_phoneme_list-3))
			{
				// last phoneme of a clause, limit its amplitude
				if(p->amp > tr->langopts.param[LOPT_MAXAMP_EOC])
					p->amp = tr->langopts.param[LOPT_MAXAMP_EOC];
			}

			// is the last syllable of a word ?
			more_syllables=0;
			end_of_clause = 0;
			for(p2 = p+1; p2->newword== 0; p2++)
			{
				if((p2->type == phVOWEL) && !(p2->ph->phflags & phNONSYLLABIC))
					more_syllables++;

				if(p2->ph->code == phonPAUSE_CLAUSE)
					end_of_clause = 2;
			}
			if(p2->ph->code == phonPAUSE_CLAUSE)
				end_of_clause = 2;

			if((p2->newword & 2) && (more_syllables==0))
			{
				end_of_clause = 2;
			}

			// calc length modifier
			if((next->ph->code == phonPAUSE_VSHORT) && (next2->type == phPAUSE))
			{
				// if PAUSE_VSHORT is followed by a pause, then use that
				next = next2;
				next2 = next3;
				next3 = &phoneme_list[ix+4];
			}

			if(more_syllables==0)
			{
				len = tr->langopts.length_mods0[next2->ph->length_mod *10+ next->ph->length_mod];

				if((next->newword) && (tr->langopts.word_gap & 0x20))
				{
					// consider as a pause + first phoneme of the next word
					length_mod = (len + tr->langopts.length_mods0[next->ph->length_mod *10+ 1])/2;
				}
				else
					length_mod = len;
			}
			else
			{
				length_mod = tr->langopts.length_mods[next2->ph->length_mod *10+ next->ph->length_mod];

				if((next->type == phNASAL) && (next2->type == phSTOP || next2->type == phVSTOP) && (next3->ph->phflags & phFORTIS))
					length_mod -= 15;
			}

			if(more_syllables==0)
				length_mod *= speed1;
			else
			if(more_syllables==1)
				length_mod *= speed2;
			else
				length_mod *= speed3;

			length_mod = length_mod / 128;

			if(length_mod < 8)
				length_mod = 8;     // restrict how much lengths can be reduced

			if(stress >= 7)
			{
				// tonic syllable, include a constant component so it doesn't decrease directly with speed
				length_mod += 20;
				if(emphasized)
					length_mod += 10;
			}
			else
			if(emphasized)
			{
				length_mod += 20;
			}

			if((len = tr->stress_lengths[stress]) == 0)
				len = tr->stress_lengths[6];

			length_mod = length_mod * len;

			if(p->tone_ph != 0)
			{
				if((tone_mod = phoneme_tab[p->tone_ph]->std_length) > 0)
				{
					// a tone phoneme specifies a percentage change to the length
					length_mod = (length_mod * tone_mod) / 100;
				}
			}

			if(end_of_clause == 2)
			{
				// this is the last syllable in the clause, lengthen it - more for short vowels
				len = (p->ph->std_length * 2);
				if(tr->langopts.stress_flags & 0x40000)
					len=200;  // don't lengthen short vowels more than long vowels at end-of-clause
				length_mod = length_mod * (256 + (280 - len)/3)/256;
			}

			if(length_mod > tr->langopts.max_lengthmod*speed1)
			{
				//limit the vowel length adjustment for some languages
				length_mod = (tr->langopts.max_lengthmod*speed1);
			}

			length_mod = length_mod / 128;

if(p->type != phVOWEL)
{
	length_mod = 256;   // syllabic consonant
	min_drop = 16;
}
			p->length = length_mod;

			if(p->env >= (N_ENVELOPE_DATA-1))
			{
				fprintf(stderr,"espeak: Bad intonation data\n");
				p->env = 0;
			}

			// pre-vocalic part
			// set last-pitch
			env2 = p->env + 1;  // version for use with preceding semi-vowel

			if(p->tone_ph != 0)
			{
				InterpretPhoneme2(p->tone_ph, &phdata_tone);
				pitch_env = GetEnvelope(phdata_tone.pitch_env);
			}
			else
			{
				pitch_env = envelope_data[env2];
			}

			pitch_start = p->pitch1 + ((p->pitch2-p->pitch1)*pitch_env[0])/256;

			if(pre_sonorant || pre_voiced)
			{
				// set pitch for pre-vocalic part
				if(pitch_start == 255)
					last_pitch = pitch_start;    // pitch is not set

				if(pitch_start - last_pitch > 16)
					last_pitch = pitch_start - 16;

				prev->pitch1 = last_pitch;
				prev->pitch2 = pitch_start;
				if(last_pitch < pitch_start)
				{
					prev->env = PITCHrise;
					p->env = env2;
				}
				else
				{
					prev->env = PITCHfall;
				}

				prev->length = length_mod;

				prev->amp = p->amp;
				if((prev->type != phLIQUID) && (prev->amp > 18))
					prev->amp = 18;
			}

			// vowel & post-vocalic part
			next->synthflags &= ~SFLAG_SEQCONTINUE;
			if(next->type == phNASAL && next2->type != phVOWEL)
				next->synthflags |= SFLAG_SEQCONTINUE;
				
			if(next->type == phLIQUID)
			{
				next->synthflags |= SFLAG_SEQCONTINUE;
					
				if(next2->type == phVOWEL)
				{
					next->synthflags &= ~SFLAG_SEQCONTINUE;
				}

				if(next2->type != phVOWEL)
				{
					if(next->ph->mnemonic == ('/'*256+'r'))
					{
						next->synthflags &= ~SFLAG_SEQCONTINUE;
//						min_drop = 15;
					}
				}
			}

			if((min_drop > 0) && ((p->pitch2 - p->pitch1) < min_drop))
			{
				pitch1 = p->pitch2 - min_drop;
				if(pitch1 < 0)
					pitch1 = 0;
				p->pitch1 = pitch1;
			}

			last_pitch = p->pitch1 + ((p->pitch2-p->pitch1)*envelope_data[p->env][127])/256;
			pre_sonorant = 0;
			pre_voiced = 0;
			break;
		}
	}
}  //  end of CalcLengths

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