eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

compiledata.c 75KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238
  1. /*
  2. * Copyright (C) 2005 to 2014 by Jonathan Duddington
  3. * email: [email protected]
  4. * Copyright (C) 2013-2015 Reece H. Dunn
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, see: <http://www.gnu.org/licenses/>.
  18. */
  19. #include "config.h"
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <stdlib.h>
  24. #include <time.h>
  25. #if HAVE_STDINT_H
  26. #include <stdint.h>
  27. #endif
  28. #include "speak_lib.h"
  29. #include "espeak_ng.h"
  30. #include "speech.h"
  31. #include "phoneme.h"
  32. #include "synthesize.h"
  33. #include "voice.h"
  34. #include "spect.h"
  35. #include <sys/stat.h>
  36. #ifdef PLATFORM_POSIX
  37. #include <unistd.h>
  38. #endif
  39. typedef struct {
  40. unsigned int value;
  41. char *name;
  42. } NAMETAB;
  43. NAMETAB *manifest = NULL;
  44. int n_manifest;
  45. extern int utf8_in(int *c, const char *buf);
  46. extern int utf8_out(unsigned int c, char *buf);
  47. typedef struct {
  48. const char *mnem;
  49. int type;
  50. int data;
  51. } keywtab_t;
  52. #define k_AND 1
  53. #define k_OR 2
  54. #define k_THEN 3
  55. #define k_NOT 4
  56. #define kTHISSTRESS 0x800
  57. // keyword types
  58. enum {
  59. tPHONEME_TYPE = 1,
  60. tPHONEME_FLAG,
  61. tTRANSITION,
  62. tPLACE,
  63. tSTATEMENT,
  64. tINSTRN1,
  65. tWHICH_PHONEME,
  66. tTEST,
  67. };
  68. static keywtab_t k_conditions[] = {
  69. { "AND", 0, k_AND },
  70. { "OR", 0, k_OR },
  71. { "THEN", 0, k_THEN },
  72. { "NOT", 0, k_NOT },
  73. { "prevPh", tWHICH_PHONEME, 0 },
  74. { "thisPh", tWHICH_PHONEME, 1 },
  75. { "nextPh", tWHICH_PHONEME, 2 },
  76. { "next2Ph", tWHICH_PHONEME, 3 },
  77. { "nextPhW", tWHICH_PHONEME, 4 },
  78. { "prevPhW", tWHICH_PHONEME, 5 },
  79. { "next2PhW", tWHICH_PHONEME, 6 },
  80. { "nextVowel", tWHICH_PHONEME, 7 },
  81. { "prevVowel", tWHICH_PHONEME, 8 },
  82. { "next3PhW", tWHICH_PHONEME, 9 },
  83. { "prev2PhW", tWHICH_PHONEME, 10 },
  84. { "PreVoicing", tTEST, 0xf01 },
  85. { "KlattSynth", tTEST, 0xf02 },
  86. { "MbrolaSynth", tTEST, 0xf03 },
  87. { NULL, 0, 0 }
  88. };
  89. static keywtab_t k_properties[] = {
  90. { "isPause", 0, phPAUSE },
  91. { "isVowel", 0, phVOWEL },
  92. { "isNasal", 0, phNASAL },
  93. { "isLiquid", 0, phLIQUID },
  94. { "isUStop", 0, phSTOP },
  95. { "isVStop", 0, phVSTOP },
  96. { "isVFricative", 0, phVFRICATIVE },
  97. { "isPalatal", 0, i_isPalatal },
  98. { "isLong", 0, i_isLong },
  99. { "isRhotic", 0, i_isRhotic },
  100. { "isSibilant", 0, i_isSibilant },
  101. { "isFlag1", 0, i_isFlag1 },
  102. { "isFlag2", 0, i_isFlag2 },
  103. { "isFlag3", 0, i_isFlag3 },
  104. { "isVel", 0, i_isVel },
  105. { "isDiminished", 0, i_isDiminished },
  106. { "isUnstressed", 0, i_isUnstressed },
  107. { "isNotStressed", 0, i_isNotStressed },
  108. { "isStressed", 0, i_isStressed },
  109. { "isMaxStress", 0, i_isMaxStress },
  110. { "isBreak", 0, i_isBreak },
  111. { "isPause2", 0, i_isBreak }, // synonym for isBreak
  112. { "isWordStart", 0, i_isWordStart },
  113. { "notWordStart", 0, i_notWordStart },
  114. { "isWordEnd", 0, i_isWordEnd },
  115. { "isAfterStress", 0, i_isAfterStress },
  116. { "isNotVowel", 0, i_isNotVowel },
  117. { "isFinalVowel", 0, i_isFinalVowel },
  118. { "isVoiced", 0, i_isVoiced }, // voiced consonant, or vowel
  119. { "isFirstVowel", 0, i_isFirstVowel },
  120. { "isSecondVowel", 0, i_isSecondVowel },
  121. { "isSeqFlag1", 0, i_isSeqFlag1 },
  122. { "isTranslationGiven", 0, i_IsTranslationGiven }, // phoneme translation given in **_list or as [[...]]
  123. { NULL, 0, 0 }
  124. };
  125. enum {
  126. kPHONEMESTART = 1,
  127. kUTF8_BOM,
  128. kPROCEDURE,
  129. kENDPHONEME,
  130. kENDPROCEDURE,
  131. kEQUIVALENTS,
  132. kPHONEMENUMBER,
  133. kPHONEMETABLE,
  134. kINCLUDE,
  135. kIMPORT_PH,
  136. kSTARTTYPE,
  137. kENDTYPE,
  138. kSTRESSTYPE,
  139. kVOICINGSWITCH,
  140. kIF,
  141. kELSE,
  142. kELIF,
  143. kENDIF,
  144. kCALLPH,
  145. kSWITCH_PREVVOWEL,
  146. kSWITCH_NEXTVOWEL,
  147. kENDSWITCH,
  148. kFMT,
  149. kWAV,
  150. kVOWELSTART,
  151. kVOWELENDING,
  152. kANDWAV,
  153. kVOWELIN,
  154. kVOWELOUT,
  155. kTONESPEC,
  156. kRETURN,
  157. kCONTINUE,
  158. };
  159. enum {
  160. kTUNE = 1,
  161. kENDTUNE,
  162. kTUNE_PREHEAD,
  163. kTUNE_ONSET,
  164. kTUNE_HEAD,
  165. kTUNE_HEADENV,
  166. kTUNE_HEADEXTEND,
  167. kTUNE_HEADLAST,
  168. kTUNE_NUCLEUS0,
  169. kTUNE_NUCLEUS1,
  170. kTUNE_SPLIT,
  171. };
  172. static unsigned const char utf8_bom[] = { 0xef, 0xbb, 0xbf, 0 };
  173. static keywtab_t k_intonation[] = {
  174. { "tune", 0, kTUNE },
  175. { "endtune", 0, kENDTUNE },
  176. { "prehead", 0, kTUNE_PREHEAD },
  177. { "onset", 0, kTUNE_ONSET },
  178. { "head", 0, kTUNE_HEAD },
  179. { "headenv", 0, kTUNE_HEADENV },
  180. { "headextend", 0, kTUNE_HEADEXTEND },
  181. { "headlast", 0, kTUNE_HEADLAST },
  182. { "nucleus0", 0, kTUNE_NUCLEUS0 },
  183. { "nucleus", 0, kTUNE_NUCLEUS1 },
  184. { "split", 0, kTUNE_SPLIT },
  185. { NULL, 0, -1 }
  186. };
  187. static keywtab_t keywords[] = {
  188. { "vowel", tPHONEME_TYPE, phVOWEL },
  189. { "liquid", tPHONEME_TYPE, phLIQUID },
  190. { "pause", tPHONEME_TYPE, phPAUSE },
  191. { "stress", tPHONEME_TYPE, phSTRESS },
  192. { "virtual", tPHONEME_TYPE, phVIRTUAL },
  193. { "fricative", tPHONEME_TYPE, phFRICATIVE },
  194. { "vstop", tPHONEME_TYPE, phVSTOP },
  195. { "vfricative", tPHONEME_TYPE, phVFRICATIVE },
  196. { "delete_phoneme", tPHONEME_TYPE, phDELETED },
  197. // type of consonant
  198. { "stop", tPHONEME_TYPE, phSTOP },
  199. { "frc", tPHONEME_TYPE, phFRICATIVE },
  200. { "nasal", tPHONEME_TYPE, phNASAL },
  201. { "flp", tPHONEME_TYPE, phVSTOP },
  202. { "afr", tPHONEME_TYPE, phSTOP }, // treat as stop
  203. { "apr", tPHONEME_TYPE, phFRICATIVE }, // [h] voiceless approximant
  204. // keywords
  205. { "phonemenumber", tSTATEMENT, kPHONEMENUMBER },
  206. { "phonemetable", tSTATEMENT, kPHONEMETABLE },
  207. { "include", tSTATEMENT, kINCLUDE },
  208. { (const char *)utf8_bom, tSTATEMENT, kUTF8_BOM },
  209. { "phoneme", tSTATEMENT, kPHONEMESTART },
  210. { "procedure", tSTATEMENT, kPROCEDURE },
  211. { "endphoneme", tSTATEMENT, kENDPHONEME },
  212. { "endprocedure", tSTATEMENT, kENDPROCEDURE },
  213. { "equivalents", tSTATEMENT, kEQUIVALENTS },
  214. { "import_phoneme", tSTATEMENT, kIMPORT_PH },
  215. { "stress_type", tSTATEMENT, kSTRESSTYPE },
  216. { "starttype", tSTATEMENT, kSTARTTYPE },
  217. { "endtype", tSTATEMENT, kENDTYPE },
  218. { "voicingswitch", tSTATEMENT, kVOICINGSWITCH },
  219. { "IF", tSTATEMENT, kIF },
  220. { "ELSE", tSTATEMENT, kELSE },
  221. { "ELIF", tSTATEMENT, kELIF },
  222. { "ELSEIF", tSTATEMENT, kELIF }, // same as ELIF
  223. { "ENDIF", tSTATEMENT, kENDIF },
  224. { "CALL", tSTATEMENT, kCALLPH },
  225. { "RETURN", tSTATEMENT, kRETURN },
  226. { "PrevVowelEndings", tSTATEMENT, kSWITCH_PREVVOWEL },
  227. { "NextVowelStarts", tSTATEMENT, kSWITCH_NEXTVOWEL },
  228. { "EndSwitch", tSTATEMENT, kENDSWITCH },
  229. { "Tone", tSTATEMENT, kTONESPEC },
  230. { "FMT", tSTATEMENT, kFMT },
  231. { "WAV", tSTATEMENT, kWAV },
  232. { "VowelStart", tSTATEMENT, kVOWELSTART },
  233. { "VowelEnding", tSTATEMENT, kVOWELENDING },
  234. { "addWav", tSTATEMENT, kANDWAV },
  235. { "Vowelin", tSTATEMENT, kVOWELIN },
  236. { "Vowelout", tSTATEMENT, kVOWELOUT },
  237. { "Continue", tSTATEMENT, kCONTINUE },
  238. { "ChangePhoneme", tINSTRN1, i_CHANGE_PHONEME },
  239. { "ChangeNextPhoneme", tINSTRN1, i_REPLACE_NEXT_PHONEME },
  240. { "InsertPhoneme", tINSTRN1, i_INSERT_PHONEME },
  241. { "AppendPhoneme", tINSTRN1, i_APPEND_PHONEME },
  242. { "IfNextVowelAppend", tINSTRN1, i_APPEND_IFNEXTVOWEL },
  243. { "ChangeIfDiminished", tINSTRN1, i_CHANGE_IF + 0 },
  244. { "ChangeIfUnstressed", tINSTRN1, i_CHANGE_IF + 1 },
  245. { "ChangeIfNotStressed", tINSTRN1, i_CHANGE_IF + 2 },
  246. { "ChangeIfStressed", tINSTRN1, i_CHANGE_IF + 3 },
  247. { "PauseBefore", tINSTRN1, i_PAUSE_BEFORE },
  248. { "PauseAfter", tINSTRN1, i_PAUSE_AFTER },
  249. { "Length", tINSTRN1, i_SET_LENGTH },
  250. { "length", tINSTRN1, i_SET_LENGTH },
  251. { "LongLength", tINSTRN1, i_LONG_LENGTH },
  252. { "LengthAdd", tINSTRN1, i_ADD_LENGTH },
  253. { "Lengthmod", tINSTRN1, i_LENGTH_MOD },
  254. { "lengthmod", tINSTRN1, i_LENGTH_MOD },
  255. { "ipa", tINSTRN1, i_IPA_NAME },
  256. // flags
  257. { "wavef", tPHONEME_FLAG, phWAVE },
  258. { "unstressed", tPHONEME_FLAG, phUNSTRESSED },
  259. { "fortis", tPHONEME_FLAG, phFORTIS },
  260. { "sibilant", tPHONEME_FLAG, phSIBILANT },
  261. { "nolink", tPHONEME_FLAG, phNOLINK },
  262. { "trill", tPHONEME_FLAG, phTRILL },
  263. { "vowel2", tPHONEME_FLAG, phVOWEL2 },
  264. { "palatal", tPHONEME_FLAG, phPALATAL },
  265. { "long", tPHONEME_FLAG, phLONG },
  266. { "dontlist", tPHONEME_FLAG, phDONTLIST },
  267. { "brkafter", tPHONEME_FLAG, phBRKAFTER },
  268. { "rhotic", tPHONEME_FLAG, phRHOTIC },
  269. { "nonsyllabic", tPHONEME_FLAG, phNONSYLLABIC },
  270. { "lengthenstop", tPHONEME_FLAG, phLENGTHENSTOP },
  271. { "nopause", tPHONEME_FLAG, phNOPAUSE },
  272. { "prevoice", tPHONEME_FLAG, phPREVOICE },
  273. { "flag1", tPHONEME_FLAG, phFLAG1 },
  274. { "flag2", tPHONEME_FLAG, phFLAG2 },
  275. { "flag3", tPHONEME_FLAG, phFLAG3 },
  276. // voiced / unvoiced
  277. { "vcd", tPHONEME_FLAG, phVOICED },
  278. { "vls", tPHONEME_FLAG, phFORTIS },
  279. // place of articulation, set bits 16-19 of phflags
  280. { "blb", tPLACE, 1 },
  281. { "lbd", tPLACE, 2 },
  282. { "dnt", tPLACE, 3 },
  283. { "alv", tPLACE, 4 },
  284. { "rfx", tPLACE, 5 },
  285. { "pla", tPLACE, 6 },
  286. { "pal", tPLACE, 7 },
  287. { "vel", tPLACE, 8 },
  288. { "lbv", tPLACE, 9 },
  289. { "uvl", tPLACE, 10 },
  290. { "phr", tPLACE, 11 },
  291. { "glt", tPLACE, 12 },
  292. // vowel transition attributes
  293. { "len=", tTRANSITION, 1 },
  294. { "rms=", tTRANSITION, 2 },
  295. { "f1=", tTRANSITION, 3 },
  296. { "f2=", tTRANSITION, 4 },
  297. { "f3=", tTRANSITION, 5 },
  298. { "brk", tTRANSITION, 6 },
  299. { "rate", tTRANSITION, 7 },
  300. { "glstop", tTRANSITION, 8 },
  301. { "lenadd", tTRANSITION, 9 },
  302. { "f4", tTRANSITION, 10 },
  303. { "gpaus", tTRANSITION, 11 },
  304. { "colr=", tTRANSITION, 12 },
  305. { "amp=", tTRANSITION, 13 }, // set rms of 1st frame as fraction of rms of 2nd frame (1/30ths)
  306. { NULL, 0, -1 }
  307. };
  308. static keywtab_t *keyword_tabs[] = {
  309. keywords, k_conditions, k_properties, k_intonation
  310. };
  311. static PHONEME_TAB *phoneme_out;
  312. static int n_phcodes_list[N_PHONEME_TABS];
  313. static PHONEME_TAB_LIST phoneme_tab_list2[N_PHONEME_TABS];
  314. static PHONEME_TAB *phoneme_tab2;
  315. static int phoneme_flags;
  316. static int place_articulation;
  317. static char *p_equivalence;
  318. static char equivalence_buf[20000];
  319. #define N_PROCS 50
  320. int n_procs;
  321. int proc_addr[N_PROCS];
  322. char proc_names[40][N_PROCS];
  323. #define MAX_PROG_BUF 2000
  324. USHORT *prog_out;
  325. USHORT *prog_out_max;
  326. USHORT prog_buf[MAX_PROG_BUF+20];
  327. static void ReadPhondataManifest()
  328. {
  329. // Read the phondata-manifest file
  330. FILE *f;
  331. int n_lines = 0;
  332. int ix;
  333. char *p;
  334. unsigned int value;
  335. char buf[sizeof(path_home)+40];
  336. char name[120];
  337. sprintf(buf, "%s%c%s", path_home, PATHSEP, "phondata-manifest");
  338. if ((f = fopen(buf, "r")) == NULL)
  339. return;
  340. while (fgets(buf, sizeof(buf), f) != NULL)
  341. n_lines++;
  342. rewind(f);
  343. if (manifest != NULL) {
  344. for (ix = 0; ix < n_manifest; ix++)
  345. free(manifest[ix].name);
  346. }
  347. if ((manifest = (NAMETAB *)realloc(manifest, n_lines * sizeof(NAMETAB))) == NULL) {
  348. fclose(f);
  349. return;
  350. }
  351. n_manifest = 0;
  352. while (fgets(buf, sizeof(buf), f) != NULL) {
  353. if (!isalpha(buf[0]))
  354. continue;
  355. if (sscanf(&buf[2], "%x %s", &value, name) == 2) {
  356. if ((p = (char *)malloc(strlen(name)+1)) != NULL) {
  357. strcpy(p, name);
  358. manifest[n_manifest].value = value;
  359. manifest[n_manifest].name = p;
  360. n_manifest++;
  361. }
  362. }
  363. }
  364. fclose(f);
  365. }
  366. static const char *KeyToMnem(keywtab_t *ktab, int type, int value)
  367. {
  368. while (ktab->mnem != NULL) {
  369. if (ktab->data == value) {
  370. if ((type == -1) || (type == ktab->type))
  371. return ktab->mnem;
  372. }
  373. ktab++;
  374. }
  375. return NULL;
  376. }
  377. static void DecompilePhoneme(FILE *f_out, PHONEME_TAB *ph, int compile_phoneme)
  378. {
  379. USHORT *pc;
  380. int instn;
  381. int instn_category;
  382. int address, address2;
  383. int data1;
  384. int type2;
  385. int ix;
  386. int any;
  387. const char *name;
  388. char buf[120];
  389. static const char *instn_category_string[16] = {
  390. "", "", "IF", "IF OR",
  391. "", "", "", "",
  392. "", "", "", "FMT",
  393. "WAV", "NextVowelStart", "PrevVowelEnd", "+wav"
  394. };
  395. static const char *nextPh_string[6] = {
  396. "prevPh", "thisPh", "nextPh", "next2Ph", "nextPhW", "**",
  397. };
  398. static const char *instn0_string[] = {
  399. "invalid", "RETURN", "Continue", "DeleteNextPhoneme",
  400. };
  401. static const char *instn10_string[] = {
  402. "", "VowelIn", "VowelOut", "Tone", "",
  403. };
  404. static const char *instn_jumps[] = {
  405. "JMP", "Invalid", "Invalid", "Invalid",
  406. "JMP false", "SwitchNextVowelType", "SwitchPrevVowelType", "Invalid"
  407. };
  408. static char instn1_paramtype[] = {
  409. 0, 3, 3, 3, 3, 3, 3, 1,
  410. 1, 1, 1, 1, 1, 0, 0, 0,
  411. 3, 3, 3, 3, 3, 3, 3, 3,
  412. 0, 0, 0, 0, 0, 0, 0, 0
  413. };
  414. return;
  415. if (compile_phoneme)
  416. fprintf(f_out, "\nPhoneme %s (%d)\n", WordToString(ph->mnemonic), ph->code);
  417. else
  418. fprintf(f_out, "\nProcedure %s\n", proc_names[n_procs]);
  419. pc = prog_buf;
  420. while (pc < prog_out) {
  421. instn = *pc++;
  422. instn_category = (instn >> 12) & 0xf;
  423. data1 = instn & 0xff;
  424. type2 = (instn >> 8) & 0xf;
  425. fprintf(f_out, " %.3x: %.4x %s", (unsigned int)(pc-prog_buf), instn, instn_category_string[instn_category]);
  426. switch (instn_category)
  427. {
  428. case 0:
  429. case 1:
  430. type2 = instn >> 8;
  431. if (instn < 0x100) {
  432. if (data1 > 2)
  433. data1 = 0;
  434. fprintf(f_out, "%s", instn0_string[data1]);
  435. } else if (type2 == i_IPA_NAME) {
  436. for (ix = 0; ix < data1; ix += 2) {
  437. instn = *pc++;
  438. buf[ix] = instn >> 8;
  439. buf[ix+1] = instn & 0xff;
  440. }
  441. buf[ix] = 0;
  442. fprintf(f_out, "ipa %s", buf);
  443. } else {
  444. fprintf(f_out, "%s(", KeyToMnem(keywords, tINSTRN1, type2));
  445. switch (instn1_paramtype[type2])
  446. {
  447. case 0:
  448. fprintf(f_out, "%.4x", instn);
  449. break;
  450. case 1:
  451. fprintf(f_out, "%d", data1);
  452. break;
  453. case 3:
  454. fprintf(f_out, "%s", WordToString(phoneme_tab2[data1].mnemonic));
  455. break;
  456. }
  457. fprintf(f_out, ")");
  458. }
  459. break;
  460. case 2:
  461. case 3:
  462. if (type2 < 12) {
  463. fprintf(f_out, " %s(", nextPh_string[type2 % 6]);
  464. if (type2 >= 6) {
  465. switch (data1 >> 5)
  466. {
  467. case 0:
  468. name = KeyToMnem(keywords, tPHONEME_TYPE, (data1 & 0x1f));
  469. if (name != NULL)
  470. fprintf(f_out, "is%s", name);
  471. else
  472. fprintf(f_out, "%d %d", (data1 >> 5), (data1 & 0x1f));
  473. break;
  474. case 1:
  475. fprintf(f_out, "%d %d", (data1 >> 5), (data1 & 0x1f));
  476. break;
  477. case 2:
  478. fprintf(f_out, "%d %d", (data1 >> 5), (data1 & 0x1f));
  479. break;
  480. case 4:
  481. name = KeyToMnem(k_properties, -1, 0x80+(data1 & 0x1f));
  482. if (name != NULL)
  483. fprintf(f_out, "%s", name);
  484. else
  485. fprintf(f_out, "%d %d", (data1 >> 5), (data1 & 0x1f));
  486. break;
  487. default:
  488. fprintf(f_out, "%d %d", (data1 >> 5), (data1 & 0x1f));
  489. break;
  490. }
  491. } else {
  492. fprintf(f_out, "%s", WordToString(phoneme_tab2[data1].mnemonic));
  493. }
  494. } else if (type2 == 8) {
  495. // list of numbers
  496. fprintf(f_out, " StressLevel(");
  497. any = 0;
  498. for (ix = 0; ix < 8; ix++) {
  499. if (data1 & (1 << ix)) {
  500. if (any)
  501. fputc(',', f_out);
  502. any = 1;
  503. fprintf(f_out, "%d", ix);
  504. }
  505. }
  506. } else {
  507. name = KeyToMnem(k_conditions, tTEST, instn & 0xfff);
  508. fprintf(f_out, "%s(", name);
  509. }
  510. fprintf(f_out, ")");
  511. break;
  512. case 6:
  513. fprintf(f_out, "%s", instn_jumps[(instn >> 9) & 7]);
  514. fprintf(f_out, " %d", instn & 0x1ff);
  515. break;
  516. case 9:
  517. address = ((data1 & 0xf) << 4) + *pc++;
  518. fprintf(f_out, "CALL %.5x", address);
  519. break;
  520. case 10:
  521. fprintf(f_out, "%s", instn10_string[type2]);
  522. switch (type2)
  523. {
  524. case 1:
  525. case 2:
  526. address = (data1 << 16) + pc[0];
  527. address2 = (pc[1] << 16) + pc[2];
  528. pc += 3;
  529. fprintf(f_out, " %.6x %.8x", address, address2);
  530. break;
  531. case 3:
  532. address = ((instn & 0xf) << 16) + *pc++;
  533. address2 = ((instn & 0xf0) << 12) + *pc++;
  534. fprintf(f_out, " %.5x %.5x", address, address2);
  535. break;
  536. }
  537. break;
  538. case 11:
  539. case 12:
  540. case 13:
  541. case 14:
  542. case 15:
  543. address = ((instn & 0xf) << 16) + *pc++;
  544. fprintf(f_out, " %d %.5x", (instn >> 4) & 0xff, address*4);
  545. break;
  546. }
  547. fprintf(f_out, "\n");
  548. }
  549. }
  550. static int n_phoneme_tabs;
  551. static int n_phcodes;
  552. // outout files
  553. static FILE *f_phdata;
  554. static FILE *f_phindex;
  555. static FILE *f_phtab;
  556. static FILE *f_phcontents;
  557. static FILE *f_errors = NULL;
  558. static FILE *f_prog_log = NULL;
  559. static FILE *f_report;
  560. static FILE *f_in;
  561. static int f_in_linenum;
  562. static int f_in_displ;
  563. static int linenum;
  564. static int count_references = 0;
  565. static int duplicate_references = 0;
  566. static int count_frames = 0;
  567. static int error_count = 0;
  568. static int resample_count = 0;
  569. static int resample_fails = 0;
  570. static int then_count = 0;
  571. static int after_if = 0;
  572. static char current_fname[80];
  573. static int markers_used[8];
  574. typedef struct {
  575. void *link;
  576. int value;
  577. int ph_mnemonic;
  578. short ph_table;
  579. char string[1];
  580. } REF_HASH_TAB;
  581. static REF_HASH_TAB *ref_hash_tab[256];
  582. #define N_ENVELOPES 30
  583. int n_envelopes = 0;
  584. char envelope_paths[N_ENVELOPES][80];
  585. unsigned char envelope_dat[N_ENVELOPES][ENV_LEN];
  586. typedef struct {
  587. FILE *file;
  588. int linenum;
  589. char fname[80];
  590. } STACK;
  591. #define N_STACK 12
  592. int stack_ix;
  593. STACK stack[N_STACK];
  594. #define N_IF_STACK 12
  595. int if_level;
  596. typedef struct {
  597. USHORT *p_then;
  598. USHORT *p_else;
  599. int returned;
  600. } IF_STACK;
  601. IF_STACK if_stack[N_IF_STACK];
  602. enum {
  603. tENDFILE = 1,
  604. tSTRING,
  605. tNUMBER,
  606. tSIGNEDNUMBER,
  607. tPHONEMEMNEM,
  608. tOPENBRACKET,
  609. tKEYWORD,
  610. tCONDITION,
  611. tPROPERTIES,
  612. tINTONATION,
  613. };
  614. int item_type;
  615. int item_terminator;
  616. #define N_ITEM_STRING 256
  617. char item_string[N_ITEM_STRING];
  618. static int ref_sorter(char **a, char **b)
  619. {
  620. int ix;
  621. REF_HASH_TAB *p1 = (REF_HASH_TAB *)(*a);
  622. REF_HASH_TAB *p2 = (REF_HASH_TAB *)(*b);
  623. ix = strcoll(p1->string, p2->string);
  624. if (ix != 0)
  625. return ix;
  626. ix = p1->ph_table - p2->ph_table;
  627. if (ix != 0)
  628. return ix;
  629. return p1->ph_mnemonic - p2->ph_mnemonic;
  630. }
  631. static void CompileReport(void)
  632. {
  633. int ix;
  634. int hash;
  635. int n;
  636. REF_HASH_TAB *p;
  637. REF_HASH_TAB **list;
  638. const char *data_path;
  639. int prev_table;
  640. int procedure_num;
  641. int prev_mnemonic;
  642. if (f_report == NULL)
  643. return;
  644. // make a list of all the references and sort it
  645. list = (REF_HASH_TAB **)malloc((count_references)* sizeof(REF_HASH_TAB *));
  646. if (list == NULL)
  647. return;
  648. fprintf(f_report, "\n%d phoneme tables\n", n_phoneme_tabs);
  649. fprintf(f_report, " new total\n");
  650. for (ix = 0; ix < n_phoneme_tabs; ix++)
  651. fprintf(f_report, "%8s %3d %4d\n", phoneme_tab_list2[ix].name, phoneme_tab_list2[ix].n_phonemes, n_phcodes_list[ix]+1);
  652. fputc('\n', f_report);
  653. fprintf(f_report, "Data file Used by\n");
  654. ix = 0;
  655. for (hash = 0; (hash < 256) && (ix < count_references); hash++) {
  656. p = ref_hash_tab[hash];
  657. while (p != NULL) {
  658. list[ix++] = p;
  659. p = (REF_HASH_TAB *)(p->link);
  660. }
  661. }
  662. n = ix;
  663. qsort((void *)list, n, sizeof(REF_HASH_TAB *), (int (*)(const void *, const void *))ref_sorter);
  664. data_path = "";
  665. prev_mnemonic = 0;
  666. prev_table = 0;
  667. for (ix = 0; ix < n; ix++) {
  668. int j = 0;
  669. if (strcmp(list[ix]->string, data_path) != 0) {
  670. data_path = list[ix]->string;
  671. j = strlen(data_path);
  672. fprintf(f_report, "%s", data_path);
  673. } else if ((list[ix]->ph_table == prev_table) && (list[ix]->ph_mnemonic == prev_mnemonic))
  674. continue; // same phoneme, don't list twice
  675. while (j < 14) {
  676. fputc(' ', f_report); // pad filename with spaces
  677. j++;
  678. }
  679. prev_mnemonic = list[ix]->ph_mnemonic;
  680. if ((prev_mnemonic >> 24) == 'P') {
  681. // a procedure, not a phoneme
  682. procedure_num = atoi(WordToString(prev_mnemonic));
  683. fprintf(f_report, " %s %s", phoneme_tab_list2[prev_table = list[ix]->ph_table].name, proc_names[procedure_num]);
  684. } else
  685. fprintf(f_report, " [%s] %s", WordToString(prev_mnemonic), phoneme_tab_list2[prev_table = list[ix]->ph_table].name);
  686. fputc('\n', f_report);
  687. }
  688. for (ix = 0; ix < n; ix++) {
  689. free(list[ix]);
  690. list[ix] = NULL;
  691. }
  692. free(list);
  693. list = NULL;
  694. fclose(f_report);
  695. }
  696. static void error(const char *format, const char *string)
  697. {
  698. if (string == NULL)
  699. string = "";
  700. fprintf(f_errors, "%s(%d): ", current_fname, linenum-1);
  701. fprintf(f_errors, format, string);
  702. fprintf(f_errors, "\n");
  703. error_count++;
  704. }
  705. static void Error(const char *string)
  706. {
  707. error("%s", string);
  708. }
  709. static FILE *fopen_log(FILE *f_log, const char *fname, const char *access)
  710. {
  711. // performs fopen, but produces error message to f_log if it fails
  712. FILE *f;
  713. if ((f = fopen(fname, access)) == NULL) {
  714. if (f_log != NULL)
  715. fprintf(f_log, "Can't access (%s) file '%s'\n", access, fname);
  716. }
  717. return f;
  718. }
  719. static unsigned int StringToWord(const char *string)
  720. {
  721. // Pack 4 characters into a word
  722. int ix;
  723. unsigned char c;
  724. unsigned int word;
  725. if (string == NULL)
  726. return 0;
  727. word = 0;
  728. for (ix = 0; ix < 4; ix++) {
  729. if (string[ix] == 0) break;
  730. c = string[ix];
  731. word |= (c << (ix*8));
  732. }
  733. return word;
  734. }
  735. static MNEM_TAB reserved_phonemes[] = {
  736. { "_\001", phonCONTROL }, // NOT USED
  737. { "%", phonSTRESS_U },
  738. { "%%", phonSTRESS_D },
  739. { ",", phonSTRESS_2 },
  740. { ",,", phonSTRESS_3 },
  741. { "'", phonSTRESS_P },
  742. { "''", phonSTRESS_P2 },
  743. { "=", phonSTRESS_PREV }, // stress previous syllable
  744. { "_:", phonPAUSE }, // pause
  745. { "_", phonPAUSE_SHORT }, // short pause
  746. { "_!", phonPAUSE_NOLINK }, // short pause, no link
  747. { ":", phonLENGTHEN },
  748. { "@", phonSCHWA },
  749. { "@-", phonSCHWA_SHORT },
  750. { "||", phonEND_WORD },
  751. { "1", phonDEFAULTTONE }, // (numeral 1) default tone (for tone language)
  752. { "#X1", phonCAPITAL }, // capital letter indication
  753. { "?", phonGLOTTALSTOP }, // glottal stop
  754. { "-", phonSYLLABIC }, // syllabic consonant
  755. { "_^_", phonSWITCH }, // Change language
  756. { "_X1", phonX1 }, // a language specific action
  757. { "_|", phonPAUSE_VSHORT }, // very short pause
  758. { "_::", phonPAUSE_LONG }, // long pause
  759. { "t#", phonT_REDUCED }, // reduced version of [t]
  760. { "'!", phonSTRESS_TONIC }, // stress - emphasized
  761. { "_;_", phonPAUSE_CLAUSE }, // clause pause
  762. { "#@", phonVOWELTYPES }, // vowel type groups, these must be consecutive
  763. { "#a", phonVOWELTYPES+1 },
  764. { "#e", phonVOWELTYPES+2 },
  765. { "#i", phonVOWELTYPES+3 },
  766. { "#o", phonVOWELTYPES+4 },
  767. { "#u", phonVOWELTYPES+5 },
  768. { NULL, 0 }
  769. };
  770. static void ReservePhCodes()
  771. {
  772. // Reserve phoneme codes which have fixed numbers so that they can be
  773. // referred to from the program code.
  774. unsigned int word;
  775. MNEM_TAB *p;
  776. p = reserved_phonemes;
  777. while (p->mnem != NULL) {
  778. word = StringToWord(p->mnem);
  779. phoneme_tab2[p->value].mnemonic = word;
  780. phoneme_tab2[p->value].code = p->value;
  781. if (n_phcodes <= p->value)
  782. n_phcodes = p->value+1;
  783. p++;
  784. }
  785. }
  786. static int LookupPhoneme(const char *string, int control)
  787. {
  788. // control = 0 explicit declaration
  789. // control = 1 declare phoneme if not found
  790. // control = 2 start looking after control & stress phonemes
  791. int ix;
  792. int start;
  793. int use;
  794. unsigned int word;
  795. if (strcmp(string, "NULL") == 0)
  796. return 1;
  797. ix = strlen(string);
  798. if ((ix == 0) || (ix > 4))
  799. error("Bad phoneme name '%s'", string);
  800. word = StringToWord(string);
  801. // don't use phoneme number 0, reserved for string terminator
  802. start = 1;
  803. if (control == 2) {
  804. // don't look for control and stress phonemes (allows these characters to be
  805. // used for other purposes)
  806. start = 8;
  807. }
  808. use = 0;
  809. for (ix = start; ix < n_phcodes; ix++) {
  810. if (phoneme_tab2[ix].mnemonic == word)
  811. return ix;
  812. if ((use == 0) && (phoneme_tab2[ix].mnemonic == 0))
  813. use = ix;
  814. }
  815. if (use == 0) {
  816. if (control == 0)
  817. return -1;
  818. if (n_phcodes >= N_PHONEME_TAB-1)
  819. return -1; // phoneme table is full
  820. use = n_phcodes++;
  821. }
  822. // add this phoneme to the phoneme table
  823. phoneme_tab2[use].mnemonic = word;
  824. phoneme_tab2[use].type = phINVALID;
  825. phoneme_tab2[use].program = linenum; // for error report if the phoneme remains undeclared
  826. return use;
  827. }
  828. static unsigned int get_char()
  829. {
  830. unsigned int c;
  831. c = fgetc(f_in);
  832. if (c == '\n')
  833. linenum++;
  834. return c;
  835. }
  836. static void unget_char(unsigned int c)
  837. {
  838. ungetc(c, f_in);
  839. if (c == '\n')
  840. linenum--;
  841. }
  842. int CheckNextChar()
  843. {
  844. int c;
  845. while (((c = get_char()) == ' ') || (c == '\t'))
  846. ;
  847. unget_char(c);
  848. return c;
  849. }
  850. static int NextItem(int type)
  851. {
  852. int acc;
  853. unsigned char c = 0;
  854. unsigned char c2;
  855. int ix;
  856. int sign;
  857. char *p;
  858. keywtab_t *pk;
  859. item_type = -1;
  860. f_in_displ = ftell(f_in);
  861. f_in_linenum = linenum;
  862. while (!feof(f_in)) {
  863. c = get_char();
  864. if (c == '/') {
  865. if ((c2 = get_char()) == '/') {
  866. // comment, ignore to end of line
  867. while (!feof(f_in) && ((c = get_char()) != '\n'))
  868. ;
  869. } else
  870. unget_char(c2);
  871. }
  872. if (!isspace(c))
  873. break;
  874. }
  875. if (feof(f_in))
  876. return -2;
  877. if (c == '(') {
  878. if (type == tOPENBRACKET)
  879. return 1;
  880. return -1;
  881. }
  882. ix = 0;
  883. while (!feof(f_in) && !isspace(c) && (c != '(') && (c != ')') && (c != ',')) {
  884. if (c == '\\')
  885. c = get_char();
  886. item_string[ix++] = c;
  887. c = get_char();
  888. if (feof(f_in))
  889. break;
  890. if (item_string[ix-1] == '=')
  891. break;
  892. }
  893. item_string[ix] = 0;
  894. while (isspace(c))
  895. c = get_char();
  896. item_terminator = ' ';
  897. if ((c == ')') || (c == '(') || (c == ','))
  898. item_terminator = c;
  899. if ((c == ')') || (c == ','))
  900. c = ' ';
  901. if (!feof(f_in))
  902. unget_char(c);
  903. if (type == tSTRING)
  904. return 0;
  905. if ((type == tNUMBER) || (type == tSIGNEDNUMBER)) {
  906. acc = 0;
  907. sign = 1;
  908. p = item_string;
  909. if ((*p == '-') && (type == tSIGNEDNUMBER)) {
  910. sign = -1;
  911. p++;
  912. }
  913. if (!isdigit(*p)) {
  914. if ((type == tNUMBER) && (*p == '-'))
  915. error("Expected an unsigned number", NULL);
  916. else
  917. error("Expected a number", NULL);
  918. }
  919. while (isdigit(*p)) {
  920. acc *= 10;
  921. acc += (*p - '0');
  922. p++;
  923. }
  924. return acc * sign;
  925. }
  926. if ((type >= tKEYWORD) && (type <= tINTONATION)) {
  927. pk = keyword_tabs[type-tKEYWORD];
  928. while (pk->mnem != NULL) {
  929. if (strcmp(item_string, pk->mnem) == 0) {
  930. item_type = pk->type;
  931. return pk->data;
  932. }
  933. pk++;
  934. }
  935. item_type = -1;
  936. return -1; // keyword not found
  937. }
  938. if (type == tPHONEMEMNEM)
  939. return LookupPhoneme(item_string, 2);
  940. return -1;
  941. }
  942. static int NextItemMax(int max)
  943. {
  944. // Get a number, but restrict value to max
  945. int value;
  946. char msg[80];
  947. value = NextItem(tNUMBER);
  948. if (value > max) {
  949. sprintf(msg, "Value %d is greater than maximum %d", value, max);
  950. error(msg, NULL);
  951. value = max;
  952. }
  953. return value;
  954. }
  955. static int NextItemBrackets(int type, int control)
  956. {
  957. // Expect a parameter inside parantheses
  958. // control: bit 0 0= need (
  959. // bit 1 1= allow comma
  960. int value;
  961. if ((control & 1) == 0) {
  962. if (!NextItem(tOPENBRACKET))
  963. error("Expected '('", NULL);
  964. }
  965. value = NextItem(type);
  966. if ((control & 2) && (item_terminator == ','))
  967. return value;
  968. if (item_terminator != ')')
  969. error("Expected ')'", NULL);
  970. return value;
  971. }
  972. static void UngetItem()
  973. {
  974. fseek(f_in, f_in_displ, SEEK_SET);
  975. linenum = f_in_linenum;
  976. }
  977. static int Range(int value, int divide, int min, int max)
  978. {
  979. if (value < 0)
  980. value -= divide/2;
  981. else
  982. value += divide/2;
  983. value = value / divide;
  984. if (value > max)
  985. value = max;
  986. if (value < min)
  987. value = min;
  988. return value - min;
  989. }
  990. int CompileVowelTransition(int which)
  991. {
  992. // Compile a vowel transition
  993. int key;
  994. int len = 0;
  995. int rms = 0;
  996. int f1 = 0;
  997. int f2 = 0;
  998. int f2_min = 0;
  999. int f2_max = 0;
  1000. int f3_adj = 0;
  1001. int f3_amp = 0;
  1002. int flags = 0;
  1003. int vcolour = 0;
  1004. int x;
  1005. int instn = i_VOWELIN;
  1006. int word1;
  1007. int word2;
  1008. if (which == 1) {
  1009. len = 50 / 2; // defaults for transition into vowel
  1010. rms = 25 / 2;
  1011. if (phoneme_out->type == phSTOP) {
  1012. len = 42 / 2; // defaults for transition into vowel
  1013. rms = 30 / 2;
  1014. }
  1015. } else if (which == 2) {
  1016. instn = i_VOWELOUT;
  1017. len = 36 / 2; // defaults for transition out of vowel
  1018. rms = 16 / 2;
  1019. }
  1020. for (;;) {
  1021. key = NextItem(tKEYWORD);
  1022. if (item_type != tTRANSITION) {
  1023. UngetItem();
  1024. break;
  1025. }
  1026. switch (key & 0xf)
  1027. {
  1028. case 1:
  1029. len = Range(NextItem(tNUMBER), 2, 0, 63) & 0x3f;
  1030. flags |= 1;
  1031. break;
  1032. case 2:
  1033. rms = Range(NextItem(tNUMBER), 2, 0, 31) & 0x1f;
  1034. flags |= 1;
  1035. break;
  1036. case 3:
  1037. f1 = NextItem(tNUMBER);
  1038. break;
  1039. case 4:
  1040. f2 = Range(NextItem(tNUMBER), 50, 0, 63) & 0x3f;
  1041. f2_min = Range(NextItem(tSIGNEDNUMBER), 50, -15, 15) & 0x1f;
  1042. f2_max = Range(NextItem(tSIGNEDNUMBER), 50, -15, 15) & 0x1f;
  1043. if (f2_min > f2_max) {
  1044. x = f2_min;
  1045. f2_min = f2_max;
  1046. f2_max = x;
  1047. }
  1048. break;
  1049. case 5:
  1050. f3_adj = Range(NextItem(tSIGNEDNUMBER), 50, -15, 15) & 0x1f;
  1051. f3_amp = Range(NextItem(tNUMBER), 8, 0, 15) & 0x1f;
  1052. break;
  1053. case 6:
  1054. flags |= 2; // break
  1055. break;
  1056. case 7:
  1057. flags |= 4; // rate
  1058. break;
  1059. case 8:
  1060. flags |= 8; // glstop
  1061. break;
  1062. case 9:
  1063. flags |= 16; // lenadd
  1064. break;
  1065. case 10:
  1066. flags |= 32; // f4
  1067. break;
  1068. case 11:
  1069. flags |= 64; // pause
  1070. break;
  1071. case 12:
  1072. vcolour = NextItem(tNUMBER);
  1073. break;
  1074. case 13:
  1075. // set rms of 1st frame as fraction of rms of 2nd frame (1/30ths)
  1076. rms = (Range(NextItem(tNUMBER), 1, 0, 31) & 0x1f) | 0x20;
  1077. flags |= 1;
  1078. break;
  1079. }
  1080. }
  1081. word1 = len + (rms << 6) + (flags << 12);
  1082. word2 = f2 + (f2_min << 6) + (f2_max << 11) + (f3_adj << 16) + (f3_amp << 21) + (f1 << 26) + (vcolour << 29);
  1083. prog_out[0] = instn + ((word1 >> 16) & 0xff);
  1084. prog_out[1] = word1;
  1085. prog_out[2] = word2 >> 16;
  1086. prog_out[3] = word2;
  1087. prog_out += 4;
  1088. return 0;
  1089. }
  1090. int LoadSpect(const char *path, int control)
  1091. {
  1092. SpectSeq *spectseq;
  1093. int peak;
  1094. int displ;
  1095. int frame;
  1096. int n_frames;
  1097. int ix;
  1098. int x, x2;
  1099. int rms;
  1100. float total;
  1101. float pkheight;
  1102. int marker1_set = 0;
  1103. int frame_vowelbreak = 0;
  1104. int klatt_flag = 0;
  1105. SpectFrame *fr;
  1106. frame_t *fr_out;
  1107. char filename[sizeof(path_home)+20];
  1108. SPECT_SEQ seq_out;
  1109. SPECT_SEQK seqk_out;
  1110. // create SpectSeq and import data
  1111. spectseq = SpectSeqCreate();
  1112. if (spectseq == NULL) {
  1113. Error("Failed to create SpectSeq");
  1114. return 0;
  1115. }
  1116. snprintf(filename, sizeof(filename), "%s/../phsource/%s", path_home, path);
  1117. LoadSpectSeq(spectseq, filename);
  1118. if (spectseq->frames == NULL) {
  1119. error("Bad vowel file, no frames: '%s'", path);
  1120. SpectSeqDestroy(spectseq);
  1121. return 0;
  1122. }
  1123. // do we need additional klatt data ?
  1124. for (frame = 0; frame < spectseq->numframes; frame++) {
  1125. for (ix = 5; ix < N_KLATTP2; ix++) {
  1126. if (spectseq->frames[frame]->klatt_param[ix] != 0)
  1127. klatt_flag = FRFLAG_KLATT;
  1128. }
  1129. }
  1130. displ = ftell(f_phdata);
  1131. seq_out.n_frames = 0;
  1132. seq_out.sqflags = 0;
  1133. seq_out.length_total = 0;
  1134. total = 0;
  1135. for (frame = 0; frame < spectseq->numframes; frame++) {
  1136. if (spectseq->frames[frame]->keyframe) {
  1137. if (seq_out.n_frames == 1)
  1138. frame_vowelbreak = frame;
  1139. if (spectseq->frames[frame]->markers & 0x2) {
  1140. // marker 1 is set
  1141. marker1_set = 1;
  1142. }
  1143. seq_out.n_frames++;
  1144. if (frame > 0)
  1145. total += spectseq->frames[frame-1]->length;
  1146. }
  1147. }
  1148. seq_out.length_total = (int)total;
  1149. if ((control & 1) && (marker1_set == 0)) {
  1150. // This is a vowel, but no Vowel Break marker is set
  1151. // set a marker flag for the second frame of a vowel
  1152. spectseq->frames[frame_vowelbreak]->markers |= FRFLAG_VOWEL_CENTRE;
  1153. }
  1154. n_frames = 0;
  1155. for (frame = 0; frame < spectseq->numframes; frame++) {
  1156. fr = spectseq->frames[frame];
  1157. if (fr->keyframe) {
  1158. if (klatt_flag)
  1159. fr_out = &seqk_out.frame[n_frames];
  1160. else
  1161. fr_out = (frame_t *)&seq_out.frame[n_frames];
  1162. x = (int)(fr->length + 0.5); // round to nearest mS
  1163. if (x > 255) x = 255;
  1164. fr_out->length = x;
  1165. fr_out->frflags = fr->markers | klatt_flag;
  1166. rms = (int)GetFrameRms(fr, spectseq->amplitude);
  1167. if (rms > 255) rms = 255;
  1168. fr_out->rms = rms;
  1169. if (n_frames == (seq_out.n_frames-1))
  1170. fr_out->length = 0; // give last frame zero length
  1171. // write: peak data
  1172. count_frames++;
  1173. for (peak = 0; peak < 8; peak++) {
  1174. if (peak < 7)
  1175. fr_out->ffreq[peak] = fr->peaks[peak].pkfreq;
  1176. pkheight = spectseq->amplitude * fr->amp_adjust * fr->peaks[peak].pkheight;
  1177. pkheight = pkheight/640000;
  1178. if (pkheight > 255) pkheight = 255;
  1179. fr_out->fheight[peak] = (int)pkheight;
  1180. if (peak < 6) {
  1181. x = fr->peaks[peak].pkwidth/4;
  1182. if (x > 255) x = 255;
  1183. fr_out->fwidth[peak] = x;
  1184. if (peak < 3) {
  1185. x2 = fr->peaks[peak].pkright/4;
  1186. if (x2 > 255) x2 = 255;
  1187. fr_out->fright[peak] = x2;
  1188. }
  1189. }
  1190. if (peak < 4) {
  1191. x = fr->peaks[peak].klt_bw / 2;
  1192. if (x > 255) x = 255;
  1193. fr_out->bw[peak] = x;
  1194. }
  1195. }
  1196. for (ix = 0; ix < 5; ix++) {
  1197. fr_out->klattp[ix] = fr->klatt_param[ix];
  1198. fr_out->klattp[KLATT_FNZ] = fr->klatt_param[KLATT_FNZ] / 2;
  1199. }
  1200. if (klatt_flag) {
  1201. // additional klatt parameters
  1202. for (ix = 0; ix < 5; ix++)
  1203. fr_out->klattp2[ix] = fr->klatt_param[ix+5];
  1204. for (peak = 0; peak < 7; peak++) {
  1205. fr_out->klatt_ap[ix] = fr->peaks[peak].klt_ap;
  1206. x = fr->peaks[peak].klt_bp / 2;
  1207. if (x > 255) x = 255;
  1208. fr_out->klatt_bp[ix] = x;
  1209. }
  1210. }
  1211. if (fr_out->bw[1] == 0) {
  1212. fr_out->bw[0] = 89 / 2;
  1213. fr_out->bw[1] = 90 / 2;
  1214. fr_out->bw[2] = 140 / 2;
  1215. fr_out->bw[3] = 260 / 2;
  1216. }
  1217. n_frames++;
  1218. }
  1219. }
  1220. if (klatt_flag) {
  1221. seqk_out.n_frames = seq_out.n_frames;
  1222. seqk_out.sqflags = seq_out.sqflags;
  1223. seqk_out.length_total = seq_out.length_total;
  1224. ix = (char *)(&seqk_out.frame[seqk_out.n_frames]) - (char *)(&seqk_out);
  1225. ix = (ix+3) & 0xfffc; // round up to multiple of 4 bytes
  1226. fwrite(&seqk_out, ix, 1, f_phdata);
  1227. } else {
  1228. ix = (char *)(&seq_out.frame[seq_out.n_frames]) - (char *)(&seq_out);
  1229. ix = (ix+3) & 0xfffc; // round up to multiple of 4 bytes
  1230. fwrite(&seq_out, ix, 1, f_phdata);
  1231. }
  1232. SpectSeqDestroy(spectseq);
  1233. return displ;
  1234. }
  1235. static int LoadWavefile(FILE *f, const char *fname)
  1236. {
  1237. int displ;
  1238. unsigned char c1;
  1239. unsigned char c3;
  1240. int c2;
  1241. int sample;
  1242. int sample2;
  1243. float x;
  1244. int max = 0;
  1245. int length;
  1246. int sr1, sr2;
  1247. int failed;
  1248. int len;
  1249. int resample_wav = 0;
  1250. const char *fname2;
  1251. char fname_temp[100];
  1252. char msg[120];
  1253. int scale_factor = 0;
  1254. fseek(f, 24, SEEK_SET);
  1255. sr1 = Read4Bytes(f);
  1256. sr2 = Read4Bytes(f);
  1257. fseek(f, 40, SEEK_SET);
  1258. if ((sr1 != samplerate_native) || (sr2 != sr1*2)) {
  1259. int fd_temp;
  1260. char command[sizeof(path_home)+250];
  1261. failed = 0;
  1262. #ifdef PLATFORM_POSIX
  1263. strcpy(fname_temp, "/tmp/espeakXXXXXX");
  1264. if ((fd_temp = mkstemp(fname_temp)) >= 0)
  1265. close(fd_temp);
  1266. #else
  1267. strcpy(fname_temp, tmpnam(NULL));
  1268. #endif
  1269. fname2 = fname;
  1270. len = strlen(fname);
  1271. if (strcmp(&fname[len-4], ".wav") == 0) {
  1272. strcpy(msg, fname);
  1273. msg[len-4] = 0;
  1274. fname2 = msg;
  1275. }
  1276. sprintf(command, "sox \"%s/../phsource/%s.wav\" -r %d -c1 -t wav %s\n", path_home, fname2, samplerate_native, fname_temp);
  1277. if (system(command) != 0)
  1278. failed = 1;
  1279. if (failed || (GetFileLength(fname_temp) <= 0)) {
  1280. if (resample_fails < 2)
  1281. error("Resample command failed: %s", command);
  1282. resample_fails++;
  1283. if (sr1 != samplerate_native) {
  1284. sprintf(msg, "Can't resample (%d to %d): %s", sr1, samplerate_native, fname);
  1285. error("%s", msg);
  1286. } else
  1287. error("WAV file is not mono: %s", fname);
  1288. remove(fname_temp);
  1289. return 0;
  1290. }
  1291. f = fopen(fname_temp, "rb");
  1292. if (f == NULL) {
  1293. error("Can't read temp file: %s", fname_temp);
  1294. return 0;
  1295. }
  1296. if (f_report != NULL)
  1297. fprintf(f_report, "resampled %s\n", fname);
  1298. resample_count++;
  1299. resample_wav = 1;
  1300. fseek(f, 40, SEEK_SET); // skip past the WAV header, up to before "data length"
  1301. }
  1302. displ = ftell(f_phdata);
  1303. // data contains: 4 bytes of length (n_samples * 2), followed by 2-byte samples (lsb byte first)
  1304. length = Read4Bytes(f);
  1305. while (!feof(f)) {
  1306. c1 = fgetc(f);
  1307. c3 = fgetc(f);
  1308. if (feof(f)) break;
  1309. c2 = c3 << 24;
  1310. c2 = c2 >> 16; // sign extend
  1311. sample = (c1 & 0xff) + c2;
  1312. if (sample > max)
  1313. max = sample;
  1314. else if (sample < -max)
  1315. max = -sample;
  1316. }
  1317. scale_factor = (max / 127) + 1;
  1318. #define MIN_FACTOR -1 // was 6, disable use of 16 bit samples
  1319. if (scale_factor > MIN_FACTOR) {
  1320. length = length/2 + (scale_factor << 16);
  1321. }
  1322. Write4Bytes(f_phdata, length);
  1323. fseek(f, 44, SEEK_SET);
  1324. while (!feof(f)) {
  1325. c1 = fgetc(f);
  1326. c3 = fgetc(f);
  1327. c2 = c3 << 24;
  1328. c2 = c2 >> 16; // sign extend
  1329. sample = (c1 & 0xff) + c2;
  1330. if (feof(f)) break;
  1331. if (scale_factor <= MIN_FACTOR) {
  1332. fputc(sample & 0xff, f_phdata);
  1333. fputc(sample >> 8, f_phdata);
  1334. } else {
  1335. x = ((float)sample / scale_factor) + 0.5;
  1336. sample2 = (int)x;
  1337. if (sample2 > 127)
  1338. sample2 = 127;
  1339. if (sample2 < -128)
  1340. sample2 = -128;
  1341. fputc(sample2, f_phdata);
  1342. }
  1343. }
  1344. length = ftell(f_phdata);
  1345. while ((length & 3) != 0) {
  1346. // pad to a multiple of 4 bytes
  1347. fputc(0, f_phdata);
  1348. length++;
  1349. }
  1350. if (resample_wav != 0) {
  1351. fclose(f);
  1352. remove(fname_temp);
  1353. }
  1354. return displ | 0x800000; // set bit 23 to indicate a wave file rather than a spectrum
  1355. }
  1356. static int LoadEnvelope(FILE *f, const char *fname)
  1357. {
  1358. int displ;
  1359. char buf[128];
  1360. displ = ftell(f_phdata);
  1361. fseek(f, 12, SEEK_SET);
  1362. if (fread(buf, 128, 1, f) == 0)
  1363. error("Failed to read envelope: %s", fname);
  1364. fwrite(buf, 128, 1, f_phdata);
  1365. if (n_envelopes < N_ENVELOPES) {
  1366. strncpy0(envelope_paths[n_envelopes], fname, sizeof(envelope_paths[0]));
  1367. memcpy(envelope_dat[n_envelopes], buf, sizeof(envelope_dat[0]));
  1368. n_envelopes++;
  1369. }
  1370. return displ;
  1371. }
  1372. // Generate a hash code from the specified string
  1373. static int Hash8(const char *string)
  1374. {
  1375. int c;
  1376. int chars = 0;
  1377. int hash = 0;
  1378. while ((c = *string++) != 0) {
  1379. c = tolower(c) - 'a';
  1380. hash = hash * 8 + c;
  1381. hash = (hash & 0x1ff) ^ (hash >> 8); // exclusive or
  1382. chars++;
  1383. }
  1384. return (hash+chars) & 0xff;
  1385. }
  1386. static int LoadEnvelope2(FILE *f, const char *fname)
  1387. {
  1388. int ix, ix2;
  1389. int n;
  1390. int x, y;
  1391. int displ;
  1392. int n_points;
  1393. double yy;
  1394. char line_buf[128];
  1395. float env_x[20];
  1396. float env_y[20];
  1397. int env_lin[20];
  1398. unsigned char env[ENV_LEN];
  1399. n_points = 0;
  1400. fgets(line_buf, sizeof(line_buf), f); // skip first line
  1401. while (!feof(f)) {
  1402. if (fgets(line_buf, sizeof(line_buf), f) == NULL)
  1403. break;
  1404. env_lin[n_points] = 0;
  1405. n = sscanf(line_buf, "%f %f %d", &env_x[n_points], &env_y[n_points], &env_lin[n_points]);
  1406. if (n >= 2) {
  1407. env_x[n_points] *= (float)1.28; // convert range 0-100 to 0-128
  1408. n_points++;
  1409. }
  1410. }
  1411. env_x[n_points] = env_x[n_points-1];
  1412. env_y[n_points] = env_y[n_points-1];
  1413. ix = -1;
  1414. ix2 = 0;
  1415. for (x = 0; x < ENV_LEN; x++) {
  1416. if (x > env_x[ix+4])
  1417. ix++;
  1418. if (x >= env_x[ix2+1])
  1419. ix2++;
  1420. if (env_lin[ix2] > 0) {
  1421. yy = env_y[ix2] + (env_y[ix2+1] - env_y[ix2]) * ((float)x - env_x[ix2]) / (env_x[ix2+1] - env_x[ix2]);
  1422. y = (int)(yy * 2.55);
  1423. } else if (n_points > 3)
  1424. y = (int)(polint(&env_x[ix], &env_y[ix], 4, x) * 2.55); // convert to range 0-255
  1425. else
  1426. y = (int)(polint(&env_x[ix], &env_y[ix], 3, x) * 2.55);
  1427. if (y < 0) y = 0;
  1428. if (y > 255) y = 255;
  1429. env[x] = y;
  1430. }
  1431. if (n_envelopes < N_ENVELOPES) {
  1432. strncpy0(envelope_paths[n_envelopes], fname, sizeof(envelope_paths[0]));
  1433. memcpy(envelope_dat[n_envelopes], env, ENV_LEN);
  1434. n_envelopes++;
  1435. }
  1436. displ = ftell(f_phdata);
  1437. fwrite(env, 1, 128, f_phdata);
  1438. return displ;
  1439. }
  1440. static int LoadDataFile(const char *path, int control)
  1441. {
  1442. // load spectrum sequence or sample data from a file.
  1443. // return index into spect or sample data area. bit 23=1 if a sample
  1444. FILE *f;
  1445. int id;
  1446. int hash;
  1447. int addr = 0;
  1448. int type_code = ' ';
  1449. REF_HASH_TAB *p, *p2;
  1450. char buf[sizeof(path_home)+150];
  1451. if (strcmp(path, "NULL") == 0)
  1452. return 0;
  1453. if (strcmp(path, "DFT") == 0)
  1454. return 1;
  1455. count_references++;
  1456. hash = Hash8(path);
  1457. p = ref_hash_tab[hash];
  1458. while (p != NULL) {
  1459. if (strcmp(path, p->string) == 0) {
  1460. duplicate_references++;
  1461. addr = p->value; // already loaded this data
  1462. break;
  1463. }
  1464. p = (REF_HASH_TAB *)p->link;
  1465. }
  1466. if (addr == 0) {
  1467. sprintf(buf, "%s/../phsource/%s", path_home, path);
  1468. if ((f = fopen(buf, "rb")) == NULL) {
  1469. sprintf(buf, "%s/../phsource/%s.wav", path_home, path);
  1470. if ((f = fopen(buf, "rb")) == NULL) {
  1471. error("Can't read file: %s", path);
  1472. return 0;
  1473. }
  1474. }
  1475. id = Read4Bytes(f);
  1476. rewind(f);
  1477. if (id == 0x43455053) {
  1478. addr = LoadSpect(path, control);
  1479. type_code = 'S';
  1480. } else if (id == 0x46464952) {
  1481. addr = LoadWavefile(f, path);
  1482. type_code = 'W';
  1483. } else if (id == 0x43544950) {
  1484. addr = LoadEnvelope(f, path);
  1485. type_code = 'E';
  1486. } else if (id == 0x45564E45) {
  1487. addr = LoadEnvelope2(f, path);
  1488. type_code = 'E';
  1489. } else {
  1490. error("File not SPEC or RIFF: %s", path);
  1491. addr = -1;
  1492. }
  1493. fclose(f);
  1494. if (addr > 0)
  1495. fprintf(f_phcontents, "%c 0x%.5x %s\n", type_code, addr & 0x7fffff, path);
  1496. }
  1497. // add this item to the hash table
  1498. if (addr > 0) {
  1499. p = ref_hash_tab[hash];
  1500. p2 = (REF_HASH_TAB *)malloc(sizeof(REF_HASH_TAB)+strlen(path)+1);
  1501. p2->value = addr;
  1502. p2->ph_mnemonic = phoneme_out->mnemonic; // phoneme which uses this file
  1503. p2->ph_table = n_phoneme_tabs-1;
  1504. strcpy(p2->string, path);
  1505. p2->link = (char *)p;
  1506. ref_hash_tab[hash] = p2;
  1507. }
  1508. return addr;
  1509. }
  1510. static int CompileToneSpec(void)
  1511. {
  1512. int pitch1 = 0;
  1513. int pitch2 = 0;
  1514. int pitch_env = 0;
  1515. int amp_env = 0;
  1516. pitch1 = NextItemBrackets(tNUMBER, 2);
  1517. pitch2 = NextItemBrackets(tNUMBER, 3);
  1518. if (item_terminator == ',') {
  1519. NextItemBrackets(tSTRING, 3);
  1520. pitch_env = LoadDataFile(item_string, 0);
  1521. }
  1522. if (item_terminator == ',') {
  1523. NextItemBrackets(tSTRING, 1);
  1524. amp_env = LoadDataFile(item_string, 0);
  1525. }
  1526. if (pitch1 < pitch2) {
  1527. phoneme_out->start_type = pitch1;
  1528. phoneme_out->end_type = pitch2;
  1529. } else {
  1530. phoneme_out->start_type = pitch2;
  1531. phoneme_out->end_type = pitch1;
  1532. }
  1533. if (pitch_env != 0) {
  1534. *prog_out++ = i_PITCHENV + ((pitch_env >> 16) & 0xf);
  1535. *prog_out++ = pitch_env;
  1536. }
  1537. if (amp_env != 0) {
  1538. *prog_out++ = i_AMPENV + ((amp_env >> 16) & 0xf);
  1539. *prog_out++ = amp_env;
  1540. }
  1541. return 0;
  1542. }
  1543. int CompileSound(int keyword, int isvowel)
  1544. {
  1545. int addr;
  1546. int value = 0;
  1547. char path[N_ITEM_STRING];
  1548. static int sound_instns[] = { i_FMT, i_WAV, i_VWLSTART, i_VWLENDING, i_WAVADD };
  1549. NextItemBrackets(tSTRING, 2);
  1550. strcpy(path, item_string);
  1551. if (item_terminator == ',') {
  1552. if ((keyword == kVOWELSTART) || (keyword == kVOWELENDING)) {
  1553. value = NextItemBrackets(tSIGNEDNUMBER, 1);
  1554. if (value > 127) {
  1555. value = 127;
  1556. error("Parameter > 127", NULL);
  1557. }
  1558. if (value < -128) {
  1559. value = -128;
  1560. error("Parameter < -128", NULL);
  1561. }
  1562. } else {
  1563. value = NextItemBrackets(tNUMBER, 1);
  1564. if (value > 255) {
  1565. value = 255;
  1566. error("Parameter > 255", NULL);
  1567. }
  1568. }
  1569. }
  1570. addr = LoadDataFile(path, isvowel);
  1571. addr = addr / 4; // addr is words not bytes
  1572. *prog_out++ = sound_instns[keyword-kFMT] + ((value & 0xff) << 4) + ((addr >> 16) & 0xf);
  1573. *prog_out++ = addr & 0xffff;
  1574. return 0;
  1575. }
  1576. /*
  1577. Condition
  1578. bits 14,15 1
  1579. bit 13 1 = AND, 0 = OR
  1580. bit 12 spare
  1581. bit 8-11
  1582. =0-3 p,t,n,n2 data=phoneme code
  1583. =4-7 p,t,n,n2 data=(bits5-7: phtype, place, property, special) (bits0-4: data)
  1584. =8 data = stress bitmap
  1585. =9 special tests
  1586. */
  1587. int CompileIf(int elif)
  1588. {
  1589. int key;
  1590. int finish = 0;
  1591. int word = 0;
  1592. int word2;
  1593. int data;
  1594. int bitmap;
  1595. int brackets;
  1596. int not_flag;
  1597. USHORT *prog_last_if = NULL;
  1598. then_count = 2;
  1599. after_if = 1;
  1600. while (!finish) {
  1601. not_flag = 0;
  1602. word2 = 0;
  1603. if (prog_out >= prog_out_max) {
  1604. error("Phoneme program too large", NULL);
  1605. return 0;
  1606. }
  1607. if ((key = NextItem(tCONDITION)) < 0)
  1608. error("Expected a condition, not '%s'", item_string);
  1609. if ((item_type == 0) && (key == k_NOT)) {
  1610. not_flag = 1;
  1611. if ((key = NextItem(tCONDITION)) < 0)
  1612. error("Expected a condition, not '%s'", item_string);
  1613. }
  1614. if (item_type == tWHICH_PHONEME) {
  1615. // prevPh(), thisPh(), nextPh(), next2Ph() etc
  1616. if (key >= 6) {
  1617. // put the 'which' code in the next instruction
  1618. word2 = key;
  1619. key = 6;
  1620. }
  1621. key = key << 8;
  1622. data = NextItemBrackets(tPROPERTIES, 0);
  1623. if (data >= 0)
  1624. word = key + data + 0x700;
  1625. else {
  1626. data = LookupPhoneme(item_string, 2);
  1627. word = key + data;
  1628. }
  1629. } else if (item_type == tTEST) {
  1630. if (key == kTHISSTRESS) {
  1631. bitmap = 0;
  1632. brackets = 2;
  1633. do {
  1634. data = NextItemBrackets(tNUMBER, brackets);
  1635. if (data > 7)
  1636. error("Expected list of stress levels", NULL);
  1637. bitmap |= (1 << data);
  1638. brackets = 3;
  1639. } while (item_terminator == ',');
  1640. word = i_StressLevel | bitmap;
  1641. } else
  1642. word = key;
  1643. } else {
  1644. error("Unexpected keyword '%s'", item_string);
  1645. if ((strcmp(item_string, "phoneme") == 0) || (strcmp(item_string, "endphoneme") == 0))
  1646. return -1;
  1647. }
  1648. // output the word
  1649. prog_last_if = prog_out;
  1650. *prog_out++ = word | i_CONDITION;
  1651. if (word2 != 0)
  1652. *prog_out++ = word2;
  1653. if (not_flag)
  1654. *prog_out++ = i_NOT;
  1655. // expect AND, OR, THEN
  1656. switch (NextItem(tCONDITION))
  1657. {
  1658. case k_AND:
  1659. break;
  1660. case k_OR:
  1661. if (prog_last_if != NULL)
  1662. *prog_last_if |= i_OR;
  1663. break;
  1664. case k_THEN:
  1665. finish = 1;
  1666. break;
  1667. default:
  1668. error("Expected AND, OR, THEN", NULL);
  1669. break;
  1670. }
  1671. }
  1672. if (elif == 0) {
  1673. if_level++;
  1674. if_stack[if_level].p_else = NULL;
  1675. }
  1676. if_stack[if_level].returned = 0;
  1677. if_stack[if_level].p_then = prog_out;
  1678. *prog_out++ = i_JUMP_FALSE;
  1679. return 0;
  1680. }
  1681. void FillThen(int add)
  1682. {
  1683. USHORT *p;
  1684. int offset;
  1685. p = if_stack[if_level].p_then;
  1686. if (p != NULL) {
  1687. offset = prog_out - p + add;
  1688. if ((then_count == 1) && (if_level == 1)) {
  1689. // The THEN part only contains one statement, we can remove the THEN jump
  1690. // and the interpreter will implicitly skip the statement.
  1691. while (p < prog_out) {
  1692. p[0] = p[1];
  1693. p++;
  1694. }
  1695. prog_out--;
  1696. } else {
  1697. if (offset > MAX_JUMP)
  1698. error("IF block is too long", NULL);
  1699. *p = i_JUMP_FALSE + offset;
  1700. }
  1701. if_stack[if_level].p_then = NULL;
  1702. }
  1703. then_count = 0;
  1704. }
  1705. int CompileElse(void)
  1706. {
  1707. USHORT *ref;
  1708. USHORT *p;
  1709. if (if_level < 1) {
  1710. error("ELSE not expected", NULL);
  1711. return 0;
  1712. }
  1713. if (if_stack[if_level].returned == 0)
  1714. FillThen(1);
  1715. else
  1716. FillThen(0);
  1717. if (if_stack[if_level].returned == 0) {
  1718. ref = prog_out;
  1719. *prog_out++ = 0;
  1720. if ((p = if_stack[if_level].p_else) != NULL)
  1721. *ref = ref - p; // backwards offset to the previous else
  1722. if_stack[if_level].p_else = ref;
  1723. }
  1724. return 0;
  1725. }
  1726. int CompileElif(void)
  1727. {
  1728. if (if_level < 1) {
  1729. error("ELIF not expected", NULL);
  1730. return 0;
  1731. }
  1732. CompileElse();
  1733. CompileIf(1);
  1734. return 0;
  1735. }
  1736. int CompileEndif(void)
  1737. {
  1738. USHORT *p;
  1739. int chain;
  1740. int offset;
  1741. if (if_level < 1) {
  1742. error("ENDIF not expected", NULL);
  1743. return 0;
  1744. }
  1745. FillThen(0);
  1746. if ((p = if_stack[if_level].p_else) != NULL) {
  1747. do {
  1748. chain = *p; // a chain of previous else links
  1749. offset = prog_out - p;
  1750. if (offset > MAX_JUMP)
  1751. error("IF block is too long", NULL);
  1752. *p = i_JUMP + offset;
  1753. p -= chain;
  1754. } while (chain > 0);
  1755. }
  1756. if_level--;
  1757. return 0;
  1758. }
  1759. static int CompileSwitch(int type)
  1760. {
  1761. // Type 0: EndSwitch
  1762. // 1: SwitchPrevVowelType
  1763. // 2: SwitchNextVowelType
  1764. if (type == 0) {
  1765. // check the instructions in the Switch
  1766. return 0;
  1767. }
  1768. if (type == 1)
  1769. *prog_out++ = i_SWITCH_PREVVOWEL+6;
  1770. if (type == 2)
  1771. *prog_out++ = i_SWITCH_NEXTVOWEL+6;
  1772. return 0;
  1773. }
  1774. static PHONEME_TAB_LIST *FindPhonemeTable(const char *string)
  1775. {
  1776. int ix;
  1777. for (ix = 0; ix < n_phoneme_tabs; ix++) {
  1778. if (strcmp(phoneme_tab_list2[ix].name, string) == 0)
  1779. return &phoneme_tab_list2[ix];
  1780. }
  1781. error("Unknown phoneme table: '%s'", string);
  1782. return NULL;
  1783. }
  1784. static PHONEME_TAB *FindPhoneme(const char *string)
  1785. {
  1786. PHONEME_TAB_LIST *phtab = NULL;
  1787. int ix;
  1788. unsigned int mnem;
  1789. char *phname;
  1790. char buf[200];
  1791. // is this the name of a phoneme which is in scope
  1792. if ((strlen(string) <= 4) && ((ix = LookupPhoneme(string, 0)) != -1))
  1793. return &phoneme_tab2[ix];
  1794. // no, treat the name as phonemetable/phoneme
  1795. strcpy(buf, string);
  1796. if ((phname = strchr(buf, '/')) != 0)
  1797. *phname++ = 0;
  1798. phtab = FindPhonemeTable(buf);
  1799. if (phtab == NULL)
  1800. return NULL; // phoneme table not found
  1801. mnem = StringToWord(phname);
  1802. for (ix = 1; ix < 256; ix++) {
  1803. if (mnem == phtab->phoneme_tab_ptr[ix].mnemonic)
  1804. return &phtab->phoneme_tab_ptr[ix];
  1805. }
  1806. error("Phoneme reference not found: '%s'", string);
  1807. return NULL;
  1808. }
  1809. static void ImportPhoneme(void)
  1810. {
  1811. unsigned int ph_mnem;
  1812. unsigned int ph_code;
  1813. PHONEME_TAB *ph;
  1814. NextItem(tSTRING);
  1815. if ((ph = FindPhoneme(item_string)) == NULL)
  1816. return;
  1817. ph_mnem = phoneme_out->mnemonic;
  1818. ph_code = phoneme_out->code;
  1819. memcpy(phoneme_out, ph, sizeof(PHONEME_TAB));
  1820. phoneme_out->mnemonic = ph_mnem;
  1821. phoneme_out->code = ph_code;
  1822. if (phoneme_out->type != phVOWEL)
  1823. phoneme_out->end_type = 0; // voicingswitch, this must be set later to refer to a local phoneme
  1824. }
  1825. static void CallPhoneme(void)
  1826. {
  1827. PHONEME_TAB *ph;
  1828. int ix;
  1829. int addr = 0;
  1830. NextItem(tSTRING);
  1831. // first look for a procedure name
  1832. for (ix = 0; ix < n_procs; ix++) {
  1833. if (strcmp(proc_names[ix], item_string) == 0) {
  1834. addr = proc_addr[ix];
  1835. break;
  1836. }
  1837. }
  1838. if (ix == n_procs) {
  1839. // procedure not found, try a phoneme name
  1840. if ((ph = FindPhoneme(item_string)) == NULL)
  1841. return;
  1842. addr = ph->program;
  1843. if (phoneme_out->type == phINVALID) {
  1844. // Phoneme type has not been set. Copy it from the called phoneme
  1845. phoneme_out->type = ph->type;
  1846. phoneme_flags = ph->phflags & ~phARTICULATION;
  1847. place_articulation = (ph->phflags & phARTICULATION) >> 16;
  1848. phoneme_out->start_type = ph->start_type;
  1849. phoneme_out->end_type = ph->end_type;
  1850. phoneme_out->std_length = ph->std_length;
  1851. phoneme_out->length_mod = ph->length_mod;
  1852. }
  1853. }
  1854. *prog_out++ = i_CALLPH + (addr >> 16);
  1855. *prog_out++ = addr;
  1856. }
  1857. static void DecThenCount()
  1858. {
  1859. if (then_count > 0)
  1860. then_count--;
  1861. }
  1862. static void InstnPlusPhoneme(int instn)
  1863. {
  1864. int phcode;
  1865. phcode = NextItemBrackets(tPHONEMEMNEM, 0);
  1866. *prog_out++ = instn + phcode;
  1867. }
  1868. int CompilePhoneme(int compile_phoneme)
  1869. {
  1870. int endphoneme = 0;
  1871. int keyword;
  1872. int value;
  1873. int phcode = 0;
  1874. int flags;
  1875. int ix;
  1876. int start;
  1877. int count;
  1878. int c;
  1879. char *p;
  1880. int vowel_length_factor = 100; // for testing
  1881. char number_buf[12];
  1882. char ipa_buf[N_ITEM_STRING+1];
  1883. PHONEME_TAB phoneme_out2;
  1884. PHONEME_PROG_LOG phoneme_prog_log;
  1885. prog_out = prog_buf;
  1886. prog_out_max = &prog_buf[MAX_PROG_BUF-1];
  1887. if_level = 0;
  1888. if_stack[0].returned = 0;
  1889. after_if = 0;
  1890. phoneme_flags = 0;
  1891. place_articulation = 0;
  1892. NextItem(tSTRING);
  1893. if (compile_phoneme) {
  1894. phcode = LookupPhoneme(item_string, 1); // declare phoneme if not already there
  1895. if (phcode == -1) return 0;
  1896. phoneme_out = &phoneme_tab2[phcode];
  1897. } else {
  1898. // declare a procedure
  1899. if (n_procs >= N_PROCS) {
  1900. error("Too many procedures", NULL);
  1901. return 0;
  1902. }
  1903. strcpy(proc_names[n_procs], item_string);
  1904. phoneme_out = &phoneme_out2;
  1905. sprintf(number_buf, "%.3dP", n_procs);
  1906. phoneme_out->mnemonic = StringToWord(number_buf);
  1907. }
  1908. phoneme_out->code = phcode;
  1909. phoneme_out->program = 0;
  1910. phoneme_out->type = phINVALID;
  1911. phoneme_out->std_length = 0;
  1912. phoneme_out->start_type = 0;
  1913. phoneme_out->end_type = 0;
  1914. phoneme_out->length_mod = 0;
  1915. while (!endphoneme && !feof(f_in)) {
  1916. if ((keyword = NextItem(tKEYWORD)) < 0) {
  1917. if (keyword == -2) {
  1918. error("Missing 'endphoneme' before end-of-file", NULL); // end of file
  1919. break;
  1920. }
  1921. error("Bad keyword in phoneme definition '%s'", item_string);
  1922. continue;
  1923. }
  1924. switch (item_type)
  1925. {
  1926. case tPHONEME_TYPE:
  1927. if (phoneme_out->type != phINVALID)
  1928. error("More than one phoneme type: %s", item_string);
  1929. phoneme_out->type = keyword;
  1930. break;
  1931. case tPLACE:
  1932. if (place_articulation > 0)
  1933. error("Place of articulation has already been given: %s", item_string);
  1934. place_articulation = keyword;
  1935. break;
  1936. case tPHONEME_FLAG:
  1937. phoneme_flags |= keyword;
  1938. break;
  1939. case tINSTRN1:
  1940. // instruction group 0, with 8 bit operands which set data in PHONEME_DATA
  1941. switch (keyword)
  1942. {
  1943. case i_CHANGE_PHONEME:
  1944. case i_APPEND_PHONEME:
  1945. case i_APPEND_IFNEXTVOWEL:
  1946. case i_INSERT_PHONEME:
  1947. case i_REPLACE_NEXT_PHONEME:
  1948. case i_VOICING_SWITCH:
  1949. case i_CHANGE_IF+0:
  1950. case i_CHANGE_IF+1:
  1951. case i_CHANGE_IF+2:
  1952. case i_CHANGE_IF+3:
  1953. InstnPlusPhoneme(keyword << 8);
  1954. DecThenCount();
  1955. break;
  1956. case i_PAUSE_BEFORE:
  1957. value = NextItemMax(255);
  1958. *prog_out++ = (i_PAUSE_BEFORE << 8) + value;
  1959. DecThenCount();
  1960. break;
  1961. case i_PAUSE_AFTER:
  1962. value = NextItemMax(255);
  1963. *prog_out++ = (i_PAUSE_AFTER << 8) + value;
  1964. DecThenCount();
  1965. break;
  1966. case i_SET_LENGTH:
  1967. value = NextItemMax(511);
  1968. if (phoneme_out->type == phVOWEL)
  1969. value = (value * vowel_length_factor)/100;
  1970. if (after_if == 0)
  1971. phoneme_out->std_length = value/2;
  1972. else {
  1973. *prog_out++ = (i_SET_LENGTH << 8) + value/2;
  1974. DecThenCount();
  1975. }
  1976. break;
  1977. case i_ADD_LENGTH:
  1978. value = NextItem(tSIGNEDNUMBER) / 2;
  1979. *prog_out++ = (i_ADD_LENGTH << 8) + (value & 0xff);
  1980. DecThenCount();
  1981. break;
  1982. case i_LENGTH_MOD:
  1983. value = NextItem(tNUMBER);
  1984. phoneme_out->length_mod = value;
  1985. break;
  1986. case i_IPA_NAME:
  1987. NextItem(tSTRING);
  1988. if (strcmp(item_string, "NULL") == 0)
  1989. strcpy(item_string, " ");
  1990. // copy the string, recognize characters in the form U+9999
  1991. flags = 0;
  1992. count = 0;
  1993. ix = 1;
  1994. for (p = item_string; *p != 0;) {
  1995. p += utf8_in(&c, p);
  1996. if ((c == '|') && (count > 0)) {
  1997. // '|' means don't allow a tie or joiner before this letter
  1998. flags |= (1 << (count -1));
  1999. } else if ((c == 'U') && (p[0] == '+')) {
  2000. int j;
  2001. // U+9999
  2002. p++;
  2003. memcpy(number_buf, p, 4); // U+ should be followed by 4 hex digits
  2004. number_buf[4] = 0;
  2005. c = '#';
  2006. sscanf(number_buf, "%x", &c);
  2007. // move past the 4 hexdecimal digits
  2008. for (j = 0; j < 4; j++) {
  2009. if (!isalnum(*p))
  2010. break;
  2011. p++;
  2012. }
  2013. ix += utf8_out(c, &ipa_buf[ix]);
  2014. count++;
  2015. } else {
  2016. ix += utf8_out(c, &ipa_buf[ix]);
  2017. count++;
  2018. }
  2019. }
  2020. ipa_buf[0] = flags;
  2021. ipa_buf[ix] = 0;
  2022. start = 1;
  2023. if (flags != 0)
  2024. start = 0; // only include the flags byte if bits are set
  2025. value = strlen(&ipa_buf[start]); // number of UTF-8 bytes
  2026. *prog_out++ = (i_IPA_NAME << 8) + value;
  2027. for (ix = 0; ix < value; ix += 2)
  2028. *prog_out++ = (ipa_buf[ix+start] << 8) + (ipa_buf[ix+start+1] & 0xff);
  2029. DecThenCount();
  2030. break;
  2031. }
  2032. break;
  2033. case tSTATEMENT:
  2034. switch (keyword)
  2035. {
  2036. case kIMPORT_PH:
  2037. ImportPhoneme();
  2038. phoneme_flags = phoneme_out->phflags;
  2039. break;
  2040. case kSTARTTYPE:
  2041. phcode = NextItem(tPHONEMEMNEM);
  2042. if (phcode == -1)
  2043. phcode = LookupPhoneme(item_string, 1);
  2044. phoneme_out->start_type = phcode;
  2045. break;
  2046. case kENDTYPE:
  2047. phcode = NextItem(tPHONEMEMNEM);
  2048. if (phcode == -1)
  2049. phcode = LookupPhoneme(item_string, 1);
  2050. if (phoneme_out->type == phVOWEL)
  2051. phoneme_out->end_type = phcode;
  2052. else if (phcode != phoneme_out->start_type)
  2053. error("endtype must equal starttype for consonants", NULL);
  2054. break;
  2055. case kVOICINGSWITCH:
  2056. phcode = NextItem(tPHONEMEMNEM);
  2057. if (phcode == -1)
  2058. phcode = LookupPhoneme(item_string, 1);
  2059. phoneme_out->end_type = phcode; // use end_type field for consonants as voicing_switch
  2060. break;
  2061. case kSTRESSTYPE:
  2062. value = NextItem(tNUMBER);
  2063. phoneme_out->std_length = value;
  2064. if (prog_out > prog_buf) {
  2065. error("stress phonemes can't contain program instructions", NULL);
  2066. prog_out = prog_buf;
  2067. }
  2068. break;
  2069. case kIF:
  2070. endphoneme = CompileIf(0);
  2071. break;
  2072. case kELSE:
  2073. endphoneme = CompileElse();
  2074. break;
  2075. case kELIF:
  2076. endphoneme = CompileElif();
  2077. break;
  2078. case kENDIF:
  2079. endphoneme = CompileEndif();
  2080. break;
  2081. case kENDSWITCH:
  2082. break;
  2083. case kSWITCH_PREVVOWEL:
  2084. endphoneme = CompileSwitch(1);
  2085. break;
  2086. case kSWITCH_NEXTVOWEL:
  2087. endphoneme = CompileSwitch(2);
  2088. break;
  2089. case kCALLPH:
  2090. CallPhoneme();
  2091. DecThenCount();
  2092. break;
  2093. case kFMT:
  2094. if_stack[if_level].returned = 1;
  2095. DecThenCount();
  2096. if (phoneme_out->type == phVOWEL)
  2097. endphoneme = CompileSound(keyword, 1);
  2098. else
  2099. endphoneme = CompileSound(keyword, 0);
  2100. break;
  2101. case kWAV:
  2102. if_stack[if_level].returned = 1;
  2103. // fallthrough:
  2104. case kVOWELSTART:
  2105. case kVOWELENDING:
  2106. case kANDWAV:
  2107. DecThenCount();
  2108. endphoneme = CompileSound(keyword, 0);
  2109. break;
  2110. case kVOWELIN:
  2111. DecThenCount();
  2112. endphoneme = CompileVowelTransition(1);
  2113. break;
  2114. case kVOWELOUT:
  2115. DecThenCount();
  2116. endphoneme = CompileVowelTransition(2);
  2117. break;
  2118. case kTONESPEC:
  2119. DecThenCount();
  2120. endphoneme = CompileToneSpec();
  2121. break;
  2122. case kCONTINUE:
  2123. *prog_out++ = i_CONTINUE;
  2124. DecThenCount();
  2125. break;
  2126. case kRETURN:
  2127. *prog_out++ = i_RETURN;
  2128. DecThenCount();
  2129. break;
  2130. case kINCLUDE:
  2131. case kPHONEMENUMBER:
  2132. case kPHONEMETABLE:
  2133. error("Missing 'endphoneme' before '%s'", item_string); // drop through to endphoneme
  2134. // fallthrough:
  2135. case kENDPHONEME:
  2136. case kENDPROCEDURE:
  2137. endphoneme = 1;
  2138. if (if_level > 0)
  2139. error("Missing ENDIF", NULL);
  2140. if ((prog_out > prog_buf) && (if_stack[0].returned == 0))
  2141. *prog_out++ = i_RETURN;
  2142. break;
  2143. }
  2144. break;
  2145. }
  2146. }
  2147. if (endphoneme != 1)
  2148. error("'endphoneme' not expected here", NULL);
  2149. if (compile_phoneme) {
  2150. if (phoneme_out->type == phINVALID) {
  2151. error("Phoneme type is missing", NULL);
  2152. phoneme_out->type = 0;
  2153. }
  2154. phoneme_out->phflags = place_articulation << 16;
  2155. phoneme_out->phflags |= phoneme_flags;
  2156. if (phoneme_out->phflags & phVOICED) {
  2157. if (phoneme_out->type == phSTOP)
  2158. phoneme_out->type = phVSTOP;
  2159. else if (phoneme_out->type == phFRICATIVE)
  2160. phoneme_out->type = phVFRICATIVE;
  2161. }
  2162. if (phoneme_out->std_length == 0) {
  2163. if (phoneme_out->type == phVOWEL)
  2164. phoneme_out->std_length = 180/2; // default length for vowel
  2165. }
  2166. phoneme_out->phflags |= phLOCAL; // declared in this phoneme table
  2167. if (phoneme_out->type == phDELETED)
  2168. phoneme_out->mnemonic = 0x01; // will not be recognised
  2169. }
  2170. DecompilePhoneme(f_errors, phoneme_out, compile_phoneme);
  2171. if (prog_out > prog_buf) {
  2172. // write out the program for this phoneme
  2173. fflush(f_phindex);
  2174. phoneme_out->program = ftell(f_phindex) / sizeof(USHORT);
  2175. if (f_prog_log != NULL) {
  2176. phoneme_prog_log.addr = phoneme_out->program;
  2177. phoneme_prog_log.length = prog_out - prog_buf;
  2178. fwrite(&phoneme_prog_log, 1, sizeof(phoneme_prog_log), f_prog_log);
  2179. }
  2180. if (compile_phoneme == 0)
  2181. proc_addr[n_procs++] = ftell(f_phindex) / sizeof(USHORT);
  2182. fwrite(prog_buf, sizeof(USHORT), prog_out - prog_buf, f_phindex);
  2183. }
  2184. return 0;
  2185. }
  2186. static void WritePhonemeTables()
  2187. {
  2188. int ix;
  2189. int j;
  2190. int n;
  2191. int value;
  2192. int count;
  2193. PHONEME_TAB *p;
  2194. value = n_phoneme_tabs;
  2195. fputc(value, f_phtab);
  2196. fputc(0, f_phtab);
  2197. fputc(0, f_phtab);
  2198. fputc(0, f_phtab);
  2199. for (ix = 0; ix < n_phoneme_tabs; ix++) {
  2200. p = phoneme_tab_list2[ix].phoneme_tab_ptr;
  2201. n = n_phcodes_list[ix];
  2202. p[n].mnemonic = 0; // terminate the phoneme table
  2203. // count number of locally declared phonemes
  2204. count = 0;
  2205. for (j = 0; j < n; j++) {
  2206. if (ix == 0)
  2207. p[j].phflags |= phLOCAL; // write all phonemes in the base phoneme table
  2208. if (p[j].phflags & phLOCAL)
  2209. count++;
  2210. }
  2211. phoneme_tab_list2[ix].n_phonemes = count+1;
  2212. fputc(count+1, f_phtab);
  2213. fputc(phoneme_tab_list2[ix].includes, f_phtab);
  2214. fputc(0, f_phtab);
  2215. fputc(0, f_phtab);
  2216. Write4Bytes(f_phtab, phoneme_tab_list2[ix].equivalence_tables); // byte index into phondata for equivalence tables
  2217. fwrite(phoneme_tab_list2[ix].name, 1, N_PHONEME_TAB_NAME, f_phtab);
  2218. for (j = 0; j < n; j++) {
  2219. if (p[j].phflags & phLOCAL) {
  2220. // this bit is set temporarily to incidate a local phoneme, declared in
  2221. // in the current phoneme file
  2222. p[j].phflags &= ~phLOCAL;
  2223. fwrite(&p[j], sizeof(PHONEME_TAB), 1, f_phtab);
  2224. }
  2225. }
  2226. fwrite(&p[n], sizeof(PHONEME_TAB), 1, f_phtab); // include the extra list-terminator phoneme entry
  2227. free(p);
  2228. }
  2229. }
  2230. static void EndPhonemeTable()
  2231. {
  2232. int ix;
  2233. int *pw;
  2234. int length;
  2235. if (n_phoneme_tabs == 0)
  2236. return;
  2237. // check that all referenced phonemes have been declared
  2238. for (ix = 0; ix < n_phcodes; ix++) {
  2239. if (phoneme_tab2[ix].type == phINVALID) {
  2240. fprintf(f_errors, "%3d: Phoneme [%s] not declared, referenced at line %d\n", linenum,
  2241. WordToString(phoneme_tab2[ix].mnemonic), (int)(phoneme_tab2[ix].program));
  2242. error_count++;
  2243. phoneme_tab2[ix].type = 0; // prevent the error message repeating
  2244. }
  2245. }
  2246. n_phcodes_list[n_phoneme_tabs-1] = n_phcodes;
  2247. if ((length = p_equivalence - equivalence_buf) > 0) {
  2248. // terminate the list of phoneme equivalence tables
  2249. pw = (int *)p_equivalence;
  2250. pw[0] = 0;
  2251. // write the equivalence data into phondata, and remember it's address
  2252. ix = ftell(f_phdata);
  2253. fprintf(f_phcontents, "Q 0x%.5x %s\n", ix, phoneme_tab_list2[n_phoneme_tabs-1].name);
  2254. phoneme_tab_list2[n_phoneme_tabs-1].equivalence_tables = ix;
  2255. fwrite(equivalence_buf, length+4, 1, f_phdata);
  2256. }
  2257. }
  2258. static void StartPhonemeTable(const char *name)
  2259. {
  2260. int ix;
  2261. int j;
  2262. PHONEME_TAB *p;
  2263. if (n_phoneme_tabs >= N_PHONEME_TABS-1) {
  2264. Error("Too many phonemetables");
  2265. return;
  2266. }
  2267. p = (PHONEME_TAB *)calloc(sizeof(PHONEME_TAB), N_PHONEME_TAB);
  2268. if (p == NULL) {
  2269. Error("Out of memory");
  2270. return;
  2271. }
  2272. memset(&phoneme_tab_list2[n_phoneme_tabs], 0, sizeof(PHONEME_TAB_LIST));
  2273. phoneme_tab_list2[n_phoneme_tabs].phoneme_tab_ptr = phoneme_tab2 = p;
  2274. strncpy0(phoneme_tab_list2[n_phoneme_tabs].name, name, N_PHONEME_TAB_NAME);
  2275. n_phcodes = 1;
  2276. phoneme_tab_list2[n_phoneme_tabs].includes = 0;
  2277. p_equivalence = equivalence_buf;
  2278. if (n_phoneme_tabs > 0) {
  2279. NextItem(tSTRING); // name of base phoneme table
  2280. for (ix = 0; ix < n_phoneme_tabs; ix++) {
  2281. if (strcmp(item_string, phoneme_tab_list2[ix].name) == 0) {
  2282. phoneme_tab_list2[n_phoneme_tabs].includes = ix+1;
  2283. // initialise the new phoneme table with the contents of this one
  2284. memcpy(phoneme_tab2, phoneme_tab_list2[ix].phoneme_tab_ptr, sizeof(PHONEME_TAB)*N_PHONEME_TAB);
  2285. n_phcodes = n_phcodes_list[ix];
  2286. // clear "local phoneme" bit"
  2287. for (j = 0; j < n_phcodes; j++)
  2288. phoneme_tab2[j].phflags &= ~phLOCAL;
  2289. break;
  2290. }
  2291. }
  2292. if (ix == n_phoneme_tabs)
  2293. error("Can't find base phonemetable '%s'", item_string);
  2294. } else
  2295. ReservePhCodes();
  2296. n_phoneme_tabs++;
  2297. }
  2298. static void CompileEquivalents()
  2299. {
  2300. // a list of phonemes in another language and the equivalent phoneme strings in this language
  2301. int ix;
  2302. int n_names;
  2303. int n_bytes;
  2304. int foreign_phoneme;
  2305. int foreign_error = 0;
  2306. int remove_stress = 0;
  2307. char *p_start;
  2308. char *p;
  2309. int foreign_table;
  2310. char foreign_table_name[40];
  2311. char line_buf[80];
  2312. char names[6][80];
  2313. char phcode[7];
  2314. NextItem(tSTRING);
  2315. strcpy(foreign_table_name, item_string);
  2316. if ((foreign_table = SelectPhonemeTableName(foreign_table_name)) < 0) {
  2317. if (strcmp(foreign_table_name, "NULL") != 0)
  2318. error("Unknown phoneme table '%s'", foreign_table_name);
  2319. foreign_error = 1;
  2320. foreign_phoneme = 0;
  2321. }
  2322. p_start = p_equivalence;
  2323. p_equivalence += 8;
  2324. p_start[0] = foreign_table;
  2325. linenum--;
  2326. while (!feof(f_in)) {
  2327. linenum++;
  2328. if (fgets(line_buf, sizeof(line_buf), f_in) == NULL)
  2329. break;
  2330. if ((p = strstr(line_buf, "//")) != NULL)
  2331. *p = 0;
  2332. for (ix = 0; ix < 6; ix++)
  2333. names[ix][0] = 0;
  2334. n_names = sscanf(line_buf, "%s %s %s %s %s %s", names[0], names[1], names[2], names[3], names[4], names[5]);
  2335. if (n_names < 1)
  2336. continue;
  2337. if (strcmp(names[0], "endphoneme") == 0)
  2338. break;
  2339. if (foreign_error)
  2340. continue;
  2341. if (strcmp(names[0], "remove_stress") == 0) {
  2342. remove_stress = 1;
  2343. continue;
  2344. }
  2345. if (p_equivalence > &equivalence_buf[sizeof(equivalence_buf) - 16]) {
  2346. error("'equivalents' tables are too large", NULL);
  2347. break;
  2348. }
  2349. if (foreign_error == 0) {
  2350. phcode[0] = foreign_phoneme = LookupPhonemeString(names[0]);
  2351. if (foreign_phoneme == 0) {
  2352. sprintf(line_buf, "%s/%s", foreign_table_name, names[0]);
  2353. error("Unknown phoneme '%s'", line_buf);
  2354. }
  2355. }
  2356. for (ix = 1; ix < n_names; ix++)
  2357. phcode[ix] = LookupPhoneme(names[ix], 1);
  2358. // only write a translation if it has an effect
  2359. if ((n_names > 2) || (phcode[0] != phcode[1])) {
  2360. // write: foreign phoneme number, then a string of local phoneme numbers
  2361. memcpy(p_equivalence, phcode, n_names);
  2362. p_equivalence += n_names;
  2363. *p_equivalence++ = 0;
  2364. }
  2365. }
  2366. *p_equivalence++ = 0;
  2367. p_equivalence = (char *)((intptr_t)(p_equivalence + 3) & ~0x3); // align to word boundary
  2368. n_bytes = p_equivalence - p_start;
  2369. p_start[1] = remove_stress;
  2370. n_bytes = n_bytes / 4;
  2371. p_start[2] = n_bytes >> 8; // index of next table
  2372. p_start[3] = n_bytes;
  2373. }
  2374. static void CompilePhonemeFiles()
  2375. {
  2376. int item;
  2377. FILE *f;
  2378. char buf[sizeof(path_home)+120];
  2379. linenum = 1;
  2380. count_references = 0;
  2381. duplicate_references = 0;
  2382. count_frames = 0;
  2383. n_procs = 0;
  2384. for (;;) {
  2385. if (feof(f_in)) {
  2386. // end of file, go back to previous from, from which this was included
  2387. if (stack_ix == 0)
  2388. break; // end of top level, finished
  2389. fclose(f_in);
  2390. f_in = stack[--stack_ix].file;
  2391. strcpy(current_fname, stack[stack_ix].fname);
  2392. linenum = stack[stack_ix].linenum;
  2393. }
  2394. item = NextItem(tKEYWORD);
  2395. switch (item)
  2396. {
  2397. case kUTF8_BOM:
  2398. break; // ignore bytes 0xef 0xbb 0xbf
  2399. case kINCLUDE:
  2400. NextItem(tSTRING);
  2401. sprintf(buf, "%s/../phsource/%s", path_home, item_string);
  2402. if ((stack_ix < N_STACK) && (f = fopen_log(f_errors, buf, "rb")) != NULL) {
  2403. stack[stack_ix].linenum = linenum;
  2404. strcpy(stack[stack_ix].fname, current_fname);
  2405. stack[stack_ix++].file = f_in;
  2406. f_in = f;
  2407. strncpy0(current_fname, item_string, sizeof(current_fname));
  2408. linenum = 1;
  2409. } else
  2410. error("Missing file: %s", item_string);
  2411. break;
  2412. case kPHONEMETABLE:
  2413. EndPhonemeTable();
  2414. NextItem(tSTRING); // name of the new phoneme table
  2415. StartPhonemeTable(item_string);
  2416. break;
  2417. case kPHONEMESTART:
  2418. if (n_phoneme_tabs == 0) {
  2419. Error("phonemetable is missing");
  2420. return;
  2421. }
  2422. CompilePhoneme(1);
  2423. break;
  2424. case kPROCEDURE:
  2425. CompilePhoneme(0);
  2426. break;
  2427. case kEQUIVALENTS:
  2428. CompileEquivalents();
  2429. break;
  2430. default:
  2431. if (!feof(f_in))
  2432. Error("Keyword 'phoneme' expected");
  2433. break;
  2434. }
  2435. }
  2436. phoneme_tab2[n_phcodes+1].mnemonic = 0; // terminator
  2437. }
  2438. static espeak_ng_STATUS CompilePhonemeData2(const char *source, FILE *log)
  2439. {
  2440. char fname[sizeof(path_home)+40];
  2441. sprintf(fname, "%s/../phsource", path_home);
  2442. fprintf(log, "Compiling phoneme data: %s\n", fname);
  2443. n_envelopes = 0;
  2444. error_count = 0;
  2445. resample_count = 0;
  2446. memset(markers_used, 0, sizeof(markers_used));
  2447. f_errors = log;
  2448. if (!access(fname, 755)) {
  2449. fprintf(log, "Can't find phoneme source directory: %s\n", fname);
  2450. return ENE_READ_ERROR;
  2451. }
  2452. strncpy0(current_fname, source, sizeof(current_fname));
  2453. sprintf(fname, "%s/../phsource/phonemes", path_home);
  2454. f_in = fopen_log(f_errors, fname, "rb");
  2455. if (f_in == NULL) {
  2456. fprintf(log, "Can't read master phonemes file: %s\n", fname);
  2457. return ENE_READ_ERROR;
  2458. }
  2459. sprintf(fname, "%s/../phsource/%s", path_home, "compile_report");
  2460. f_report = fopen_log(f_errors, fname, "w");
  2461. sprintf(fname, "%s/%s", path_home, "phondata-manifest");
  2462. if ((f_phcontents = fopen_log(f_phcontents, fname, "w")) == NULL)
  2463. f_phcontents = stderr;
  2464. fprintf(f_phcontents,
  2465. "# This file lists the type of data that has been compiled into the\n"
  2466. "# phondata file\n"
  2467. "#\n"
  2468. "# The first character of a line indicates the type of data:\n"
  2469. "# S - A SPECT_SEQ structure\n"
  2470. "# W - A wavefile segment\n"
  2471. "# E - An envelope\n"
  2472. "# Q - Phoneme equivalence tables\n"
  2473. "#\n"
  2474. "# Address is the displacement within phondata of this item\n"
  2475. "#\n"
  2476. "# Address Data file\n"
  2477. "# ------- ---------\n");
  2478. sprintf(fname, "%s/%s", path_home, "phondata");
  2479. f_phdata = fopen_log(f_errors, fname, "wb");
  2480. sprintf(fname, "%s/%s", path_home, "phonindex");
  2481. f_phindex = fopen_log(f_errors, fname, "wb");
  2482. sprintf(fname, "%s/%s", path_home, "phontab");
  2483. f_phtab = fopen_log(f_errors, fname, "wb");
  2484. if (f_phdata == NULL || f_phindex == NULL || f_phtab == NULL)
  2485. return ENE_WRITE_ERROR;
  2486. sprintf(fname, "%s/../phsource/compile_prog_log", path_home);
  2487. f_prog_log = fopen_log(f_errors, fname, "wb");
  2488. fprintf(log, "Compiling phoneme data: %s/../phsource\n", path_home);
  2489. // write a word so that further data doesn't start at displ=0
  2490. Write4Bytes(f_phdata, version_phdata);
  2491. Write4Bytes(f_phdata, samplerate_native);
  2492. Write4Bytes(f_phindex, version_phdata);
  2493. memset(ref_hash_tab, 0, sizeof(ref_hash_tab));
  2494. n_phoneme_tabs = 0;
  2495. stack_ix = 0;
  2496. StartPhonemeTable("base");
  2497. CompilePhonemeFiles();
  2498. EndPhonemeTable();
  2499. WritePhonemeTables();
  2500. fprintf(f_errors, "\nRefs %d, Reused %d\n", count_references, duplicate_references);
  2501. fclose(f_in);
  2502. fclose(f_phdata);
  2503. if (f_prog_log != NULL)
  2504. fclose(f_prog_log);
  2505. fclose(f_phindex);
  2506. fclose(f_phtab);
  2507. fclose(f_phcontents);
  2508. LoadPhData(NULL);
  2509. CompileReport();
  2510. if (resample_count > 0) {
  2511. fprintf(f_errors, "\n%d WAV files resampled to %d Hz\n", resample_count, samplerate_native);
  2512. fprintf(log, "Compiled phonemes: %d errors, %d files resampled to %d Hz.\n", error_count, resample_count, samplerate_native);
  2513. } else
  2514. fprintf(log, "Compiled phonemes: %d errors.\n", error_count);
  2515. if (f_errors != stderr && f_errors != stdout)
  2516. fclose(f_errors);
  2517. ReadPhondataManifest();
  2518. return ENS_OK;
  2519. }
  2520. static const char *preset_tune_names[] = {
  2521. "s1", "c1", "q1", "e1", NULL
  2522. };
  2523. static const TUNE default_tune = {
  2524. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  2525. { 0, 0, 0, 0 },
  2526. { 0, 40, 24, 8, 0, 0, 0, 0 },
  2527. 46, 57, PITCHfall, 16, 0, 0,
  2528. 255, 78, 50, 255,
  2529. 3, 5,
  2530. { -7, -7, -7 }, { -7, -7, -7 },
  2531. PITCHfall, 64, 8,
  2532. PITCHfall, 70, 18, 24, 12,
  2533. PITCHfall, 70, 18, 24, 12, 0,
  2534. { 0, 0, 0, 0, 0, 0, 0, 0 }, 0
  2535. };
  2536. #define N_TUNE_NAMES 100
  2537. MNEM_TAB envelope_names[] = {
  2538. { "fall", 0 },
  2539. { "rise", 2 },
  2540. { "fall-rise", 4 },
  2541. { "fall-rise2", 6 },
  2542. { "rise-fall", 8 },
  2543. { "fall-rise3", 10 },
  2544. { "fall-rise4", 12 },
  2545. { "fall2", 14 },
  2546. { "rise2", 16 },
  2547. { "rise-fall-rise", 18 },
  2548. { NULL, -1 }
  2549. };
  2550. int LookupEnvelopeName(const char *name)
  2551. {
  2552. return LookupMnem(envelope_names, name);
  2553. }
  2554. #pragma GCC visibility push(default)
  2555. espeak_ng_STATUS espeak_ng_CompileIntonation(FILE *log)
  2556. {
  2557. if (!log) log = stderr;
  2558. int ix;
  2559. char *p;
  2560. char c;
  2561. int keyword;
  2562. int compiling_tune = 0;
  2563. int n_tune_names = 0;
  2564. int done_split;
  2565. int done_onset = 0;
  2566. int done_last = 0;
  2567. int n_preset_tunes = 0;
  2568. int found;
  2569. int tune_number = 0;
  2570. FILE *f_out;
  2571. TUNE *tune_data;
  2572. TUNE new_tune;
  2573. char name[12];
  2574. char tune_names[N_TUNE_NAMES][12];
  2575. char buf[sizeof(path_home)+150];
  2576. error_count = 0;
  2577. f_errors = log;
  2578. sprintf(buf, "%s/../phsource/intonation.txt", path_home);
  2579. if ((f_in = fopen(buf, "r")) == NULL) {
  2580. sprintf(buf, "%s/../phsource/intonation", path_home);
  2581. if ((f_in = fopen_log(f_errors, buf, "r")) == NULL) {
  2582. fprintf(log, "Can't read file: %s\n", buf);
  2583. fclose(f_errors);
  2584. return ENE_READ_ERROR;
  2585. }
  2586. }
  2587. for (ix = 0; preset_tune_names[ix] != NULL; ix++)
  2588. strcpy(tune_names[ix], preset_tune_names[ix]);
  2589. n_tune_names = ix;
  2590. n_preset_tunes = ix;
  2591. // make a list of the tune names
  2592. while (!feof(f_in)) {
  2593. if (fgets(buf, sizeof(buf), f_in) == NULL)
  2594. break;
  2595. if ((memcmp(buf, "tune", 4) == 0) && isspace(buf[4])) {
  2596. p = &buf[5];
  2597. while (isspace(*p)) p++;
  2598. ix = 0;
  2599. while ((ix < (int)(sizeof(name) - 1)) && !isspace(*p))
  2600. name[ix++] = *p++;
  2601. name[ix] = 0;
  2602. found = 0;
  2603. for (ix = 0; ix < n_tune_names; ix++) {
  2604. if (strcmp(name, tune_names[ix]) == 0) {
  2605. found = 1;
  2606. break;
  2607. }
  2608. }
  2609. if (found == 0) {
  2610. strncpy0(tune_names[n_tune_names++], name, sizeof(name));
  2611. if (n_tune_names >= N_TUNE_NAMES)
  2612. break;
  2613. }
  2614. }
  2615. }
  2616. rewind(f_in);
  2617. linenum = 1;
  2618. tune_data = (TUNE *)calloc(sizeof(TUNE), n_tune_names);
  2619. if (tune_data == NULL) {
  2620. fprintf(f_errors, "Failed to allocate data for tunes\n");
  2621. fclose(f_in);
  2622. fclose(f_errors);
  2623. return ENE_OUT_OF_MEMORY;
  2624. }
  2625. sprintf(buf, "%s/intonations", path_home);
  2626. f_out = fopen_log(f_errors, buf, "wb");
  2627. if (f_out == NULL) {
  2628. fclose(f_in);
  2629. fclose(f_errors);
  2630. free(tune_data);
  2631. return ENE_WRITE_ERROR;
  2632. }
  2633. while (!feof(f_in)) {
  2634. keyword = NextItem(tINTONATION);
  2635. switch (keyword)
  2636. {
  2637. case kTUNE:
  2638. compiling_tune = 1;
  2639. done_split = 0;
  2640. memcpy(&new_tune, &default_tune, sizeof(TUNE));
  2641. NextItem(tSTRING);
  2642. strncpy0(new_tune.name, item_string, sizeof(new_tune.name));
  2643. found = 0;
  2644. tune_number = 0;
  2645. for (ix = 0; ix < n_tune_names; ix++) {
  2646. if (strcmp(new_tune.name, tune_names[ix]) == 0) {
  2647. found = 1;
  2648. tune_number = ix;
  2649. if (tune_data[ix].name[0] != 0)
  2650. found = 2;
  2651. break;
  2652. }
  2653. }
  2654. if (found == 2)
  2655. error("Duplicate tune name: '%s'", new_tune.name);
  2656. if (found == 0)
  2657. error("Bad tune name: '%s;", new_tune.name);
  2658. break;
  2659. case kENDTUNE:
  2660. compiling_tune = 0;
  2661. if (done_onset == 0) {
  2662. new_tune.unstr_start[0] = new_tune.unstr_start[1];
  2663. new_tune.unstr_end[0] = new_tune.unstr_end[1];
  2664. }
  2665. if (done_last == 0) {
  2666. new_tune.unstr_start[2] = new_tune.unstr_start[1];
  2667. new_tune.unstr_end[2] = new_tune.unstr_end[1];
  2668. }
  2669. memcpy(&tune_data[tune_number], &new_tune, sizeof(TUNE));
  2670. break;
  2671. case kTUNE_PREHEAD:
  2672. new_tune.prehead_start = NextItem(tNUMBER);
  2673. new_tune.prehead_end = NextItem(tNUMBER);
  2674. break;
  2675. case kTUNE_ONSET:
  2676. new_tune.onset = NextItem(tNUMBER);
  2677. new_tune.unstr_start[0] = NextItem(tSIGNEDNUMBER);
  2678. new_tune.unstr_end[0] = NextItem(tSIGNEDNUMBER);
  2679. done_onset = 1;
  2680. break;
  2681. case kTUNE_HEADLAST:
  2682. new_tune.head_last = NextItem(tNUMBER);
  2683. new_tune.unstr_start[2] = NextItem(tSIGNEDNUMBER);
  2684. new_tune.unstr_end[2] = NextItem(tSIGNEDNUMBER);
  2685. done_last = 1;
  2686. break;
  2687. case kTUNE_HEADENV:
  2688. NextItem(tSTRING);
  2689. if ((ix = LookupEnvelopeName(item_string)) < 0)
  2690. error("Bad envelope name: '%s'", item_string);
  2691. else
  2692. new_tune.stressed_env = ix;
  2693. new_tune.stressed_drop = NextItem(tNUMBER);
  2694. break;
  2695. case kTUNE_HEAD:
  2696. new_tune.head_max_steps = NextItem(tNUMBER);
  2697. new_tune.head_start = NextItem(tNUMBER);
  2698. new_tune.head_end = NextItem(tNUMBER);
  2699. new_tune.unstr_start[1] = NextItem(tSIGNEDNUMBER);
  2700. new_tune.unstr_end[1] = NextItem(tSIGNEDNUMBER);
  2701. break;
  2702. case kTUNE_HEADEXTEND:
  2703. // up to 8 numbers
  2704. for (ix = 0; ix < (int)(sizeof(new_tune.head_extend)); ix++) {
  2705. if (!isdigit(c = CheckNextChar()) && (c != '-'))
  2706. break;
  2707. new_tune.head_extend[ix] = (NextItem(tSIGNEDNUMBER) * 64) / 100; // convert from percentage to 64ths
  2708. }
  2709. new_tune.n_head_extend = ix; // number of values
  2710. break;
  2711. case kTUNE_NUCLEUS0:
  2712. NextItem(tSTRING);
  2713. if ((ix = LookupEnvelopeName(item_string)) < 0) {
  2714. error("Bad envelope name: '%s'", item_string);
  2715. break;
  2716. }
  2717. new_tune.nucleus0_env = ix;
  2718. new_tune.nucleus0_max = NextItem(tNUMBER);
  2719. new_tune.nucleus0_min = NextItem(tNUMBER);
  2720. break;
  2721. case kTUNE_NUCLEUS1:
  2722. NextItem(tSTRING);
  2723. if ((ix = LookupEnvelopeName(item_string)) < 0) {
  2724. error("Bad envelope name: '%s'", item_string);
  2725. break;
  2726. }
  2727. new_tune.nucleus1_env = ix;
  2728. new_tune.nucleus1_max = NextItem(tNUMBER);
  2729. new_tune.nucleus1_min = NextItem(tNUMBER);
  2730. new_tune.tail_start = NextItem(tNUMBER);
  2731. new_tune.tail_end = NextItem(tNUMBER);
  2732. if (!done_split) {
  2733. // also this as the default setting for 'split'
  2734. new_tune.split_nucleus_env = ix;
  2735. new_tune.split_nucleus_max = new_tune.nucleus1_max;
  2736. new_tune.split_nucleus_min = new_tune.nucleus1_min;
  2737. new_tune.split_tail_start = new_tune.tail_start;
  2738. new_tune.split_tail_end = new_tune.tail_end;
  2739. }
  2740. break;
  2741. case kTUNE_SPLIT:
  2742. NextItem(tSTRING);
  2743. if ((ix = LookupEnvelopeName(item_string)) < 0) {
  2744. error("Bad envelope name: '%s'", item_string);
  2745. break;
  2746. }
  2747. done_split = 1;
  2748. new_tune.split_nucleus_env = ix;
  2749. new_tune.split_nucleus_max = NextItem(tNUMBER);
  2750. new_tune.split_nucleus_min = NextItem(tNUMBER);
  2751. new_tune.split_tail_start = NextItem(tNUMBER);
  2752. new_tune.split_tail_end = NextItem(tNUMBER);
  2753. NextItem(tSTRING);
  2754. item_string[12] = 0;
  2755. for (ix = 0; ix < n_tune_names; ix++) {
  2756. if (strcmp(item_string, tune_names[ix]) == 0)
  2757. break;
  2758. }
  2759. if (ix == n_tune_names)
  2760. error("Tune '%s' not found", item_string);
  2761. else
  2762. new_tune.split_tune = ix;
  2763. break;
  2764. default:
  2765. error("Unexpected: '%s'", item_string);
  2766. break;
  2767. }
  2768. }
  2769. for (ix = 0; ix < n_preset_tunes; ix++) {
  2770. if (tune_data[ix].name[0] == 0)
  2771. error("Tune '%s' not defined", preset_tune_names[ix]);
  2772. }
  2773. fwrite(tune_data, n_tune_names, sizeof(TUNE), f_out);
  2774. free(tune_data);
  2775. fclose(f_in);
  2776. fclose(f_out);
  2777. fprintf(log, "Compiled %d intonation tunes: %d errors.\n", n_tune_names, error_count);
  2778. LoadPhData(NULL);
  2779. return error_count > 0 ? ENE_COMPILE_ERRORS : ENS_OK;
  2780. }
  2781. espeak_ng_STATUS espeak_ng_CompilePhonemeData(long rate, FILE *log)
  2782. {
  2783. if (!log) log = stderr;
  2784. WavegenInit(rate, 0);
  2785. WavegenSetVoice(voice);
  2786. return CompilePhonemeData2("phonemes", log);
  2787. }
  2788. #pragma GCC visibility pop