KlattGrid.cpp 113 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951
  1. /* KlattGrid.cpp
  2. *
  3. * Copyright (C) 2008-2017 David Weenink, 2015,2017 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. djmw 20080917 Initial version
  20. djmw 20090109 Add formulas for formant frequencies and bandwidths.
  21. djmw 20090123 Add PlayOptions.
  22. djmw 20090129 KlattGrid_draw text in boxes displays better
  23. djmw 20090311 Add RealTier_valuesInRange
  24. djmw 20090312 Add klattGrid_addFormantAndBandwidthTier
  25. djmw 20090326 Changed DBSPL_to_A into DB_to_A for bypass and formant amplitudes.
  26. djmw 20100223 Removed gsl dependency
  27. djmw 20110304 Thing_new
  28. djmw 20110308 struc connections -> struct structconnections
  29. djmw 20110329 Table_get(Numeric|String)Value is now Table_get(Numeric|String)Value_Assert
  30. djmw 20111011 Sound_VocalTractGrid_CouplingGrid_filter_cascade: group warnings
  31. */
  32. #include "FormantGrid_extensions.h"
  33. #include "Formula.h"
  34. #include "KlattGrid.h"
  35. #include "KlattTable.h"
  36. #include "Resonator.h"
  37. #include "Pitch_to_PitchTier.h"
  38. #include "PitchTier_to_Sound.h"
  39. #include "PitchTier_to_PointProcess.h"
  40. #include "NUM2.h"
  41. #include "Sound_to_Formant.h"
  42. #include "Sound_to_Intensity.h"
  43. #include "Sound_to_Pitch.h"
  44. #include "oo_DESTROY.h"
  45. #include "KlattGrid_def.h"
  46. #include "oo_COPY.h"
  47. #include "KlattGrid_def.h"
  48. #include "oo_EQUAL.h"
  49. #include "KlattGrid_def.h"
  50. #include "oo_CAN_WRITE_AS_ENCODING.h"
  51. #include "KlattGrid_def.h"
  52. #include "oo_WRITE_TEXT.h"
  53. #include "KlattGrid_def.h"
  54. #include "oo_WRITE_BINARY.h"
  55. #include "KlattGrid_def.h"
  56. #include "oo_READ_TEXT.h"
  57. #include "KlattGrid_def.h"
  58. #include "oo_READ_BINARY.h"
  59. #include "KlattGrid_def.h"
  60. #include "oo_DESCRIPTION.h"
  61. #include "KlattGrid_def.h"
  62. /*
  63. * A KlattGrid consists of a great many tiers that can be independently modified.
  64. *
  65. * For any particular formant, the formant frequency tier and the formant bandwidth tier can only be added or removed jointly
  66. * because they are part of a FormantGrid object. There will always be an equal number of formant frequency tiers and
  67. * formant bandwidth tiers.
  68. *
  69. * For parallel synthesis we also need, besides the frequency and bandwidth tier, an additional amplitude tier for each formant.
  70. * It is not necessary that there are an equal number of formant frequency tiers (nf) and amplitude tiers (na).
  71. * During parallel synthesis we simply synthesize with min(nf,na) number of formants.
  72. * These numbers nf and na can get out of sync because of the following (add, remove, replace) actions:
  73. * - we replace a FormantGrid that has not the same number of tiers as the corresponding number of amplitude tiers
  74. * - we remove/add a formant tier and a bandwidth tier together and not the corresponding amplitude tier
  75. * - we remove/add an amplitude tier and not the corresponding formant&bandwidth tiers
  76. *
  77. * As of 20130113 the KlattGrid_addFormant (/remove) which also added automatically an amplitude tier has been split into two explicit actions
  78. * KlattGrid_addFormantFrequencyAndBandwidth (/remove)
  79. * KlattGrid_addFormantAmplitudeTier (/remove)
  80. *
  81. */
  82. #define KlattGrid_OPENPHASE_DEFAULT 0.7
  83. #define KlattGrid_POWER1_DEFAULT 3
  84. #define KlattGrid_POWER2_DEFAULT (KlattGrid_POWER1_DEFAULT+1)
  85. /* Amplitude scaling: maximum amplitude (-1,+1) corresponds to 91 dB */
  86. /*static double NUMinterpolateLinear (double x1, double y1, double x2, double y2, double x)
  87. {
  88. if (y1 == y2) return y1;
  89. if (x1 == x2) return undefined;
  90. return (y2 - y1) * (x - x1) / (x2 - x1) + y1;
  91. }*/
  92. static void rel_to_abs (double *w, double *ws, integer n, double d) {
  93. double sum = 0.0;
  94. for (integer i = 1; i <= n; i ++) { // relative
  95. sum += w [i];
  96. }
  97. if (sum != 0.0) {
  98. double dw = d / sum;
  99. sum = 0.0;
  100. for (integer i = 1; i <= n; i ++) { // to absolute
  101. w [i] *= dw;
  102. sum += w [i];
  103. ws [i] = sum;
  104. }
  105. }
  106. }
  107. static bool RealTier_valuesInRange (RealTier me, double min, double max) {
  108. for (integer i = 1; i <= my points.size; i ++) {
  109. RealPoint p = my points.at [i];
  110. if (isdefined (min) && p -> value < min) {
  111. return false;
  112. }
  113. if (isdefined (max) && p -> value < max) {
  114. return false;
  115. }
  116. }
  117. return true;
  118. }
  119. static double PointProcess_getPeriodAtIndex (PointProcess me, integer it, double maximumPeriod) {
  120. double period = undefined;
  121. if (it >= 2) {
  122. period = my t [it] - my t [it - 1];
  123. if (period > maximumPeriod) {
  124. period = undefined;
  125. }
  126. }
  127. if (isundef (period)) {
  128. if (it < my nt) {
  129. period = my t [it + 1] - my t [it];
  130. if (period > maximumPeriod) {
  131. period = undefined;
  132. }
  133. }
  134. }
  135. // undefined can only occur for a single isolated pulse.
  136. return period;
  137. }
  138. #define UPDATE_TIER \
  139. RealTier_addPoint (thee.get(), mytime, myvalue); \
  140. lasttime = mytime; \
  141. myindex ++; \
  142. if (myindex <= numberOfValues) { \
  143. mypoint = my points.at [myindex]; \
  144. mytime = mypoint -> number; \
  145. myvalue = mypoint -> value;\
  146. } else { \
  147. mytime = my xmax; \
  148. }
  149. static autoRealTier RealTier_updateWithDelta (RealTier me, RealTier delta, PhonationTier glottis, double openglottis_fadeFraction) {
  150. try {
  151. integer myindex = 1;
  152. RealPoint mypoint = my points.at [myindex];
  153. integer numberOfValues = my points.size;
  154. double mytime = mypoint -> number;
  155. double myvalue = mypoint -> value;
  156. double lasttime = my xmin - 0.001; // sometime before xmin
  157. autoRealTier thee = RealTier_create (my xmin, my xmax);
  158. if (openglottis_fadeFraction <= 0.0)
  159. openglottis_fadeFraction = 0.0001;
  160. if (openglottis_fadeFraction >= 0.5)
  161. openglottis_fadeFraction = 0.4999;
  162. for (integer ipoint = 1; ipoint <= glottis -> points.size; ipoint ++) {
  163. PhonationPoint point = glottis -> points.at [ipoint];
  164. double t4 = point -> number; // glottis closing
  165. double openDuration = point -> te;
  166. double t1 = t4 - openDuration;
  167. double t2 = t1 + openglottis_fadeFraction * openDuration;
  168. double t3 = t4 - openglottis_fadeFraction * openDuration;
  169. /*
  170. Add my points that lie before t1 and after previous t4.
  171. */
  172. while (mytime > lasttime && mytime < t1) {
  173. UPDATE_TIER
  174. }
  175. if (t2 > t1) {
  176. // Set new value at t1
  177. double myvalue1 = RealTier_getValueAtTime (me, t1);
  178. RealTier_addPoint (thee.get(), t1, myvalue1);
  179. // Add my points between t1 and t2
  180. while (mytime > lasttime && mytime < t2) {
  181. double dvalue = RealTier_getValueAtTime (delta, mytime);
  182. if (isdefined (dvalue)) {
  183. double fraction = (mytime - t1) / (openglottis_fadeFraction * openDuration);
  184. myvalue += dvalue * fraction;
  185. }
  186. UPDATE_TIER
  187. }
  188. }
  189. double myvalue2 = RealTier_getValueAtTime (me, t2);
  190. double dvalue = RealTier_getValueAtTime (delta, t2);
  191. if (isdefined (dvalue))
  192. myvalue2 += dvalue;
  193. RealTier_addPoint (thee.get(), t2, myvalue2);
  194. // Add points between t2 and t3
  195. while (mytime > lasttime && mytime < t3) {
  196. dvalue = RealTier_getValueAtTime (delta, mytime);
  197. if (isdefined (dvalue))
  198. myvalue += dvalue;
  199. UPDATE_TIER
  200. }
  201. // set new value at t3
  202. double myvalue3 = RealTier_getValueAtTime (me, t3);
  203. dvalue = RealTier_getValueAtTime (delta, t3);
  204. if (isdefined (dvalue)) {
  205. myvalue3 += dvalue;
  206. }
  207. RealTier_addPoint (thee.get(), t3, myvalue3);
  208. if (t4 > t3) {
  209. // Add my points between t3 and t4
  210. while (mytime > lasttime && mytime < t4) {
  211. dvalue = RealTier_getValueAtTime (delta, mytime);
  212. if (isdefined (dvalue)) {
  213. double fraction = 1 - (mytime - t3) / (openglottis_fadeFraction * openDuration);
  214. myvalue += dvalue * fraction;
  215. }
  216. UPDATE_TIER
  217. }
  218. // Set new value at t4
  219. double myvalue4 = RealTier_getValueAtTime (me, t4);
  220. RealTier_addPoint (thee.get(), t4, myvalue4);
  221. }
  222. }
  223. return thee;
  224. } catch (MelderError) {
  225. Melder_throw (me, U": not updated with delta.");
  226. }
  227. }
  228. static bool FormantGrid_isFormantDefined (FormantGrid me, integer iformant) {
  229. // formant and bandwidth are always in sync
  230. RealTier ftier = my formants.at [iformant];
  231. RealTier btier = my bandwidths.at [iformant];
  232. return ftier -> points.size > 0 and btier -> points.size > 0;
  233. }
  234. static bool FormantGrid_Intensities_isFormantDefined (FormantGrid me, OrderedOf<structIntensityTier>* thee, integer iformant) {
  235. bool exists = false;
  236. if (iformant <= my formants.size && iformant <= my bandwidths.size && iformant <= thee->size) {
  237. RealTier ftier = my formants.at [iformant];
  238. RealTier btier = my bandwidths.at [iformant];
  239. IntensityTier atier = thy at [iformant];
  240. exists = ( ftier -> points.size > 0 && btier -> points.size > 0 && atier -> points.size > 0 );
  241. }
  242. return exists;
  243. }
  244. static void check_formants (integer numberOfFormants, integer *ifb, integer *ife) {
  245. if (numberOfFormants <= 0 || *ifb > numberOfFormants || *ife < *ifb || *ife < 1) {
  246. *ife = 0; // overrules everything *ifb value is a don't care now
  247. return;
  248. }
  249. if (*ifb <= 1)
  250. *ifb = 1;
  251. if (*ife > numberOfFormants)
  252. *ife = numberOfFormants;
  253. }
  254. static autoSound Sound_createEmptyMono (double xmin, double xmax, double samplingFrequency) {
  255. integer nt = Melder_iceiling ((xmax - xmin) * samplingFrequency);
  256. double dt = 1.0 / samplingFrequency;
  257. double tmid = (xmin + xmax) / 2.0;
  258. double t1 = tmid - 0.5 * (nt - 1) * dt;
  259. return Sound_create (1, xmin, xmax, nt, dt, t1);
  260. }
  261. static void _Sounds_add_inplace (Sound me, Sound thee) {
  262. for (integer i = 1; i <= my nx; i ++)
  263. my z [1] [i] += thy z [1] [i];
  264. }
  265. static autoSound _Sound_diff (Sound me, int scale) {
  266. try {
  267. autoSound thee = Data_copy (me);
  268. // extremum
  269. double amax1 = -1.0e34, amax2 = amax1, val, pval = 0.0;
  270. if (scale) {
  271. for (integer i = 1; i <= thy nx; i ++) {
  272. val = fabs (thy z [1] [i]);
  273. if (val > amax1)
  274. amax1 = val;
  275. }
  276. }
  277. // x [n]-x [n-1]
  278. for (integer i = 1; i <= thy nx; i ++) {
  279. val = thy z [1] [i];
  280. thy z [1] [i] -= pval;
  281. pval = val;
  282. }
  283. if (scale) {
  284. for (integer i = 1; i <= thy nx; i ++) {
  285. val = fabs (thy z [1] [i]);
  286. if (val > amax2)
  287. amax2 = val;
  288. }
  289. // scale
  290. for (integer i = 1; i <= thy nx; i ++)
  291. thy z [1] [i] *= amax1 / amax2;
  292. }
  293. return thee;
  294. } catch (MelderError) {
  295. Melder_throw (me, U": not differenced.");
  296. }
  297. }
  298. /*static void _Sounds_addDifferentiated_inplace (Sound me, Sound thee)
  299. {
  300. double pval = 0, dx = my dx;
  301. for (integer i = 1; i <= my nx; i ++)
  302. {
  303. double val = thy z [1] [i];
  304. my z [1] [i] += (val - pval) / dx; // dx makes amplitude of dz/dt independent of sampling.
  305. pval = val;
  306. }
  307. }*/
  308. typedef struct structconnections {
  309. integer numberOfConnections;
  310. double *x, *y;
  311. } *connections;
  312. static void connections_free (connections me) {
  313. if (! me)
  314. return;
  315. NUMvector_free (my x, 1);
  316. NUMvector_free (my y, 1);
  317. Melder_free (me);
  318. }
  319. static connections connections_create (integer numberOfConnections) {
  320. connections me = 0;
  321. try {
  322. me = (connections) Melder_malloc (structconnections, 1);
  323. my numberOfConnections = numberOfConnections;
  324. my x = NUMvector<double> (1, numberOfConnections);
  325. my y = NUMvector<double> (1, numberOfConnections);
  326. return me;
  327. } catch (MelderError) {
  328. connections_free (me);
  329. Melder_throw (U"Connections not created.");
  330. }
  331. }
  332. // Calculates the intersection point (xi,yi) of a line with a circle.
  333. // The line starts at the origin and P (xp, yp) is on that line.
  334. static void NUMcircle_radial_intersection_sq (double x, double y, double r, double xp, double yp, double *xi, double *yi) {
  335. double dx = xp - x, dy = yp - y;
  336. double d = sqrt (dx * dx + dy * dy);
  337. if (d > 0) {
  338. *xi = x + dx * r / d;
  339. *yi = y + dy * r / d;
  340. } else {
  341. *xi = *yi = undefined;
  342. }
  343. }
  344. static void summer_draw (Graphics g, double x, double y, double r, bool alternating) {
  345. Graphics_setLineWidth (g, 2);
  346. Graphics_circle (g, x, y, r);
  347. double dy = 3.0 * r / 4.0;
  348. // + symbol
  349. if (alternating)
  350. y += r / 4.0;
  351. Graphics_line (g, x, y + r / 2.0, x, y - r / 2.0);
  352. Graphics_line (g, x - r / 2.0, y, x + r / 2.0, y);
  353. if (alternating) {
  354. Graphics_line (g, x - r / 2.0, y - dy , x + r / 2.0, y - dy);
  355. }
  356. }
  357. static void _summer_drawConnections (Graphics g, double x, double y, double r, connections thee, bool arrow, bool alternating, double horizontalFraction) {
  358. summer_draw (g, x, y, r, alternating);
  359. for (integer i = 1; i <= thy numberOfConnections; i ++) {
  360. double xto, yto, xp = thy x [i], yp = thy y [i];
  361. if (horizontalFraction > 0) {
  362. double dx = x - xp;
  363. if (dx > 0) {
  364. xp += horizontalFraction * dx;
  365. Graphics_line (g, thy x [i], yp, xp, yp);
  366. }
  367. }
  368. NUMcircle_radial_intersection_sq (x, y, r, xp, yp, &xto, &yto);
  369. if (isundef (xto) || isundef (yto))
  370. continue;
  371. if (arrow) {
  372. Graphics_arrow (g, xp, yp, xto, yto);
  373. } else {
  374. Graphics_line (g, xp, yp, xto, yto);
  375. }
  376. }
  377. }
  378. static void summer_drawConnections (Graphics g, double x, double y, double r, connections thee, bool arrow, double horizontalFraction) {
  379. _summer_drawConnections (g, x, y, r, thee, arrow, false, horizontalFraction);
  380. }
  381. static void alternatingSummer_drawConnections (Graphics g, double x, double y, double r, connections thee, bool arrow, double horizontalFraction) {
  382. _summer_drawConnections (g, x, y, r, thee, arrow, true, horizontalFraction);
  383. }
  384. static void draw_oneSection (Graphics g, double xmin, double xmax, double ymin, double ymax,
  385. conststring32 line1, conststring32 line2, conststring32 line3)
  386. {
  387. Graphics_rectangle (g, xmin, xmax, ymin, ymax);
  388. integer numberOfTextLines = 0;
  389. if (line1)
  390. numberOfTextLines ++;
  391. if (line2)
  392. numberOfTextLines ++;
  393. if (line3)
  394. numberOfTextLines ++;
  395. double y = ymax, dy = (ymax - ymin) / (numberOfTextLines + 1), ddy = dy / 10.0;
  396. double x = (xmax + xmin) / 2.0;
  397. integer iline = 0;
  398. if (line1) {
  399. iline ++;
  400. y -= dy - ( numberOfTextLines == 2 ? ddy : 0.0 ); // extra spacing for two lines
  401. Graphics_text (g, x, y, line1);
  402. }
  403. if (line2) {
  404. iline ++;
  405. y -= dy - ( numberOfTextLines == 2 ? ( iline == 1 ? ddy : -iline * ddy ) : 0.0 );
  406. Graphics_text (g, x, y, line2);
  407. }
  408. if (line3) {
  409. iline ++;
  410. y -= dy - ( numberOfTextLines == 2 ? -iline * ddy : 0.0 );
  411. Graphics_text (g, x, y, line3);
  412. }
  413. }
  414. // Maximum amplitue (-1,1) at 93.97940008672037 dB
  415. #define DBSPL_to_A(x) (pow (10.0, x / 20.0) * 2.0e-5)
  416. // Normal dB's
  417. #define DB_to_A(x) (pow (10.0, x / 20.0))
  418. /************************ Sound & FormantGrid *********************************************/
  419. static void _Sound_FormantGrid_filterWithOneFormant_inplace (Sound me, FormantGrid thee, integer iformant, int antiformant) {
  420. if (iformant < 1 || iformant > thy formants.size) {
  421. Melder_warning (U"Formant ", iformant, U" does not exist.");
  422. return;
  423. }
  424. RealTier ftier = thy formants.at [iformant];
  425. RealTier btier = thy bandwidths.at [iformant];
  426. if (ftier -> points.size == 0 && btier -> points.size == 0)
  427. return;
  428. if (ftier -> points.size == 0 || btier -> points.size == 0)
  429. Melder_throw (U"Empty tier");
  430. double nyquist = 0.5 / my dx;
  431. autoFilter r;
  432. if (antiformant != 0) {
  433. r = AntiResonator_create (my dx);
  434. } else {
  435. r = Resonator_create (my dx, Resonator_NORMALISATION_H0);
  436. }
  437. for (integer is = 1; is <= my nx; is ++) {
  438. double t = my x1 + (is - 1) * my dx;
  439. double f = RealTier_getValueAtTime (ftier, t);
  440. double b = RealTier_getValueAtTime (btier, t);
  441. if (f <= nyquist && isdefined (b))
  442. Filter_setFB (r.get(), f, b);
  443. my z [1] [is] = Filter_getOutput (r.get(), my z [1] [is]);
  444. }
  445. }
  446. void Sound_FormantGrid_filterWithOneAntiFormant_inplace (Sound me, FormantGrid thee, integer iformant) {
  447. _Sound_FormantGrid_filterWithOneFormant_inplace (me, thee, iformant, 1);
  448. }
  449. void Sound_FormantGrid_filterWithOneFormant_inplace (Sound me, FormantGrid thee, integer iformant) {
  450. _Sound_FormantGrid_filterWithOneFormant_inplace (me, thee, iformant, 0);
  451. }
  452. void Sound_FormantGrid_Intensities_filterWithOneFormant_inplace (Sound me, FormantGrid thee, OrderedOf<structIntensityTier>* amplitudes, integer iformant) {
  453. try {
  454. Melder_require (iformant > 0 && iformant <= thy formants.size, U"Formant ", iformant, U" not defined.");
  455. double nyquist = 0.5 / my dx;
  456. RealTier ftier = thy formants.at [iformant];
  457. RealTier btier = thy bandwidths.at [iformant];
  458. IntensityTier atier = amplitudes->at [iformant];
  459. if (ftier -> points.size == 0 || btier -> points.size == 0 || atier -> points.size == 0)
  460. return; // nothing to do
  461. autoResonator r = Resonator_create (my dx, Resonator_NORMALISATION_HMAX);
  462. for (integer is = 1; is <= my nx; is ++) {
  463. double t = my x1 + (is - 1) * my dx;
  464. double f = RealTier_getValueAtTime (ftier, t);
  465. double b = RealTier_getValueAtTime (btier, t);
  466. double a;
  467. if (f <= nyquist && isdefined (b)) {
  468. Filter_setFB (r.get(), f, b);
  469. a = RealTier_getValueAtTime (atier, t);
  470. if (isdefined (a))
  471. r -> a *= DB_to_A (a);
  472. }
  473. my z [1] [is] = Filter_getOutput (r.get(), my z [1] [is]);
  474. }
  475. } catch (MelderError) {
  476. Melder_throw (me, U": not filtered with one formant filter.");
  477. }
  478. }
  479. autoSound Sound_FormantGrid_Intensities_filter (Sound me, FormantGrid thee, OrderedOf<structIntensityTier>* amplitudes, integer iformantb, integer iformante, int alternatingSign) {
  480. try {
  481. if (iformantb > iformante) {
  482. iformantb = 1;
  483. iformante = thy formants.size;
  484. }
  485. Melder_require (iformantb > 0 && iformantb <= thy formants.size , U"From formant ", iformantb, U" not defined.");
  486. Melder_require (iformante > 0 && iformante <= thy formants.size , U"To formant ", iformante, U" not defined.");
  487. autoSound him = Sound_create (my ny, my xmin, my xmax, my nx, my dx, my x1);
  488. for (integer iformant = iformantb; iformant <= iformante; iformant ++) {
  489. if (FormantGrid_Intensities_isFormantDefined (thee, amplitudes, iformant)) {
  490. autoSound tmp = Data_copy (me);
  491. Sound_FormantGrid_Intensities_filterWithOneFormant_inplace (tmp.get(), thee, amplitudes, iformant);
  492. for (integer is = 1; is <= my nx; is ++) {
  493. his z [1] [is] += ( alternatingSign >= 0 ? tmp -> z [1] [is] : - tmp -> z [1] [is] );
  494. }
  495. if (alternatingSign != 0)
  496. alternatingSign = - alternatingSign;
  497. }
  498. }
  499. return him;
  500. } catch (MelderError) {
  501. Melder_throw (me, U": not filtered.");
  502. }
  503. }
  504. /********************* PhonationTier ************************/
  505. Thing_implement (PhonationPoint, AnyPoint, 0);
  506. autoPhonationPoint PhonationPoint_create (double time, double period, double openPhase, double collisionPhase, double te,
  507. double power1, double power2, double pulseScale) {
  508. try {
  509. autoPhonationPoint me = Thing_new (PhonationPoint);
  510. my number = time;
  511. my period = period;
  512. my openPhase = openPhase;
  513. my collisionPhase = collisionPhase;
  514. my te = te;
  515. my power1 = power1;
  516. my power2 = power2;
  517. my pulseScale = pulseScale;
  518. return me;
  519. } catch (MelderError) {
  520. Melder_throw (U"PhonationPoint not created.");
  521. }
  522. }
  523. Thing_implement (PhonationTier, AnyTier, 0);
  524. autoPhonationTier PhonationTier_create (double tmin, double tmax) {
  525. try {
  526. autoPhonationTier me = Thing_new (PhonationTier);
  527. Function_init (me.get(), tmin, tmax);
  528. return me;
  529. } catch (MelderError) {
  530. Melder_throw (U"PhonationTier not created.");
  531. }
  532. }
  533. autoPointProcess PhonationTier_to_PointProcess_closures (PhonationTier me) {
  534. try {
  535. integer nt = my points.size;
  536. autoPointProcess thee = PointProcess_create (my xmin, my xmax, nt);
  537. for (integer ip = 1; ip <= nt; ip ++) {
  538. PhonationPoint fp = my points.at [ip];
  539. PointProcess_addPoint (thee.get(), fp -> number);
  540. }
  541. return thee;
  542. } catch (MelderError) {
  543. Melder_throw (me, U": no PointProcess with closure times created.");
  544. }
  545. }
  546. /********************** PhonationGridPlayOptions **********************/
  547. Thing_implement (PhonationGridPlayOptions, Daata, 0);
  548. static void PhonationGridPlayOptions_setDefaults (PhonationGridPlayOptions me) {
  549. my flowDerivative = my voicing = 1;
  550. my aspiration = my breathiness = 1;
  551. my flutter = my doublePulsing = 1;
  552. my collisionPhase = my spectralTilt = 1;
  553. my flowFunction = 1; // User defined flow tiers (power1 & power2)
  554. my maximumPeriod = 0;
  555. }
  556. autoPhonationGridPlayOptions PhonationGridPlayOptions_create () {
  557. try {
  558. autoPhonationGridPlayOptions me = Thing_new (PhonationGridPlayOptions);
  559. return me;
  560. } catch (MelderError) {
  561. Melder_throw (U"PhonationGridPlayOptions not created.");
  562. }
  563. }
  564. /********************** PhonationGrid **********************/
  565. Thing_implement (PhonationGrid, Function, 0);
  566. void structPhonationGrid :: v_info () {
  567. structDaata :: v_info ();
  568. conststring32 in1 = U" ", in2 = U" ";
  569. MelderInfo_writeLine (in1, U"Time domain:");
  570. MelderInfo_writeLine (in2, U"Start time: ", xmin, U" seconds");
  571. MelderInfo_writeLine (in2, U"End time: ", xmax, U" seconds");
  572. MelderInfo_writeLine (in2, U"Total duration: ", xmax - xmin, U" seconds");
  573. MelderInfo_writeLine (in1, U"\nNumber of points in the PHONATION tiers:");
  574. MelderInfo_writeLine (in2, U"pitch: ", pitch -> points.size);
  575. MelderInfo_writeLine (in2, U"voicingAmplitude: ", voicingAmplitude -> points.size);
  576. MelderInfo_writeLine (in2, U"openPhase: ", openPhase -> points.size);
  577. MelderInfo_writeLine (in2, U"collisionPhase: ", collisionPhase -> points.size);
  578. MelderInfo_writeLine (in2, U"power1: ", power1 -> points.size);
  579. MelderInfo_writeLine (in2, U"power2: ", power2 -> points.size);
  580. MelderInfo_writeLine (in2, U"flutter: ", flutter -> points.size);
  581. MelderInfo_writeLine (in2, U"doublePulsing: ", doublePulsing -> points.size);
  582. MelderInfo_writeLine (in2, U"spectralTilt: ", spectralTilt -> points.size);
  583. MelderInfo_writeLine (in2, U"aspirationAmplitude: ", aspirationAmplitude -> points.size);
  584. MelderInfo_writeLine (in2, U"breathinessAmplitude:", breathinessAmplitude -> points.size);
  585. }
  586. void PhonationGrid_setNames (PhonationGrid me) {
  587. Thing_setName (my pitch.get(), U"pitch");
  588. Thing_setName (my voicingAmplitude.get(), U"voicingAmplitude");
  589. Thing_setName (my openPhase.get(), U"openPhase");
  590. Thing_setName (my collisionPhase.get(), U"collisionPhase");
  591. Thing_setName (my power1.get(), U"power1");
  592. Thing_setName (my power2.get(), U"power2");
  593. Thing_setName (my flutter.get(), U"flutter");
  594. Thing_setName (my doublePulsing.get(), U"doublePulsing");
  595. Thing_setName (my spectralTilt.get(), U"spectralTilt");
  596. Thing_setName (my aspirationAmplitude.get(), U"aspirationAmplitude");
  597. Thing_setName (my breathinessAmplitude.get(), U"breathinessAmplitude");
  598. }
  599. autoPhonationGrid PhonationGrid_create (double tmin, double tmax) {
  600. try {
  601. autoPhonationGrid me = Thing_new (PhonationGrid);
  602. Function_init (me.get(), tmin, tmax);
  603. my pitch = PitchTier_create (tmin, tmax);
  604. my voicingAmplitude = IntensityTier_create (tmin, tmax);
  605. my openPhase = RealTier_create (tmin, tmax);
  606. my collisionPhase = RealTier_create (tmin, tmax);
  607. my power1 = RealTier_create (tmin, tmax);
  608. my power2 = RealTier_create (tmin, tmax);
  609. my flutter = RealTier_create (tmin, tmax);
  610. my doublePulsing = RealTier_create (tmin, tmax);
  611. my spectralTilt = IntensityTier_create (tmin, tmax);
  612. my aspirationAmplitude = IntensityTier_create (tmin, tmax);
  613. my breathinessAmplitude = IntensityTier_create (tmin, tmax);
  614. my options = PhonationGridPlayOptions_create ();
  615. PhonationGrid_setNames (me.get());
  616. return me;
  617. } catch (MelderError) {
  618. Melder_throw (U"PhonationGrid not created.");
  619. }
  620. }
  621. static void PhonationGrid_checkFlowFunction (PhonationGrid me) {
  622. int hasPower1Points = my power1 -> points.size > 0;
  623. int hasPower2Points = my power2 -> points.size > 0;
  624. integer ipoint = 1;
  625. do {
  626. double time = ( hasPower1Points ? my power1 -> points.at [ipoint] -> number : 0.5 * (my xmin + my xmax) );
  627. double power1 = RealTier_getValueAtIndex (my power1.get(), ipoint);
  628. if (isundef (power1))
  629. power1 = KlattGrid_POWER1_DEFAULT;
  630. Melder_require (power1 > 0.0,
  631. U"All power1 values should greater than zero.");
  632. double power2 = RealTier_getValueAtTime (my power2.get(), time);
  633. if (isundef (power2))
  634. power2 = KlattGrid_POWER2_DEFAULT;
  635. Melder_require (power1 < power2,
  636. U"At all times a power1 value should be smaller than the corresponding power2 value.");
  637. } while ( ++ ipoint < my power1 -> points.size);
  638. // Now check power2 values. This is necessary to catch situations where power2 has a valley:
  639. // power1(0) = 3; power2(1)= 4; power2(1)= 4; power2(0.5) = 3;
  640. ipoint = 1;
  641. do {
  642. double time = ( hasPower2Points ? my power2 -> points.at [ipoint] -> number : 0.5 * (my xmin + my xmax) );
  643. double power2 = RealTier_getValueAtIndex (my power2.get(), ipoint);
  644. if (isundef (power2))
  645. power2 = KlattGrid_POWER2_DEFAULT;
  646. double power1 = RealTier_getValueAtTime (my power1.get(), time);
  647. if (isundef (power1))
  648. power1 = KlattGrid_POWER1_DEFAULT;
  649. Melder_require (power1 < power2,
  650. U"At all times a power1 value should be smaller than the corresponding power2 value.");
  651. } while ( ++ ipoint < my power2 -> points.size);
  652. }
  653. static void PhonationGrid_draw_inside (PhonationGrid me, Graphics g, double xmin, double xmax, double ymin, double ymax, double dy, double *yout) {
  654. // dum voicing conn tilt conn summer
  655. (void) me;
  656. double xw [6] = { 0.0, 1.0, 0.5, 1.0, 0.5, 0.5 }, xws [6];
  657. connections thee = connections_create (2);
  658. rel_to_abs (xw, xws, 5, xmax - xmin);
  659. dy = (ymax - ymin) / (1.0 + (dy < 0.0 ? 0.0 : dy) + 1.0);
  660. double x1 = xmin, x2 = x1 + xw [1];
  661. double y2 = ymax, y1 = y2 - dy;
  662. draw_oneSection (g, x1, x2, y1, y2, nullptr, U"Voicing", nullptr);
  663. x1 = x2; x2 = x1 + xw [2];
  664. double ymid = (y1 + y2) / 2.0;
  665. Graphics_line (g, x1, ymid, x2, ymid);
  666. x1 = x2; x2 = x1 + xw [3];
  667. draw_oneSection (g, x1, x2, y1, y2, nullptr, U"Tilt", nullptr);
  668. thy x [1] = x2; thy y [1] = ymid;
  669. y2 = y1 - 0.5 * dy; y1 = y2 - dy; ymid = (y1 + y2) / 2.0;
  670. x2 = xmin + xws [3]; x1 = x2 - 1.5 * xw [3]; // some extra space
  671. draw_oneSection (g, x1, x2, y1, y2, nullptr, U"Aspiration", nullptr);
  672. thy x [2] = x2; thy y [2] = ymid;
  673. double r = xw [5] / 2.0;
  674. double xs = xmax - r, ys = (ymax + ymin) / 2.0;
  675. bool arrow = true;
  676. summer_drawConnections (g, xs, ys, r, thee, arrow, 0.4);
  677. connections_free (thee);
  678. if (yout)
  679. *yout = ys;
  680. }
  681. void PhonationGrid_draw (PhonationGrid me, Graphics g) {
  682. double xmin = 0.0, xmax2 = 0.9, xmax = 1.0, ymin = 0.0, ymax = 1.0, dy = 0.5, yout;
  683. Graphics_setInner (g);
  684. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  685. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
  686. PhonationGrid_draw_inside (me, g, xmin, xmax2, ymin, ymax, dy, &yout);
  687. Graphics_arrow (g, xmax2, yout, xmax, yout);
  688. Graphics_unsetInner (g);
  689. }
  690. double PhonationGrid_getMaximumPeriod (PhonationGrid me) {
  691. double minimumPitch = RealTier_getMinimumValue (my pitch.get());
  692. return 2.0 / ( isdefined (minimumPitch) && minimumPitch != 0.0 ? minimumPitch : my xmax - my xmin );
  693. }
  694. static autoPointProcess PitchTier_to_PointProcess_flutter (PitchTier pitch, RealTier flutter, double maximumPeriod) {
  695. try {
  696. autoPointProcess thee = PitchTier_to_PointProcess (pitch);
  697. if (! flutter)
  698. return thee;
  699. double tsum = 0;
  700. for (integer it = 2; it <= thy nt; it ++) {
  701. double t = thy t [it - 1];
  702. double period = thy t [it] - thy t [it - 1];
  703. if (period < maximumPeriod && flutter -> points.size > 0) {
  704. double fltr = RealTier_getValueAtTime (flutter, t);
  705. if (isdefined (fltr)) {
  706. // newF0 = f0 * (1 + (val / 50) * (sin ... + ...));
  707. double newPeriod = period / (1.0 + (fltr / 50.0) * (sin (2.0 * NUMpi * 12.7 * t) + sin (2.0 * NUMpi * 7.1 * t) + sin (2.0 * NUMpi * 4.7 * t)));
  708. tsum += newPeriod - period;
  709. }
  710. }
  711. thy t [it] += tsum;
  712. }
  713. return thee;
  714. } catch (MelderError) {
  715. Melder_throw (pitch, U": no flutter PointProcess created.");
  716. }
  717. }
  718. autoSound PhonationGrid_to_Sound_aspiration (PhonationGrid me, double samplingFrequency) {
  719. try {
  720. autoSound thee = Sound_createEmptyMono (my xmin, my xmax, samplingFrequency);
  721. // Noise spectrum is tilted down by soft low-pass filter having a pole near
  722. // the origin in the z-plane, i.e. y [n] = x [n] + (0.75 * y [n-1])
  723. double lastval = 0.0;
  724. if (my aspirationAmplitude -> points.size > 0) {
  725. for (integer i = 1; i <= thy nx; i ++) {
  726. double t = thy x1 + (i - 1) * thy dx;
  727. double val = NUMrandomUniform (-1.0, 1.0);
  728. double a = DBSPL_to_A (RealTier_getValueAtTime (my aspirationAmplitude.get(), t));
  729. if (isdefined (a)) {
  730. thy z [1] [i] = lastval = val + 0.75 * lastval;
  731. lastval = (val += 0.75 * lastval); // soft low-pass
  732. thy z [1] [i] = val * a;
  733. }
  734. }
  735. }
  736. return thee;
  737. } catch (MelderError) {
  738. Melder_throw (me, U": no aspiration Sound created.");
  739. }
  740. }
  741. static void Sound_PhonationGrid_spectralTilt_inplace (Sound thee, PhonationGrid me) {
  742. if (my spectralTilt -> points.size > 0) {
  743. /* Spectral tilt
  744. Filter y [n] = a * x [n] + b * y [n-1] => H(z) = a / (1 - bz^(-1)).
  745. We need attenuation, i.e. low-pass. Therefore 0 <= b <= 1.
  746. |H(f)| = a / sqrt (1 - 2*b*cos(2*pi*f*T) + b^2),
  747. |H(0)|= a /(1 - b) => if |H(0)| == 1, then a = 1 - b.
  748. Now solve 20 log|H(F)|= -c (at F=3 kHz and c > 0)
  749. Solution: if q = (1 - D * cos(2*pi*F*T)) / (1 - D), with D = 10^(-c/10)
  750. then b = q -sqrt(q^2 - 1)
  751. */
  752. double cosf = cos (2.0 * NUMpi * 3000.0 * thy dx), ynm1 = 0.0; // samplingFrequency > 6000.0 !
  753. for (integer i = 1; i <= thy nx; i ++) {
  754. double t = thy x1 + (i - 1) * thy dx;
  755. double tilt_db = RealTier_getValueAtTime (my spectralTilt.get(), t);
  756. if (tilt_db > 0) {
  757. double d = pow (10.0, -tilt_db / 10.0);
  758. double q = (1.0 - d * cosf) / (1.0 - d);
  759. double b = q - sqrt (q * q - 1.0);
  760. double a = 1.0 - b;
  761. thy z [1] [i] = a * thy z [1] [i] + b * ynm1;
  762. ynm1 = thy z [1] [i];
  763. }
  764. }
  765. }
  766. }
  767. struct nrfunction_struct {
  768. double n;
  769. double m;
  770. double a;
  771. };
  772. static void nrfunction (double x, double *fx, double *dfx, void *closure) {
  773. struct nrfunction_struct *nrfs = (struct nrfunction_struct *) closure;
  774. double mplusax = nrfs -> m + nrfs -> a * x;
  775. double mminn = nrfs -> m - nrfs -> n;
  776. *fx = pow (x, mminn) - (nrfs -> n + nrfs -> a * x) / mplusax;
  777. *dfx = mminn * pow (x, mminn - 1) - nrfs -> a * mminn / (mplusax * mplusax);
  778. }
  779. static double get_collisionPoint_x (double n, double m, double collisionPhase) {
  780. double y = undefined;
  781. /*
  782. Domain [0,1]:
  783. The glottal flow is given by:
  784. U(y) = y^n - y^m 0<= y <= x, and m > n
  785. (x^n - x^m)exp(-a(y-x)) y >= x, where a = 1 / collisionPhase
  786. The x where this occurs is the point where the amplitudes as well as the derivatives are equal.
  787. I.e. the x where n x^(n-1) - m x^(m-1) = (x^n-x^m)(-a).
  788. This can be simplified: find x in (0,1) where f(x) = x^(m-n) - (n+ax)/(m+ax) == 0.
  789. For m - n == 1, f(x) is a second order equation f(x)= a x^2 + (m-a) x - n == 0.
  790. In all other cases we solve with Newton-Raphson. For these cases we also need the derivative:
  791. f'(x)= (m - n)x^(m - n - 1)- a(m - n) / (m + a x)^2
  792. */
  793. if (collisionPhase <= 0.0)
  794. return 1.0;
  795. double a = 1.0 / collisionPhase;
  796. if (m - n == 1.0) {
  797. double b = m - a;
  798. double c = - n, y1, y2;
  799. integer nroots = NUMsolveQuadraticEquation (a, b, c, &y1, &y2);
  800. if (nroots == 2) {
  801. y = y2;
  802. } else if (nroots == 1) {
  803. y = y1;
  804. }
  805. } else { // Newton-Raphson
  806. // search in the interval from where the flow is a maximum to 1
  807. struct nrfunction_struct nrfs = {n, m, a};
  808. double root, xmaxFlow = pow (n / m, 1.0 / (m - n));
  809. NUMnrbis (& nrfunction, xmaxFlow, 1.0, & nrfs, & root);
  810. y = root;
  811. }
  812. return y;
  813. }
  814. autoPhonationTier PhonationGrid_to_PhonationTier (PhonationGrid me) {
  815. try {
  816. integer diplophonicPulseIndex = 0;
  817. PhonationGridPlayOptions pp = my options.get();
  818. PhonationGrid_checkFlowFunction (me);
  819. Melder_require (my pitch -> points.size > 0,
  820. U"Pitch tier should not be empty.");
  821. if (pp -> maximumPeriod == 0.0)
  822. pp -> maximumPeriod = PhonationGrid_getMaximumPeriod (me);
  823. autoPointProcess point = PitchTier_to_PointProcess_flutter (my pitch.get(), (pp -> flutter ? my flutter.get() : nullptr), pp -> maximumPeriod);
  824. autoPhonationTier thee = PhonationTier_create (my xmin, my xmax);
  825. /*
  826. Cycle through the points of the point PointProcess. Each will become a period.
  827. We assume that the planning for the pitch period occurs approximately at a time T before the glottal closure.
  828. For each point t [i]:
  829. Determine the f0 -> period T [i]
  830. Determine time t [i]-T [i] the open quotient, power1, power2, collisionphase etc.
  831. Generate the period.
  832. */
  833. for (integer it = 1; it <= point -> nt; it ++) {
  834. double re = 0.0, t = point -> t [it]; // the glottis "closing" point
  835. double pulseDelay = 0.0; // For alternate pulses in case of diplophonia
  836. double pulseScale = 1.0; // For alternate pulses in case of diplophonia
  837. double period = PointProcess_getPeriodAtIndex (point.get(), it, pp -> maximumPeriod);
  838. if (isundef (period))
  839. period = 0.5 * pp -> maximumPeriod; // some default value
  840. // Calculate the point where the exponential decay starts:
  841. // Query tiers where period starts .
  842. double periodStart = t - period;
  843. double collisionPhase = pp -> collisionPhase ? RealTier_getValueAtTime (my collisionPhase.get(), periodStart) : 0.0;
  844. if (isundef (collisionPhase))
  845. collisionPhase = 0.0;
  846. double power1 = pp -> flowFunction == 1 ? RealTier_getValueAtTime (my power1.get(), periodStart) : pp -> flowFunction;
  847. if (isundef (power1))
  848. power1 = KlattGrid_POWER1_DEFAULT;
  849. double power2 = pp -> flowFunction == 1 ? RealTier_getValueAtTime (my power2.get(), periodStart) : pp -> flowFunction + 1;
  850. if (isundef (power2))
  851. power2 = KlattGrid_POWER2_DEFAULT;
  852. try {
  853. re = get_collisionPoint_x (power1, power2, collisionPhase);
  854. } catch (MelderError) {
  855. Melder_warning (U"Illegal collision point at t = ", t, U" (power1=", power1, U", power2=", power2, U"colPhase=", collisionPhase, U")");
  856. }
  857. double openPhase = RealTier_getValueAtTime (my openPhase.get(), periodStart);
  858. if (isundef (openPhase))
  859. openPhase = KlattGrid_OPENPHASE_DEFAULT;
  860. double te = re * period * openPhase;
  861. // In case of diplophonia alternate pulses get modified.
  862. // A modified puls is delayed in time and its amplitude attenuated.
  863. // This delay scales to maximally equal the closed phase of the next period.
  864. // The doublePulsing scales the amplitudes as well as the delay linearly.
  865. double doublePulsing = pp -> doublePulsing ? RealTier_getValueAtTime (my doublePulsing.get(), periodStart) : 0.0;
  866. if (isundef (doublePulsing))
  867. doublePulsing = 0.0;
  868. if (doublePulsing > 0.0) {
  869. diplophonicPulseIndex ++;
  870. if (diplophonicPulseIndex % 2 == 1) { // the odd-numbered one
  871. double nextPeriod = PointProcess_getPeriodAtIndex (point.get(), it + 1, pp -> maximumPeriod);
  872. if (isundef (nextPeriod)) {
  873. nextPeriod = period;
  874. }
  875. double openPhase2 = KlattGrid_OPENPHASE_DEFAULT;
  876. if (my openPhase -> points.size > 0) {
  877. openPhase2 = RealTier_getValueAtTime (my openPhase.get(), t);
  878. }
  879. double maxDelay = period * (1.0 - openPhase2);
  880. pulseDelay = maxDelay * doublePulsing;
  881. pulseScale *= 1.0 - doublePulsing;
  882. }
  883. } else {
  884. diplophonicPulseIndex = 0;
  885. }
  886. t += pulseDelay;
  887. autoPhonationPoint phonationPoint = PhonationPoint_create (t, period, openPhase, collisionPhase, te, power1, power2, pulseScale);
  888. AnyTier_addPoint_move (thee.get()->asAnyTier(), phonationPoint.move());
  889. }
  890. return thee;
  891. } catch (MelderError) {
  892. Melder_throw (me, U": no PhonationTier created.");
  893. }
  894. }
  895. static autoSound PhonationGrid_PhonationTier_to_Sound_voiced (PhonationGrid me, PhonationTier thee, double samplingFrequency) {
  896. try {
  897. PhonationGridPlayOptions p = my options.get();
  898. double lastVal = undefined;
  899. Melder_require (my voicingAmplitude -> points.size > 0, U"Voicing amplitude tier should not be empty.");
  900. autoSound him = Sound_createEmptyMono (my xmin, my xmax, samplingFrequency);
  901. autoSound breathy;
  902. if (p -> breathiness && my breathinessAmplitude -> points.size > 0) {
  903. breathy = Sound_createEmptyMono (my xmin, my xmax, samplingFrequency);
  904. }
  905. /*
  906. Cycle through the points of the PhonationTier. Each will become a period.
  907. We assume that the planning for the pitch period occurs approximately at a time T before the glottal closure.
  908. For each point t [i]:
  909. Determine the f0 -> period T [i]
  910. Determine time t [i]-T [i] the open quotient, power1, power2, collisionphase etc.
  911. Generate the period.
  912. */
  913. double *sound = his z [1];
  914. for (integer it = 1; it <= thy points.size; it ++) {
  915. PhonationPoint point = thy points.at [it];
  916. double t = point -> number; // the glottis "closing" point
  917. double te = point -> te;
  918. double period = point -> period; // duration of the current period
  919. double openPhase = point -> openPhase;
  920. double collisionPhase = point -> collisionPhase;
  921. double pulseScale = point -> pulseScale; // For alternate pulses in case of diplophonia
  922. double power1 = point -> power1, power2 = point -> power2;
  923. double phase; // 0..1
  924. double flow;
  925. //- double amplitude = pulseScale * (power1 + power2 + 1.0) / (power2 - power1);
  926. //- amplitude /= period * openPhase;
  927. // Maximum of U(x) = x^n - x^m is where the derivative U'(x) = n x^(n-1) - m x^(m-1) == 0,
  928. // i.e. (n/m) = x^(m-n), so xmax = (n/m)^(1/(m-n))
  929. // U(xmax) = x^n (1-x^(m-n)) = (n/m)^(n/(m-n))(1-n/m)
  930. double amplitude = pulseScale / (pow (power1 / power2, 1.0 / (power2 / power1 - 1.0)) * (1.0 - power1 / power2));
  931. // Fill in the samples to the left of the current point.
  932. integer midSample = Sampled_xToLowIndex (him.get(), t), beginSample;
  933. beginSample = midSample - Melder_ifloor (te / his dx);
  934. if (beginSample < 1)
  935. beginSample = 0;
  936. if (midSample > his nx)
  937. midSample = his nx;
  938. for (integer i = beginSample; i <= midSample; i ++) {
  939. double tsamp = his x1 + (i - 1) * his dx;
  940. phase = (tsamp - (t - te)) / (period * openPhase);
  941. if (phase > 0.0) {
  942. flow = amplitude * (pow (phase, power1) - pow (phase, power2));
  943. if (i == 0) {
  944. lastVal = flow; // For the derivative
  945. continue;
  946. }
  947. sound [i] += flow;
  948. // Breathiness only during open part modulated by the flow
  949. if (breathy) {
  950. double val = flow * NUMrandomUniform (-1.0, 1.0);
  951. double a = RealTier_getValueAtTime (my breathinessAmplitude.get(), t);
  952. breathy -> z [1] [i] += val * DBSPL_to_A (a);
  953. }
  954. }
  955. }
  956. // Determine the signal parameters at the current point.
  957. phase = te / (period * openPhase);
  958. //- double flow = amplitude * (period * openPhase) * (pow (phase, power1) - pow (phase, power2));
  959. flow = amplitude * (pow (phase, power1) - pow (phase, power2));
  960. // Fill in the samples to the right of the current point.
  961. if (flow > 0.0) {
  962. double ta = collisionPhase * (period * openPhase);
  963. double factorPerSample = exp (- his dx / ta);
  964. double value = flow * exp (- (his x1 + midSample * his dx - t) / ta);
  965. integer endSample = midSample + Melder_ifloor (20.0 * ta / his dx);
  966. if (endSample > his nx)
  967. endSample = his nx;
  968. for (integer i = midSample + 1; i <= endSample; i ++) {
  969. sound [i] += value;
  970. value *= factorPerSample;
  971. }
  972. }
  973. }
  974. // Scale voiced part and add breathiness during open phase
  975. if (p -> flowDerivative) {
  976. double extremum = Vector_getAbsoluteExtremum (him.get(), 0.0, 0.0, Vector_VALUE_INTERPOLATION_CUBIC);
  977. if (isundef (lastVal))
  978. lastVal = 0.0;
  979. for (integer i = 1; i <= his nx; i ++) {
  980. double val = his z [1] [i];
  981. his z [1] [i] -= lastVal;
  982. lastVal = val;
  983. }
  984. Vector_scale (him.get(), extremum);
  985. }
  986. for (integer i = 1; i <= his nx; i ++) {
  987. double t = his x1 + (i - 1) * his dx;
  988. his z [1] [i] *= DBSPL_to_A (RealTier_getValueAtTime (my voicingAmplitude.get(), t));
  989. if (breathy)
  990. his z [1] [i] += breathy -> z [1] [i];
  991. }
  992. return him;
  993. } catch (MelderError) {
  994. Melder_throw (me, U": no Sound created.");
  995. }
  996. }
  997. static autoSound PhonationGrid_to_Sound_voiced (PhonationGrid me, double samplingFrequency) {
  998. try {
  999. autoPhonationTier thee = PhonationGrid_to_PhonationTier (me);
  1000. return PhonationGrid_PhonationTier_to_Sound_voiced (me, thee.get(), samplingFrequency);
  1001. } catch (MelderError) {
  1002. Melder_throw (me, U": no voiced Sound created.");
  1003. }
  1004. }
  1005. static autoSound PhonationGrid_to_Sound (PhonationGrid me, CouplingGrid him, double samplingFrequency) {
  1006. try {
  1007. PhonationGridPlayOptions pp = my options.get();
  1008. autoSound thee;
  1009. if (pp -> voicing) {
  1010. if (him && his glottis -> points.size > 0) {
  1011. thee = PhonationGrid_PhonationTier_to_Sound_voiced (me, his glottis.get(), samplingFrequency);
  1012. } else {
  1013. thee = PhonationGrid_to_Sound_voiced (me, samplingFrequency);
  1014. }
  1015. if (pp -> spectralTilt)
  1016. Sound_PhonationGrid_spectralTilt_inplace (thee.get(), me);
  1017. }
  1018. if (pp -> aspiration) {
  1019. autoSound aspiration = PhonationGrid_to_Sound_aspiration (me, samplingFrequency);
  1020. if (thee) {
  1021. _Sounds_add_inplace (thee.get(), aspiration.get());
  1022. } else {
  1023. thee = aspiration.move();
  1024. }
  1025. }
  1026. if (! thee)
  1027. thee = Sound_createEmptyMono (my xmin, my xmax, samplingFrequency);
  1028. return thee;
  1029. } catch (MelderError) {
  1030. Melder_throw (me, U": no Sound created.");
  1031. }
  1032. }
  1033. static void formantsAmplitudes_create (OrderedOf<structIntensityTier>* me, double tmin, double tmax, integer numberOfFormants) {
  1034. try {
  1035. for (integer i = 1; i <= numberOfFormants; i ++) {
  1036. autoIntensityTier a = IntensityTier_create (tmin, tmax);
  1037. me -> addItem_move (a.move());
  1038. }
  1039. } catch (MelderError) {
  1040. Melder_throw (U"No formants amplitudes created.");
  1041. };
  1042. }
  1043. /********************** VocalTractGridPlayOptions **********************/
  1044. Thing_implement (VocalTractGridPlayOptions, Daata, 0);
  1045. static void VocalTractGridPlayOptions_setDefaults (VocalTractGridPlayOptions me, VocalTractGrid thee) {
  1046. my filterModel = KlattGrid_FILTER_CASCADE;
  1047. my endOralFormant = std::min (thy oral_formants -> formants.size, thy oral_formants -> bandwidths.size);
  1048. my startOralFormant = 1;
  1049. my endNasalFormant = std::min (thy nasal_formants -> formants.size, thy nasal_formants -> bandwidths.size);
  1050. my startNasalFormant = 1;
  1051. my endNasalAntiFormant = std::min (thy nasal_antiformants -> formants.size, thy nasal_antiformants -> bandwidths.size);
  1052. my startNasalAntiFormant = 1;
  1053. }
  1054. autoVocalTractGridPlayOptions VocalTractGridPlayOptions_create () {
  1055. try {
  1056. autoVocalTractGridPlayOptions me = Thing_new (VocalTractGridPlayOptions);
  1057. return me;
  1058. } catch (MelderError) {
  1059. Melder_throw (U"VocalTractGridPlayOptions not created.");
  1060. }
  1061. }
  1062. /********************** VocalTractGrid ***************************************/
  1063. static integer FormantGrid_getNumberOfFormantPoints (FormantGrid me, integer iformant) {
  1064. if (iformant < 1 || iformant > my formants.size)
  1065. return -1;
  1066. RealTier f = my formants.at [iformant];
  1067. return f -> points.size;
  1068. }
  1069. static integer FormantGrid_getNumberOfBandwidthPoints (FormantGrid me, integer iformant) {
  1070. if (iformant < 1 || iformant > my bandwidths.size)
  1071. return -1;
  1072. RealTier b = my bandwidths.at [iformant];
  1073. return b -> points.size;
  1074. }
  1075. static integer Ordered_getNumberOfAmplitudePoints (OrderedOf<structIntensityTier>* me, integer iformant) {
  1076. if (! me || iformant < 1 || iformant > my size)
  1077. return -1;
  1078. RealTier t = my at [iformant];
  1079. return t -> points.size;
  1080. }
  1081. static void FormantGrid_info (FormantGrid me, OrderedOf<structIntensityTier>* amplitudes, conststring32 in1, conststring32 in2) {
  1082. integer nformants = my formants.size;
  1083. integer namplitudes = ( amplitudes ? amplitudes->size : 0 );
  1084. integer nmax = std::max (nformants, namplitudes);
  1085. for (integer iformant = 1; iformant <= nmax; iformant ++) {
  1086. MelderInfo_writeLine (in1, U"Formant ", iformant, U":");
  1087. if (iformant <= my formants.size) {
  1088. integer nfp = FormantGrid_getNumberOfFormantPoints (me, iformant);
  1089. integer nbp = FormantGrid_getNumberOfBandwidthPoints (me, iformant);
  1090. MelderInfo_writeLine (in2, U"formants: ", (nfp >= 0 ? Melder_integer (nfp) : U"--undefined--"));
  1091. MelderInfo_writeLine (in2, U"bandwidths: ", (nbp >= 0 ? Melder_integer (nbp) : U"--undefined--"));
  1092. }
  1093. if (amplitudes) {
  1094. integer nap = Ordered_getNumberOfAmplitudePoints (amplitudes, iformant);
  1095. MelderInfo_writeLine (in2, U"amplitudes: ", (nap >= 0 ? Melder_integer (nap) : U"--undefined--"));
  1096. }
  1097. }
  1098. }
  1099. void structVocalTractGrid :: v_info () {
  1100. our structDaata :: v_info ();
  1101. conststring32 in1 = U" ", in2 = U" ", in3 = U" ";
  1102. MelderInfo_writeLine (in1, U"Time domain:");
  1103. MelderInfo_writeLine (in2, U"Start time: ", our xmin, U" seconds");
  1104. MelderInfo_writeLine (in2, U"End time: ", our xmax, U" seconds");
  1105. MelderInfo_writeLine (in2, U"Total duration: ", our xmax - our xmin, U" seconds");
  1106. MelderInfo_writeLine (in1, U"\nNumber of points in the ORAL FORMANT tiers:");
  1107. FormantGrid_info (our oral_formants.get(), & our oral_formants_amplitudes, in2, in3);
  1108. MelderInfo_writeLine (in1, U"\nNumber of points in the NASAL FORMANT tiers:");
  1109. FormantGrid_info (our nasal_formants.get(), & our nasal_formants_amplitudes, in2, in3);
  1110. MelderInfo_writeLine (in1, U"\nNumber of points in the NASAL ANTIFORMANT tiers:");
  1111. FormantGrid_info (our nasal_antiformants.get(), nullptr, in2, in3);
  1112. }
  1113. Thing_implement (VocalTractGrid, Function, 0);
  1114. void VocalTractGrid_setNames (VocalTractGrid me) {
  1115. Thing_setName (my oral_formants.get(), U"oral_formants");
  1116. Thing_setName (my nasal_formants.get(), U"nasal_formants");
  1117. Thing_setName (my nasal_antiformants.get(), U"nasal_antiformants");
  1118. //Thing_setName (my oral_formants_amplitudes.get(), U"oral_formants_amplitudes");
  1119. //Thing_setName (my nasal_formants_amplitudes.get(), U"nasal_formants_amplitudes");
  1120. }
  1121. autoVocalTractGrid VocalTractGrid_create (double tmin, double tmax, integer numberOfFormants,
  1122. integer numberOfNasalFormants, integer numberOfNasalAntiFormants) {
  1123. try {
  1124. autoVocalTractGrid me = Thing_new (VocalTractGrid);
  1125. Function_init (me.get(), tmin, tmax);
  1126. my oral_formants = FormantGrid_createEmpty (tmin, tmax, numberOfFormants);
  1127. my nasal_formants = FormantGrid_createEmpty (tmin, tmax, numberOfNasalFormants);
  1128. my nasal_antiformants = FormantGrid_createEmpty (tmin, tmax, numberOfNasalAntiFormants);
  1129. formantsAmplitudes_create (& my oral_formants_amplitudes, tmin, tmax, numberOfFormants);
  1130. formantsAmplitudes_create (& my nasal_formants_amplitudes, tmin, tmax, numberOfNasalFormants);
  1131. my options = VocalTractGridPlayOptions_create ();
  1132. VocalTractGrid_setNames (me.get());
  1133. return me;
  1134. } catch (MelderError) {
  1135. Melder_throw (U"VocalTractGrid not created.");
  1136. }
  1137. }
  1138. static void VocalTractGrid_CouplingGrid_drawCascade_inplace (VocalTractGrid me, CouplingGrid thee, Graphics g, double xmin, double xmax, double ymin, double ymax, double *yin, double *yout) {
  1139. integer numberOfOralFormants = my oral_formants -> formants.size;
  1140. integer numberOfNasalFormants = my nasal_formants -> formants.size;
  1141. integer numberOfNasalAntiFormants = my nasal_antiformants -> formants.size;
  1142. integer numberOfTrachealFormants = thee ? thy tracheal_formants -> formants.size : 0;
  1143. integer numberOfTrachealAntiFormants = thee ? thy tracheal_antiformants -> formants.size : 0;
  1144. double x1, y1 = ymin, x2, y2 = ymax, dx, ddx = 0.2, ymid = (y1 + y2) / 2.0;
  1145. conststring32 text [6] = { 0, U"TF", U"TAF", U"NF", U"NAF", U""};
  1146. integer nf [6] = { 0, numberOfTrachealFormants, numberOfTrachealAntiFormants, numberOfNasalFormants, numberOfNasalAntiFormants, numberOfOralFormants };
  1147. integer numberOfXSections = 5, nsx = 0;
  1148. autoMelderString ff, fb;
  1149. integer numberOfFilters = numberOfNasalFormants + numberOfNasalAntiFormants + numberOfTrachealFormants + numberOfTrachealAntiFormants + numberOfOralFormants;
  1150. if (numberOfFilters == 0) {
  1151. x2 = xmax;
  1152. Graphics_line (g, xmin, ymid, x2, ymid);
  1153. goto end;
  1154. }
  1155. for (integer isection = 1; isection <= numberOfXSections; isection ++) if (nf [isection] > 0)
  1156. nsx ++;
  1157. dx = (xmax - xmin) / (numberOfFilters + (nsx - 1) * ddx);
  1158. x1 = xmin;
  1159. for (integer isection = 1; isection <= numberOfXSections; isection ++) {
  1160. integer numberOfFormants = nf [isection];
  1161. if (numberOfFormants == 0)
  1162. continue;
  1163. x2 = x1 + dx;
  1164. for (integer i = 1; i <= numberOfFormants; i ++) {
  1165. MelderString_copy (&ff, U"F", i);
  1166. MelderString_copy (&fb, U"B", i);
  1167. // ppgb: met Melder_cat kan het misschien ook,
  1168. // maar je weet niet of Graphics (in draw_oneSection) niet indirect de cat-buffers gebruikt,
  1169. // dus deze methode is veiliger (kost bovendien maar 1 heap-allocatie voor de hele loop);
  1170. // alleen Melder_sprint is nog simpeler, omdat je weet dat 40 chars genoeg is
  1171. draw_oneSection (g, x1, x2, y1, y2, text [isection], ff.string, fb.string);
  1172. if (i < numberOfFormants) {
  1173. x1 = x2;
  1174. x2 = x1 + dx;
  1175. }
  1176. }
  1177. if (isection < numberOfXSections) {
  1178. x1 = x2; x2 = x1 + ddx * dx;
  1179. Graphics_line (g, x1, ymid, x2, ymid);
  1180. x1 = x2;
  1181. }
  1182. }
  1183. end:
  1184. if (yin)
  1185. *yin = ymid;
  1186. if (yout)
  1187. *yout = ymid;
  1188. }
  1189. static void VocalTractGrid_CouplingGrid_drawParallel_inplace (VocalTractGrid me, CouplingGrid thee, Graphics g, double xmin, double xmax, double ymin, double ymax, double dy, double *yin, double *yout) {
  1190. // (0: filler) (1: hor. line to split) (2: split to diff) (3: diff) (4: diff to split)
  1191. // (5: split to filter) (6: filters) (7: conn to summer) (8: summer)
  1192. double xw [9] = { 0.0, 0.3, 0.2, 1.5, 0.5, 0.5, 1.0, 0.5, 0.5 }, xws [9];
  1193. integer numberOfXSections = 8, ic = 0, numberOfYSections = 4;
  1194. integer numberOfNasalFormants = my nasal_formants -> formants.size;
  1195. integer numberOfOralFormants = my oral_formants -> formants.size;
  1196. integer numberOfTrachealFormants = thee ? thy tracheal_formants -> formants.size : 0;
  1197. integer numberOfFormants = numberOfNasalFormants + numberOfOralFormants + numberOfTrachealFormants;
  1198. integer numberOfUpperPartFormants = numberOfNasalFormants + ( numberOfOralFormants > 0 ? 1 : 0 );
  1199. integer numberOfLowerPartFormants = numberOfFormants - numberOfUpperPartFormants;
  1200. double ddy = dy < 0 ? 0 : dy, x1, y1, x2, y2, x3, r, ymid;
  1201. conststring32 text [5] = { nullptr, U"Nasal", U"", U"", U"Tracheal" };
  1202. integer nffrom [5] = { 0, 1, 1, 2, 1 };
  1203. integer nfto [5] = { 0, numberOfNasalFormants, ( numberOfOralFormants > 0 ? 1 : 0 ), numberOfOralFormants, numberOfTrachealFormants };
  1204. autoMelderString fba;
  1205. rel_to_abs (xw, xws, numberOfXSections, xmax - xmin);
  1206. if (numberOfFormants == 0) {
  1207. y1 = y2 = (ymin + ymax) / 2.0;
  1208. Graphics_line (g, xmin, y1, xmax, y1);
  1209. if (yin)
  1210. *yin = y1;
  1211. if (yout)
  1212. *yout = y2;
  1213. return;
  1214. }
  1215. dy = (ymax - ymin) / (numberOfFormants * (1.0 + ddy) - ddy);
  1216. connections local_in = connections_create (numberOfFormants);
  1217. connections local_out = connections_create (numberOfFormants);
  1218. // parallel section
  1219. x1 = xmin + xws [5]; x2 = x1 + xw [6]; y2 = ymax;
  1220. x3 = xmin + xws [4];
  1221. for (integer isection = 1; isection <= numberOfYSections; isection ++) {
  1222. integer ifrom = nffrom [isection], ito = nfto [isection];
  1223. if (ito < ifrom)
  1224. continue;
  1225. for (integer i = ifrom; i <= ito; i ++) {
  1226. y1 = y2 - dy;
  1227. ymid = (y1 + y2) / 2.0;
  1228. conststring32 fi = Melder_integer (i);
  1229. MelderString_copy (&fba, U"A", fi, U" F", fi, U" B", fi);
  1230. draw_oneSection (g, x1, x2, y1, y2, text [isection], fba.string, nullptr);
  1231. Graphics_line (g, x3, ymid, x1, ymid); // to the left
  1232. ic ++;
  1233. local_in -> x [ic] = x3;
  1234. local_out -> x [ic] = x2;
  1235. local_in -> y [ic] = local_out -> y [ic] = ymid;
  1236. y2 = y1 - 0.5 * dy;
  1237. }
  1238. }
  1239. ic = 0;
  1240. x1 = local_in -> y [1];
  1241. if (numberOfUpperPartFormants > 0) {
  1242. x1 = local_in -> x [numberOfUpperPartFormants]; y1 = local_in -> y [numberOfUpperPartFormants];
  1243. if (numberOfUpperPartFormants > 1)
  1244. Graphics_line (g, x1, y1, local_in -> x [1], local_in -> y [1]); // vertical
  1245. x2 = xmin;
  1246. if (numberOfLowerPartFormants > 0)
  1247. x2 += xw [1];
  1248. Graphics_line (g, x1, y1, x2, y1); // done
  1249. }
  1250. if (numberOfLowerPartFormants > 0) {
  1251. integer ifrom = numberOfUpperPartFormants + 1;
  1252. x1 = local_in -> x [ifrom];
  1253. y1 = local_in -> y [ifrom]; // at the split
  1254. if (numberOfLowerPartFormants > 1)
  1255. Graphics_line (g, x1, y1, local_in -> x [numberOfFormants], local_in -> y [numberOfFormants]); // vertical
  1256. x2 = xmin + xws [3]; // right of diff
  1257. Graphics_line (g, x1, y1, x2, y1); // from vertical to diff
  1258. x1 = xmin + xws [2]; // left of diff
  1259. draw_oneSection (g, x1, x2, y1 + 0.5 * dy, y1 - 0.5 * dy, U"Pre-emphasis", nullptr, nullptr);
  1260. x2 = x1;
  1261. if (numberOfUpperPartFormants > 0) {
  1262. x2 = xmin + xw [1];
  1263. y2 = y1; // at split
  1264. Graphics_line (g, x1, y1, x2, y1); // to split
  1265. y1 += (1 + ddy) * dy;
  1266. Graphics_line (g, x2, y2, x2, y1); // vertical
  1267. y1 -= 0.5 * (1.0 + ddy) * dy;
  1268. }
  1269. Graphics_line (g, xmin, y1, x2, y1);
  1270. }
  1271. r = xw [8] / 2.0;
  1272. x2 = xmax - r;
  1273. y2 = (ymin + ymax) / 2.0;
  1274. alternatingSummer_drawConnections (g, x2, y2, r, local_out, true, 0.4);
  1275. connections_free (local_out);
  1276. connections_free (local_in);
  1277. if (yin) {
  1278. *yin = y1;
  1279. }
  1280. if (yout) {
  1281. *yout = y2;
  1282. }
  1283. }
  1284. static void VocalTractGrid_CouplingGrid_draw_inside (VocalTractGrid me, CouplingGrid thee, Graphics g, int filterModel, double xmin, double xmax, double ymin, double ymax, double dy, double *yin, double *yout) {
  1285. filterModel == KlattGrid_FILTER_CASCADE ?
  1286. VocalTractGrid_CouplingGrid_drawCascade_inplace (me, thee, g, xmin, xmax, ymin, ymax, yin, yout) :
  1287. VocalTractGrid_CouplingGrid_drawParallel_inplace (me, thee, g, xmin, xmax, ymin, ymax, dy, yin, yout);
  1288. }
  1289. static void VocalTractGrid_CouplingGrid_draw (VocalTractGrid me, CouplingGrid thee, Graphics g, int filterModel) {
  1290. double xmin = 0.0, xmin1 = 0.05, xmax1 = 0.95, xmax = 1.0, ymin = 0.0, ymax = 1.0, dy = 0.5, yin, yout;
  1291. Graphics_setInner (g);
  1292. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  1293. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
  1294. Graphics_setLineWidth (g, 2);
  1295. VocalTractGrid_CouplingGrid_draw_inside (me, thee, g, filterModel, xmin1, xmax1, ymin, ymax, dy, &yin, &yout);
  1296. Graphics_line (g, xmin, yin, xmin1, yin);
  1297. Graphics_arrow (g, xmax1, yout, xmax, yout);
  1298. Graphics_unsetInner (g);
  1299. }
  1300. static autoSound Sound_VocalTractGrid_CouplingGrid_filter_cascade (Sound me, VocalTractGrid thee, CouplingGrid coupling) {
  1301. try {
  1302. VocalTractGridPlayOptions pv = thy options.get();
  1303. CouplingGridPlayOptions pc = coupling -> options.get();
  1304. bool useOpenGlottisInfo = pc -> openglottis && coupling && coupling -> glottis && coupling -> glottis -> points.size > 0;
  1305. FormantGrid oral_formants = thy oral_formants.get();
  1306. FormantGrid nasal_formants = thy nasal_formants.get();
  1307. FormantGrid nasal_antiformants = thy nasal_antiformants.get();
  1308. FormantGrid tracheal_formants = coupling -> tracheal_formants.get();
  1309. FormantGrid tracheal_antiformants = coupling -> tracheal_antiformants.get();
  1310. int antiformants = 0;
  1311. integer numberOfFormants = oral_formants -> formants.size;
  1312. integer numberOfTrachealFormants = tracheal_formants -> formants.size;
  1313. integer numberOfTrachealAntiFormants = tracheal_antiformants -> formants.size;
  1314. integer numberOfNasalFormants = nasal_formants -> formants.size;
  1315. integer numberOfNasalAntiFormants = nasal_antiformants -> formants.size;
  1316. check_formants (numberOfFormants, & pv -> startOralFormant, & pv -> endOralFormant);
  1317. check_formants (numberOfNasalFormants, & pv -> startNasalFormant, & pv -> endNasalFormant);
  1318. check_formants (numberOfTrachealFormants, & pc -> startTrachealFormant, & pc -> endTrachealFormant);
  1319. check_formants (numberOfNasalAntiFormants, & pv -> startNasalAntiFormant, & pv -> endNasalAntiFormant);
  1320. check_formants (numberOfTrachealAntiFormants, & pc -> startTrachealAntiFormant, & pc -> endTrachealAntiFormant);
  1321. autoSound him = Data_copy (me);
  1322. autoFormantGrid formants;
  1323. if (useOpenGlottisInfo) {
  1324. formants = Data_copy (thy oral_formants.get());
  1325. FormantGrid_CouplingGrid_updateOpenPhases (formants.get(), coupling);
  1326. }
  1327. integer nasal_formant_warning = 0, any_warning = 0;
  1328. if (pv -> endNasalFormant > 0) { // nasal formants
  1329. antiformants = 0;
  1330. for (integer iformant = pv -> startNasalFormant; iformant <= pv -> endNasalFormant; iformant ++) {
  1331. if (FormantGrid_isFormantDefined (thy nasal_formants.get(), iformant)) {
  1332. _Sound_FormantGrid_filterWithOneFormant_inplace (him.get(), thy nasal_formants.get(), iformant, antiformants);
  1333. } else {
  1334. // Melder_warning ("Nasal formant", iformant, ": frequency and/or bandwidth missing.");
  1335. nasal_formant_warning ++; any_warning ++;
  1336. }
  1337. }
  1338. }
  1339. integer nasal_antiformant_warning = 0;
  1340. if (pv -> endNasalAntiFormant > 0) { // nasal antiformants
  1341. antiformants = 1;
  1342. for (integer iformant = pv -> startNasalAntiFormant; iformant <= pv -> endNasalAntiFormant; iformant ++) {
  1343. if (FormantGrid_isFormantDefined (thy nasal_antiformants.get(), iformant)) {
  1344. _Sound_FormantGrid_filterWithOneFormant_inplace (him.get(), thy nasal_antiformants.get(), iformant, antiformants);
  1345. } else {
  1346. // Melder_warning ("Nasal antiformant", iformant, ": frequency and/or bandwidth missing.");
  1347. nasal_antiformant_warning ++; any_warning ++;
  1348. }
  1349. }
  1350. }
  1351. integer tracheal_formant_warning = 0;
  1352. if (pc -> endTrachealFormant > 0) { // tracheal formants
  1353. antiformants = 0;
  1354. for (integer iformant = pc -> startTrachealFormant; iformant <= pc -> endTrachealFormant; iformant ++) {
  1355. if (FormantGrid_isFormantDefined (tracheal_formants, iformant)) {
  1356. _Sound_FormantGrid_filterWithOneFormant_inplace (him.get(), tracheal_formants, iformant, antiformants);
  1357. } else {
  1358. // Melder_warning ("Tracheal formant", iformant, ": frequency and/or bandwidth missing.");
  1359. tracheal_formant_warning ++; any_warning ++;
  1360. }
  1361. }
  1362. }
  1363. integer tracheal_antiformant_warning = 0;
  1364. if (pc -> endTrachealAntiFormant > 0) { // tracheal antiformants
  1365. antiformants = 1;
  1366. for (integer iformant = pc -> startTrachealAntiFormant; iformant <= pc -> endTrachealAntiFormant; iformant ++) {
  1367. if (FormantGrid_isFormantDefined (tracheal_antiformants, iformant)) {
  1368. _Sound_FormantGrid_filterWithOneFormant_inplace (him.get(), tracheal_antiformants, iformant, antiformants);
  1369. } else {
  1370. // Melder_warning ("Tracheal antiformant", iformant, ": frequency and/or bandwidth missing.");
  1371. tracheal_antiformant_warning ++; any_warning ++;
  1372. }
  1373. }
  1374. }
  1375. integer oral_formant_warning = 0;
  1376. if (pv -> endOralFormant > 0) { // oral formants
  1377. antiformants = 0;
  1378. if (! formants) {
  1379. formants = Data_copy (thy oral_formants.get());
  1380. }
  1381. for (integer iformant = pv -> startOralFormant; iformant <= pv -> endOralFormant; iformant ++) {
  1382. if (FormantGrid_isFormantDefined (formants.get(), iformant)) {
  1383. _Sound_FormantGrid_filterWithOneFormant_inplace (him.get(), formants.get(), iformant, antiformants);
  1384. } else {
  1385. // Melder_warning ("Oral formant", iformant, ": frequency and/or bandwidth missing.");
  1386. oral_formant_warning ++; any_warning ++;
  1387. }
  1388. }
  1389. }
  1390. if (any_warning > 0)
  1391. {
  1392. autoMelderString warning;
  1393. if (nasal_formant_warning > 0) {
  1394. MelderString_append (&warning, U"\tNasal formants: one or more are missing.\n");
  1395. }
  1396. if (nasal_antiformant_warning) {
  1397. MelderString_append (&warning, U"\tNasal antiformants: one or more are missing.\n");
  1398. }
  1399. if (tracheal_formant_warning) {
  1400. MelderString_append (&warning, U"\tTracheal formants: one or more are missing.\n");
  1401. }
  1402. if (tracheal_antiformant_warning) {
  1403. MelderString_append (&warning, U"\tTracheal antiformants: one or more are missing.\n");
  1404. }
  1405. if (oral_formant_warning) {
  1406. MelderString_append (&warning, U"\tOral formants: one or more are missing.\n");
  1407. }
  1408. MelderInfo_write (U"\nWarning:\n", warning.string);
  1409. MelderInfo_drain ();
  1410. }
  1411. return him;
  1412. } catch (MelderError) {
  1413. Melder_throw (me, U": not filtered by vocaltract and coupling grid.");
  1414. }
  1415. }
  1416. static autoSound Sound_VocalTractGrid_CouplingGrid_filter_parallel (Sound me, VocalTractGrid thee, CouplingGrid coupling) {
  1417. try {
  1418. VocalTractGridPlayOptions pv = thy options.get();
  1419. CouplingGridPlayOptions pc = coupling -> options.get();
  1420. autoSound him;
  1421. FormantGrid oral_formants = thy oral_formants.get();
  1422. autoFormantGrid aof;
  1423. int alternatingSign = 0; // 0: no alternating signs in parallel adding of filter outputs, 1/-1 start sign
  1424. bool useOpenGlottisInfo = pc -> openglottis && coupling -> glottis && coupling -> glottis -> points.size > 0;
  1425. int scale = 1;
  1426. integer numberOfFormants = thy oral_formants -> formants.size;
  1427. integer numberOfNasalFormants = thy nasal_formants -> formants.size;
  1428. integer numberOfTrachealFormants = coupling -> tracheal_formants -> formants.size;
  1429. check_formants (numberOfFormants, & (pv -> startOralFormant), & (pv -> endOralFormant));
  1430. check_formants (numberOfNasalFormants, & (pv -> startNasalFormant), & (pv -> endNasalFormant));
  1431. check_formants (numberOfTrachealFormants, & (pc -> startTrachealFormant), & (pc -> endTrachealFormant));
  1432. if (useOpenGlottisInfo) {
  1433. aof = Data_copy (thy oral_formants.get());
  1434. oral_formants = aof.get();
  1435. FormantGrid_CouplingGrid_updateOpenPhases (oral_formants, coupling);
  1436. }
  1437. if (pv -> endOralFormant > 0) {
  1438. if (pv -> startOralFormant == 1) {
  1439. him = Data_copy (me);
  1440. if (oral_formants -> formants.size > 0) {
  1441. Sound_FormantGrid_Intensities_filterWithOneFormant_inplace (him.get(), oral_formants, & thy oral_formants_amplitudes, 1);
  1442. }
  1443. }
  1444. }
  1445. if (pv -> endNasalFormant > 0) {
  1446. alternatingSign = 0;
  1447. autoSound nasal = Sound_FormantGrid_Intensities_filter (me, thy nasal_formants.get(), & thy nasal_formants_amplitudes, pv -> startNasalFormant, pv -> endNasalFormant, alternatingSign);
  1448. if (! him) {
  1449. him = Data_copy (nasal.get());
  1450. } else {
  1451. _Sounds_add_inplace (him.get(), nasal.get());
  1452. }
  1453. }
  1454. // Formants 2 and up, with alternating signs.
  1455. // We perform pre-emphasis by differentiating.
  1456. // Klatt (1980) states that a first difference for the higher formants is necessary to remove low-frequency
  1457. // energy from them. This energy would otherwise distort the spectrum in the region of F1 during the synthesis
  1458. // of some vowels.
  1459. autoSound me_diff = _Sound_diff (me, scale);
  1460. if (pv -> endOralFormant >= 2) {
  1461. integer startOralFormant2 = pv -> startOralFormant > 2 ? pv -> startOralFormant : 2;
  1462. alternatingSign = ( startOralFormant2 % 2 == 0 ? -1 : 1 ); // 2 starts with negative sign
  1463. if (startOralFormant2 <= oral_formants -> formants.size) {
  1464. autoSound vocalTract = Sound_FormantGrid_Intensities_filter (me_diff.get(), oral_formants, & thy oral_formants_amplitudes, startOralFormant2, pv -> endOralFormant, alternatingSign);
  1465. if (! him) {
  1466. him = Data_copy (vocalTract.get());
  1467. } else {
  1468. _Sounds_add_inplace (him.get(), vocalTract.get());
  1469. }
  1470. }
  1471. }
  1472. if (pc -> endTrachealFormant > 0) { // tracheal formants
  1473. alternatingSign = 0;
  1474. autoSound trachea = Sound_FormantGrid_Intensities_filter (me_diff.get(), coupling -> tracheal_formants.get(), & coupling -> tracheal_formants_amplitudes,
  1475. pc -> startTrachealFormant, pc -> endTrachealFormant, alternatingSign);
  1476. if (! him) {
  1477. him = Data_copy (trachea.get());
  1478. } else {
  1479. _Sounds_add_inplace (him.get(), trachea.get());
  1480. }
  1481. }
  1482. if (! him) {
  1483. him = Data_copy (me);
  1484. }
  1485. return him;
  1486. } catch (MelderError) {
  1487. Melder_throw (me, U": not filtered in parallel.");
  1488. }
  1489. }
  1490. autoSound Sound_VocalTractGrid_CouplingGrid_filter (Sound me, VocalTractGrid thee, CouplingGrid coupling) {
  1491. return thy options -> filterModel == KlattGrid_FILTER_CASCADE ?
  1492. Sound_VocalTractGrid_CouplingGrid_filter_cascade (me, thee, coupling) :
  1493. Sound_VocalTractGrid_CouplingGrid_filter_parallel (me, thee, coupling);
  1494. }
  1495. /********************** CouplingGridPlayOptions **********************/
  1496. Thing_implement (CouplingGridPlayOptions, Daata, 0);
  1497. static void CouplingGridPlayOptions_setDefaults (CouplingGridPlayOptions me, CouplingGrid thee) {
  1498. my fadeFraction = 0.1;
  1499. my openglottis = 1;
  1500. my endTrachealFormant = std::min (thy tracheal_formants -> formants.size, thy tracheal_formants -> bandwidths.size);
  1501. my startTrachealFormant = 1;
  1502. my endTrachealAntiFormant = std::min (thy tracheal_antiformants -> formants.size, thy tracheal_antiformants -> bandwidths.size);
  1503. my startTrachealAntiFormant = 1;
  1504. my startDeltaFormant = 1;
  1505. my endDeltaFormant = thy delta_formants -> formants.size;
  1506. my startDeltaBandwidth = 1;
  1507. my endDeltaBandwidth = thy delta_formants -> bandwidths.size;
  1508. }
  1509. autoCouplingGridPlayOptions CouplingGridPlayOptions_create () {
  1510. try {
  1511. autoCouplingGridPlayOptions me = Thing_new (CouplingGridPlayOptions);
  1512. return me;
  1513. } catch (MelderError) {
  1514. Melder_throw (U"CouplingGridPlayOptions not created.");
  1515. }
  1516. }
  1517. /********************** CouplingGrid *************************************/
  1518. Thing_implement (CouplingGrid, Function, 0);
  1519. void structCouplingGrid :: v_info () {
  1520. structDaata :: v_info ();
  1521. conststring32 in1 = U" ", in2 = U" ", in3 = U" ";
  1522. MelderInfo_writeLine (in1, U"Time domain:");
  1523. MelderInfo_writeLine (in2, U"Start time: ", xmin, U" seconds");
  1524. MelderInfo_writeLine (in2, U"End time: ", xmax, U" seconds");
  1525. MelderInfo_writeLine (in2, U"Total duration: ", xmax - xmin, U" seconds");
  1526. MelderInfo_writeLine (in1, U"\nNumber of points in the TRACHEAL FORMANT tiers:");
  1527. FormantGrid_info (our tracheal_formants.get(), & tracheal_formants_amplitudes, in2, in3);
  1528. MelderInfo_writeLine (in1, U"\nNumber of points in the TRACHEAL ANTIFORMANT tiers:");
  1529. FormantGrid_info (our tracheal_antiformants.get(), nullptr, in2, in3);
  1530. MelderInfo_writeLine (in1, U"\nNumber of points in the DELTA FORMANT tiers:");
  1531. FormantGrid_info (our delta_formants.get(), nullptr, in2, in3);
  1532. }
  1533. void CouplingGrid_setNames (CouplingGrid me) {
  1534. Thing_setName (my tracheal_formants.get(), U"tracheal_formants");
  1535. Thing_setName (my tracheal_antiformants.get(), U"tracheal_antiformants");
  1536. //Thing_setName (my tracheal_formants_amplitudes.get(), U"tracheal_formants_amplitudes");
  1537. Thing_setName (my delta_formants.get(), U"delta_formants");
  1538. Thing_setName (my glottis.get(), U"glottis");
  1539. }
  1540. autoCouplingGrid CouplingGrid_create (double tmin, double tmax, integer numberOfTrachealFormants, integer numberOfTrachealAntiFormants, integer numberOfDeltaFormants) {
  1541. try {
  1542. autoCouplingGrid me = Thing_new (CouplingGrid);
  1543. Function_init (me.get(), tmin, tmax);
  1544. my tracheal_formants = FormantGrid_createEmpty (tmin, tmax, numberOfTrachealFormants);
  1545. my tracheal_antiformants = FormantGrid_createEmpty (tmin, tmax, numberOfTrachealAntiFormants);
  1546. formantsAmplitudes_create (& my tracheal_formants_amplitudes, tmin, tmax, numberOfTrachealFormants);
  1547. my delta_formants = FormantGrid_createEmpty (tmin, tmax, numberOfDeltaFormants);
  1548. my glottis = PhonationTier_create (tmin, tmax);
  1549. my options = CouplingGridPlayOptions_create ();
  1550. CouplingGrid_setNames (me.get());
  1551. return me;
  1552. } catch (MelderError) {
  1553. Melder_throw (U"CouplingGrid not created.");
  1554. }
  1555. }
  1556. /********************** FormantGrid & CouplingGrid *************************************/
  1557. void FormantGrid_CouplingGrid_updateOpenPhases (FormantGrid me, CouplingGrid thee) {
  1558. try {
  1559. CouplingGridPlayOptions pc = thy options.get();
  1560. for (integer itier = 1; itier <= thy delta_formants -> formants.size; itier ++) {
  1561. RealTier delta = thy delta_formants -> formants.at [itier];
  1562. if (itier <= my formants.size) {
  1563. if (delta -> points.size > 0) {
  1564. autoRealTier rt = RealTier_updateWithDelta (my formants.at [itier], delta, thy glottis.get(), pc -> fadeFraction);
  1565. Melder_require (RealTier_valuesInRange (rt.get(), 0, undefined), U"Formant ", itier, U" coupling should not give negative values.");
  1566. my formants. replaceItem_move (rt.move(), itier);
  1567. }
  1568. }
  1569. delta = thy delta_formants -> bandwidths.at [itier];
  1570. if (itier <= my bandwidths.size) {
  1571. if (delta -> points.size > 0) {
  1572. autoRealTier rt = RealTier_updateWithDelta (my bandwidths.at [itier], delta, thy glottis.get(), pc -> fadeFraction);
  1573. Melder_require (RealTier_valuesInRange (rt.get(), 0, undefined), U"Bandwidth ", itier, U" coupling gives negative values.");
  1574. my bandwidths. replaceItem_move (rt.move(), itier);
  1575. }
  1576. }
  1577. }
  1578. } catch (MelderError) {
  1579. Melder_throw (me, U": not updated with open hase information.");
  1580. }
  1581. }
  1582. /********************** FricationGridPlayOptions **********************/
  1583. Thing_implement (FricationGridPlayOptions, Daata, 0);
  1584. static void FricationGridPlayOptions_setDefaults (FricationGridPlayOptions me, FricationGrid thee) {
  1585. my endFricationFormant = std::min (thy frication_formants -> formants.size, thy frication_formants -> bandwidths.size);
  1586. my startFricationFormant = 2;
  1587. my bypass = 1;
  1588. }
  1589. autoFricationGridPlayOptions FricationGridPlayOptions_create () {
  1590. try {
  1591. autoFricationGridPlayOptions me = Thing_new (FricationGridPlayOptions);
  1592. return me;
  1593. } catch (MelderError) {
  1594. Melder_throw (U"FricationGridPlayOptions not created.");
  1595. }
  1596. }
  1597. /************************ FricationGrid (& Sound) *********************************************/
  1598. void structFricationGrid :: v_info () {
  1599. structDaata :: v_info ();
  1600. const static char32 *in1 = U" ", *in2 = U" ", *in3 = U" ";
  1601. MelderInfo_writeLine (in1, U"Time domain:");
  1602. MelderInfo_writeLine (in2, U"Start time: ", xmin, U" seconds");
  1603. MelderInfo_writeLine (in2, U"End time: ", xmax, U" seconds");
  1604. MelderInfo_writeLine (in2, U"Total duration: ", xmax - xmin, U" seconds");
  1605. MelderInfo_writeLine (in1, U"\nNumber of points in the FRICATION tiers:");
  1606. MelderInfo_writeLine (in2, U"fricationAmplitude: ", fricationAmplitude -> points.size);
  1607. MelderInfo_writeLine (in2, U"bypass: ", bypass -> points.size);
  1608. MelderInfo_writeLine (in1, U"\nNumber of points in the FRICATION FORMANT tiers:");
  1609. FormantGrid_info (our frication_formants.get(), & our frication_formants_amplitudes, in2, in3);
  1610. }
  1611. Thing_implement (FricationGrid, Function, 0);
  1612. void FricationGrid_setNames (FricationGrid me) {
  1613. Thing_setName (my fricationAmplitude.get(), U"fricationAmplitude");
  1614. Thing_setName (my frication_formants.get(), U"frication_formants");
  1615. Thing_setName (my bypass.get(), U"bypass");
  1616. //Thing_setName (my frication_formants_amplitudes.get(), U"frication_formants_amplitudes");
  1617. }
  1618. autoFricationGrid FricationGrid_create (double tmin, double tmax, integer numberOfFormants) {
  1619. try {
  1620. autoFricationGrid me = Thing_new (FricationGrid);
  1621. Function_init (me.get(), tmin, tmax);
  1622. my fricationAmplitude = IntensityTier_create (tmin, tmax);
  1623. my frication_formants = FormantGrid_createEmpty (tmin, tmax, numberOfFormants);
  1624. my bypass = IntensityTier_create (tmin, tmax);
  1625. formantsAmplitudes_create (& my frication_formants_amplitudes, tmin, tmax, numberOfFormants);
  1626. my options = FricationGridPlayOptions_create ();
  1627. FricationGrid_setNames (me.get());
  1628. return me;
  1629. } catch (MelderError) {
  1630. Melder_throw (U"FricationGrid not created.");
  1631. }
  1632. }
  1633. static void FricationGrid_draw_inside (FricationGrid me, Graphics g, double xmin, double xmax, double ymin, double ymax, double dy, double *yout) {
  1634. integer numberOfXSections = 5;
  1635. integer numberOfFormants = my frication_formants -> formants.size;
  1636. integer numberOfParts = numberOfFormants + ( numberOfFormants > 1 ? 0 : 1 ) ; // 2..number + bypass
  1637. // dum noise, connections, filter, connections, adder
  1638. double xw [6] = { 0.0, 2, 0.6, 1.5, 0.6, 0.5 }, xws [6];
  1639. double r, x1, y1, x2, y2, x3, xs, ys, ymid = (ymin + ymax) / 2.0;
  1640. rel_to_abs (xw, xws, numberOfXSections, xmax - xmin);
  1641. dy = dy < 0.0 ? 0.0 : dy;
  1642. dy = (ymax - ymin) / (numberOfParts * (1.0 + dy) - dy);
  1643. connections cp = connections_create (numberOfParts);
  1644. if (cp == 0) {
  1645. return;
  1646. }
  1647. // section 1
  1648. x1 = xmin;
  1649. x2 = x1 + xw [1];
  1650. y1 = ymid - 0.5 * dy;
  1651. y2 = y1 + dy;
  1652. draw_oneSection (g, x1, x2, y1, y2, U"Frication", U"noise", nullptr);
  1653. // section 2, horizontal line halfway, vertical line
  1654. x1 = x2;
  1655. x2 = x1 + xw [2] / 2.0;
  1656. Graphics_line (g, x1, ymid, x2, ymid);
  1657. Graphics_line (g, x2, ymax - dy / 2, x2, ymin + dy / 2.0);
  1658. x3 = x2;
  1659. // final connection to section 2 , filters , connections to adder
  1660. x1 = xmin + xws [2];
  1661. x2 = x1 + xw [3];
  1662. y2 = ymax;
  1663. autoMelderString fba;
  1664. for (integer i = 1; i <= numberOfParts; i ++) {
  1665. conststring32 fi = Melder_integer (i + 1);
  1666. y1 = y2 - dy;
  1667. if (i < numberOfParts) {
  1668. MelderString_copy (&fba, U"A", fi, U" F", fi, U" B", fi);
  1669. } else {
  1670. MelderString_copy (&fba, U"Bypass");
  1671. }
  1672. draw_oneSection (g, x1, x2, y1, y2, nullptr, fba.string, nullptr);
  1673. double ymidi = (y1 + y2) / 2.0;
  1674. Graphics_line (g, x3, ymidi, x1, ymidi); // from noise to filter
  1675. cp -> x [i] = x2;
  1676. cp -> y [i] = ymidi;
  1677. y2 = y1 - 0.5 * dy;
  1678. }
  1679. r = xw [5] / 2.0;
  1680. xs = xmax - r;
  1681. ys = ymid;
  1682. if (numberOfParts > 1) {
  1683. alternatingSummer_drawConnections (g, xs, ys, r, cp, 1, 0.4);
  1684. } else {
  1685. Graphics_line (g, cp -> x [1], cp -> y [1], xs + r, ys);
  1686. }
  1687. connections_free (cp);
  1688. if (yout) {
  1689. *yout = ys;
  1690. }
  1691. }
  1692. void FricationGrid_draw (FricationGrid me, Graphics g) {
  1693. double xmin = 0.0, xmax = 1.0, xmax2 = 0.9, ymin = 0.0, ymax = 1.0, dy = 0.5, yout;
  1694. Graphics_setInner (g);
  1695. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  1696. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
  1697. Graphics_setLineWidth (g, 2);
  1698. FricationGrid_draw_inside (me, g, xmin, xmax2, ymin, ymax, dy, &yout);
  1699. Graphics_arrow (g, xmax2, yout, xmax, yout);
  1700. Graphics_unsetInner (g);
  1701. }
  1702. autoSound FricationGrid_to_Sound (FricationGrid me, double samplingFrequency) {
  1703. try {
  1704. autoSound thee = Sound_createEmptyMono (my xmin, my xmax, samplingFrequency);
  1705. double lastval = 0.0;
  1706. for (integer i = 1; i <= thy nx; i ++) {
  1707. double t = thy x1 + (i - 1) * thy dx;
  1708. double val = NUMrandomUniform (-1.0, 1.0);
  1709. double a = 0.0;
  1710. if (my fricationAmplitude -> points.size > 0) {
  1711. double dba = RealTier_getValueAtTime (my fricationAmplitude.get(), t);
  1712. a = ( isdefined (dba) ? DBSPL_to_A (dba) : 0.0 );
  1713. }
  1714. lastval = (val += 0.75 * lastval); // TODO: soft low-pass coefficient should be Fs dependent!
  1715. thy z [1] [i] = val * a;
  1716. }
  1717. autoSound him = Sound_FricationGrid_filter (thee.get(), me);
  1718. return him;
  1719. } catch (MelderError) {
  1720. Melder_throw (me, U": no frication Sound created.");
  1721. }
  1722. }
  1723. /************************ Sound & FricationGrid *********************************************/
  1724. autoSound Sound_FricationGrid_filter (Sound me, FricationGrid thee) {
  1725. try {
  1726. FricationGridPlayOptions pf = thy options.get();
  1727. autoSound him;
  1728. integer numberOfFricationFormants = thy frication_formants -> formants.size;
  1729. check_formants (numberOfFricationFormants, & (pf -> startFricationFormant), & (pf -> endFricationFormant));
  1730. if (pf -> endFricationFormant > 1) {
  1731. integer startFricationFormant2 = pf -> startFricationFormant > 2 ? pf -> startFricationFormant : 2;
  1732. int alternatingSign = startFricationFormant2 % 2 == 0 ? 1 : -1; // 2 starts with positive sign
  1733. him = Sound_FormantGrid_Intensities_filter (me, thy frication_formants.get(), & thy frication_formants_amplitudes, startFricationFormant2, pf -> endFricationFormant, alternatingSign);
  1734. }
  1735. if (! him) {
  1736. him = Data_copy (me);
  1737. }
  1738. if (pf -> bypass) {
  1739. for (integer is = 1; is <= his nx; is ++) { // Bypass
  1740. double t = his x1 + (is - 1) * his dx;
  1741. double ab = 0.0;
  1742. if (thy bypass -> points.size > 0) {
  1743. double val = RealTier_getValueAtTime (thy bypass.get(), t);
  1744. ab = ( isundef (val) ? 0.0 : DB_to_A (val) );
  1745. }
  1746. his z [1] [is] += my z [1] [is] * ab;
  1747. }
  1748. }
  1749. return him;
  1750. } catch (MelderError) {
  1751. Melder_throw (me, U": not filtered by frication filter.");
  1752. }
  1753. }
  1754. /********************** KlattGridPlayOptions **********************/
  1755. Thing_implement (KlattGridPlayOptions, Daata, 0);
  1756. static void KlattGridPlayOptions_setDefaults (KlattGridPlayOptions me, KlattGrid thee) {
  1757. my samplingFrequency = 44100.0;
  1758. my scalePeak = 1;
  1759. my xmin = thy xmin;
  1760. my xmax = thy xmax;
  1761. }
  1762. autoKlattGridPlayOptions KlattGridPlayOptions_create () {
  1763. try {
  1764. autoKlattGridPlayOptions me = Thing_new (KlattGridPlayOptions);
  1765. return me;
  1766. } catch (MelderError) {
  1767. Melder_throw (U"KlattGridPlayOptions not created.");
  1768. }
  1769. }
  1770. void KlattGrid_setDefaultPlayOptions (KlattGrid me) {
  1771. KlattGridPlayOptions_setDefaults (my options.get(), me);
  1772. PhonationGridPlayOptions_setDefaults (my phonation -> options.get());
  1773. VocalTractGridPlayOptions_setDefaults (my vocalTract -> options.get(), my vocalTract.get());
  1774. CouplingGridPlayOptions_setDefaults (my coupling -> options.get(), my coupling.get());
  1775. FricationGridPlayOptions_setDefaults (my frication -> options.get(), my frication.get());
  1776. }
  1777. /************************ KlattGrid *********************************************/
  1778. Thing_implement (KlattGrid, Function, 0);
  1779. void structKlattGrid :: v_info () {
  1780. structDaata :: v_info ();
  1781. MelderInfo_writeLine (U"Time domain:");
  1782. MelderInfo_writeLine (U" Start time: ", xmin, U" seconds");
  1783. MelderInfo_writeLine (U" End time: ", xmax, U" seconds");
  1784. MelderInfo_writeLine (U" Total duration: ", xmax - xmin, U" seconds");
  1785. MelderInfo_writeLine (U"\n--- PhonationGrid ---\n");
  1786. phonation -> v_info ();
  1787. MelderInfo_writeLine (U"\n--- VocalTractGrid ---\n");
  1788. vocalTract -> v_info ();
  1789. MelderInfo_writeLine (U"\n--- CouplingGrid ---\n");
  1790. coupling -> v_info ();
  1791. MelderInfo_writeLine (U"\n--- FricationgGrid ---\n");
  1792. frication -> v_info ();
  1793. }
  1794. void KlattGrid_setNames (KlattGrid me) {
  1795. Thing_setName (my phonation.get(), U"phonation");
  1796. Thing_setName (my vocalTract.get(), U"vocalTract");
  1797. Thing_setName (my coupling.get(), U"coupling");
  1798. Thing_setName (my frication.get(), U"frication");
  1799. Thing_setName (my gain.get(), U"gain");
  1800. }
  1801. autoKlattGrid KlattGrid_create (double tmin, double tmax, integer numberOfFormants, integer numberOfNasalFormants, integer numberOfNasalAntiFormants, integer numberOfTrachealFormants, integer numberOfTrachealAntiFormants, integer numberOfFricationFormants, integer numberOfDeltaFormants) {
  1802. try {
  1803. autoKlattGrid me = Thing_new (KlattGrid);
  1804. Function_init (me.get(), tmin, tmax);
  1805. my phonation = PhonationGrid_create (tmin, tmax);
  1806. my vocalTract = VocalTractGrid_create (tmin, tmax, numberOfFormants, numberOfNasalFormants, numberOfNasalAntiFormants);
  1807. my coupling = CouplingGrid_create (tmin, tmax, numberOfTrachealFormants, numberOfTrachealAntiFormants, numberOfDeltaFormants);
  1808. my frication = FricationGrid_create (tmin, tmax, numberOfFricationFormants);
  1809. my gain = IntensityTier_create (tmin, tmax);
  1810. my options = KlattGridPlayOptions_create ();
  1811. KlattGrid_setDefaultPlayOptions (me.get());
  1812. KlattGrid_setNames (me.get());
  1813. return me;
  1814. } catch (MelderError) {
  1815. Melder_throw (U"KlattGrid not created.");
  1816. }
  1817. }
  1818. autoKlattGrid KlattGrid_createExample () {
  1819. try {
  1820. autoKlattTable thee = KlattTable_createExample ();
  1821. autoKlattGrid me = KlattTable_to_KlattGrid (thee.get(), 0.005);
  1822. return me;
  1823. } catch (MelderError) {
  1824. Melder_throw (U"KlattGrid example not created.");
  1825. };
  1826. }
  1827. // y is the height in units of the height of one section,
  1828. // y1 is the height from the top to the split between the uppper, non-diffed, and lower diffed part
  1829. static void _KlattGrid_queryParallelSplit (KlattGrid me, double dy, double *y, double *y1) {
  1830. integer ny = my vocalTract -> nasal_formants -> formants.size +
  1831. my vocalTract -> oral_formants -> formants.size + my coupling -> tracheal_formants -> formants.size;
  1832. integer n1 = my vocalTract -> nasal_formants -> formants.size +
  1833. ( my vocalTract -> oral_formants -> formants.size > 0 ? 1 : 0 );
  1834. integer n2 = ny - n1;
  1835. if (ny == 0) {
  1836. *y = 0.0;
  1837. *y1 = 0.0;
  1838. return;
  1839. }
  1840. *y = ny + (ny - 1) * dy;
  1841. if (n1 == 0) {
  1842. *y1 = 0.5;
  1843. } else if (n2 == 0) {
  1844. *y1 = *y - 0.5;
  1845. } else {
  1846. *y1 = n1 + (n1 - 1) * dy + 0.5 * dy;
  1847. }
  1848. return;
  1849. }
  1850. static void getYpositions (double h1, double h2, double h3, double h4, double h5, double fractionOverlap, double *dy, double *ymin1, double *ymax1, double *ymin2, double *ymax2, double *ymin3, double *ymax3) {
  1851. // Given: five 'blocks' with relative heights h1..h5 in arbitrary units.
  1852. // Problem: scale all h1..h5 such that:
  1853. // 1. blocks h1 and h2 form one unit, with h1 on top of h2, the quotient h1/h2 is fixed
  1854. // 2. blocks h3 and h4 form one unit, with h3 on top of h4, the quotient h3/h4 is fixed
  1855. // 3. blocks h1 and h3 have the same baseline.
  1856. // 4. h5 is always underneath (h1,h2) but may partially overlap (0.45) with h4.
  1857. // 5. After scaling the new h1+h2 >= 0.3
  1858. // 6. Optimally use the vertical space from 0.. 1, i.e the top of h1 or h3 is at 1,
  1859. // the bottom of h5 is at 0. Preferably scale all blocks with the same factor, if not possible than
  1860. // scale h3,h4 and h5 the same
  1861. //
  1862. // h1 h3
  1863. // h2 h4
  1864. // h5
  1865. /* Cases:
  1866. x x ^
  1867. x x x x x x |
  1868. h1 x x x x x x x x h3 | h13
  1869. -----------------------------------------------------------
  1870. h2 x x x x x x x x h4
  1871. x x x x x x
  1872. x x
  1873. x x x x x x
  1874. h5 x x x x
  1875. x x x x
  1876. */
  1877. double h; // h12_min = 0.3; not yet
  1878. double h13 = ( h1 > h3 ? h1 : h3 ); // baselines are now equal
  1879. if (h2 >= h4) {
  1880. h = h13 + h2 + h5;
  1881. } else { // h2 < h4
  1882. double maximumOverlap3 = fractionOverlap * h5;
  1883. if (maximumOverlap3 < h1 + h2) {
  1884. maximumOverlap3 = 0.0;
  1885. } else if (maximumOverlap3 > h4 - h2) {
  1886. maximumOverlap3 = h4 - h2;
  1887. }
  1888. h = h13 + h4 + h5 - maximumOverlap3;
  1889. }
  1890. *dy = 1.0 / (1.1 * h);
  1891. *ymin1 = 1.0 - (h13 + h2) * *dy;
  1892. *ymax1 = *ymin1 + (h1 + h2) * *dy;
  1893. *ymin2 = 1.0 - (h13 + h4) * *dy;
  1894. *ymax2 = *ymin2 + (h3 + h4) * *dy;
  1895. *ymin3 = 0.0;
  1896. *ymax3 = h5 * *dy;
  1897. }
  1898. void KlattGrid_drawVocalTract (KlattGrid me, Graphics g, int filterModel, int withTrachea) {
  1899. VocalTractGrid_CouplingGrid_draw (my vocalTract.get(), withTrachea ? my coupling.get() : nullptr, g, filterModel);
  1900. }
  1901. void KlattGrid_draw (KlattGrid me, Graphics g, int filterModel) {
  1902. double xs1, xs2, ys1, ys2, xf1, xf2, yf1, yf2;
  1903. double xp1, xp2, yp1, yp2, xc1, xc2, yc1, yc2;
  1904. double dy, r, xs, ys;
  1905. double xmin = 0.0, xmax2 = 0.90, xmax3 = 0.95, xmax = 1.0, ymin = 0.0, ymax = 1.0;
  1906. double xws [6];
  1907. double height_phonation = 0.3;
  1908. double dy_phonation = 0.5, dy_vocalTract_p = 0.5, dy_frication = 0.5;
  1909. connections tf;
  1910. try {
  1911. tf = connections_create (2);
  1912. } catch (MelderError) {
  1913. Melder_clearError ();
  1914. return;
  1915. }
  1916. Graphics_setInner (g);
  1917. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  1918. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
  1919. Graphics_setLineWidth (g, 2);
  1920. integer nff = my frication -> frication_formants -> formants.size - 1 + 1;
  1921. double yh_frication = ( nff > 0 ? nff + (nff - 1) * dy_frication : 1.0 );
  1922. double yh_phonation = 1.0 + dy_phonation + 1.0;
  1923. double yout_phonation, yout_frication;
  1924. dy = height_phonation / yh_phonation; // 1 vertical unit in source section height units
  1925. if (filterModel == KlattGrid_FILTER_CASCADE) { // Cascade section
  1926. // source connection tract connection, out
  1927. // frication
  1928. double xw [6] = {0, 1.75, 0.125, 3, 0.25, 0.125 };
  1929. double yin_vocalTract_c, yout_vocalTract_c;
  1930. rel_to_abs (xw, xws, 5, xmax2 - xmin);
  1931. // limit height of frication unit dy !
  1932. height_phonation = yh_phonation / (yh_phonation + yh_frication);
  1933. if (height_phonation < 0.3) {
  1934. height_phonation = 0.3;
  1935. }
  1936. dy = height_phonation / yh_phonation;
  1937. xs1 = xmin;
  1938. xs2 = xs1 + xw [1];
  1939. ys2 = ymax;
  1940. ys1 = ys2 - height_phonation;
  1941. PhonationGrid_draw_inside (my phonation.get(), g, xs1, xs2, ys1, ys2, dy_phonation, &yout_phonation);
  1942. // units in cascade have same heigth as units in source part.
  1943. xc1 = xmin + xws [2];
  1944. xc2 = xc1 + xw [3];
  1945. yc2 = yout_phonation + dy / 2.0;
  1946. yc1 = yc2 - dy;
  1947. VocalTractGrid_CouplingGrid_drawCascade_inplace (my vocalTract.get(), my coupling.get(), g, xc1, xc2, yc1, yc2, &yin_vocalTract_c, &yout_vocalTract_c);
  1948. tf -> x [1] = xc2;
  1949. tf -> y [1] = yout_vocalTract_c;
  1950. Graphics_line (g, xs2, yout_phonation, xc1, yin_vocalTract_c);
  1951. xf1 = xmin + xws [2];
  1952. xf2 = xf1 + xw [3];
  1953. yf2 = ymax - height_phonation;
  1954. yf1 = 0.0;
  1955. FricationGrid_draw_inside (my frication.get(), g, xf1, xf2, yf1, yf2, dy_frication, &yout_frication);
  1956. } else { // Parallel
  1957. // source connection tract connection, out
  1958. // frication
  1959. double yf_parallel, yh_parallel, yh_overlap = 0.3, yin_vocalTract_p, yout_vocalTract_p;
  1960. double xw [6] = { 0.0, 1.75, 0.125, 3.0, 0.25, 0.125 };
  1961. rel_to_abs (xw, xws, 5, xmax2 - xmin);
  1962. // optimize the vertical space for source, parallel and frication
  1963. // source part is relatively fixed. let the number of vertical section units be the divisor
  1964. // connector line from source to parallel has to be horizontal
  1965. // determine y's of source and parallel section
  1966. _KlattGrid_queryParallelSplit (me, dy_vocalTract_p, &yh_parallel, &yf_parallel);
  1967. if (yh_parallel == 0.0) {
  1968. yh_parallel = yh_phonation;
  1969. yf_parallel = yh_parallel / 2.0;
  1970. yh_overlap = -0.1;
  1971. }
  1972. height_phonation = yh_phonation / (yh_phonation + yh_frication);
  1973. if (height_phonation < 0.3) {
  1974. height_phonation = 0.3;
  1975. }
  1976. //double yunit = (ymax - ymin) / (yh_parallel + (1 - yh_overlap) * yh_frication); // some overlap
  1977. //double ycs = ymax - 0.5 * height_phonation; // source output connector
  1978. //double ycp = ymax - yf_parallel * yunit; // parallel input connector
  1979. //double ytrans_phonation = ycs > ycp ? ycp - ycs : 0;
  1980. //double ytrans_parallel = ycp > ycs ? ycs - ycp : 0;
  1981. // source, tract, frication
  1982. xs1 = xmin; xs2 = xs1 + xw [1];
  1983. double h1 = yh_phonation / 2.0, h2 = h1, h3 = yf_parallel, h4 = yh_parallel - h3, h5 = yh_frication;
  1984. getYpositions (h1, h2, h3, h4, h5, yh_overlap, &dy, &ys1, &ys2, &yp1, &yp2, &yf1, &yf2);
  1985. PhonationGrid_draw_inside (my phonation.get(), g, xs1, xs2, ys1, ys2, dy_phonation, &yout_phonation);
  1986. xp1 = xmin + xws [2];
  1987. xp2 = xp1 + xw [3];
  1988. VocalTractGrid_CouplingGrid_drawParallel_inplace (my vocalTract.get(), my coupling.get(), g, xp1, xp2, yp1, yp2, dy_vocalTract_p, &yin_vocalTract_p, &yout_vocalTract_p);
  1989. tf -> x [1] = xp2;
  1990. tf -> y [1] = yout_vocalTract_p;
  1991. Graphics_line (g, xs2, yout_phonation, xp1, yin_vocalTract_p);
  1992. xf1 = xmin /* + 0.5 * xws [1] */;
  1993. xf2 = xf1 + 0.55 * (xw [2] + xws [3]);
  1994. FricationGrid_draw_inside (my frication.get(), g, xf1, xf2, yf1, yf2, dy_frication, &yout_frication);
  1995. }
  1996. tf -> x [2] = xf2;
  1997. tf -> y [2] = yout_frication;
  1998. r = (xmax3 - xmax2) / 2.0;
  1999. xs = xmax2 + r / 2.0;
  2000. ys = (ymax - ymin) / 2.0;
  2001. summer_drawConnections (g, xs, ys, r, tf, true, 0.6);
  2002. Graphics_arrow (g, xs + r, ys, xmax, ys);
  2003. Graphics_unsetInner (g);
  2004. connections_free (tf);
  2005. }
  2006. /**** Query, Add, Remove, Extract Replace ********/
  2007. #define PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE(Name,name,tierType) \
  2008. double KlattGrid_get##Name##AtTime (KlattGrid me, double t) \
  2009. { return RealTier_getValueAtTime (my phonation -> name.get(), t); } \
  2010. void KlattGrid_add##Name##Point (KlattGrid me, double t, double value) \
  2011. { RealTier_addPoint (my phonation -> name.get(), t, value);} \
  2012. void KlattGrid_remove##Name##Points (KlattGrid me, double t1, double t2) \
  2013. { AnyTier_removePointsBetween (my phonation -> name.get()->asAnyTier(), t1, t2); } \
  2014. auto##tierType KlattGrid_extract##Name##Tier (KlattGrid me) \
  2015. { return Data_copy (my phonation -> name.get()); } \
  2016. void KlattGrid_replace##Name##Tier (KlattGrid me, tierType thee) \
  2017. { try {\
  2018. Melder_require (my xmin == thy xmin && my xmax == thy xmax, U"Domains should be equal"); \
  2019. auto##tierType any = Data_copy (thee); \
  2020. my phonation -> name = any.move(); \
  2021. } catch (MelderError) { Melder_throw (me, U": tier not replaced."); } \
  2022. }
  2023. // Generate 55 functions
  2024. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (Pitch, pitch, PitchTier)
  2025. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (VoicingAmplitude, voicingAmplitude, IntensityTier)
  2026. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (Flutter, flutter, RealTier)
  2027. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (Power1, power1, RealTier)
  2028. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (Power2, power2, RealTier)
  2029. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (OpenPhase, openPhase, RealTier)
  2030. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (CollisionPhase, collisionPhase, RealTier)
  2031. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (DoublePulsing, doublePulsing, RealTier)
  2032. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (SpectralTilt, spectralTilt, IntensityTier)
  2033. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (AspirationAmplitude, aspirationAmplitude, IntensityTier)
  2034. PhonationGrid_QUERY_ADD_REMOVE_EXTRACT_REPLACE (BreathinessAmplitude, breathinessAmplitude, IntensityTier)
  2035. autoFormantGrid* KlattGrid_getAddressOfFormantGrid (KlattGrid me, int formantType) {
  2036. return formantType == KlattGrid_ORAL_FORMANTS ? & my vocalTract -> oral_formants :
  2037. formantType == KlattGrid_NASAL_FORMANTS ? & my vocalTract -> nasal_formants :
  2038. formantType == KlattGrid_FRICATION_FORMANTS ? & my frication -> frication_formants :
  2039. formantType == KlattGrid_TRACHEAL_FORMANTS ? & my coupling -> tracheal_formants :
  2040. formantType == KlattGrid_NASAL_ANTIFORMANTS ? & my vocalTract -> nasal_antiformants :
  2041. formantType == KlattGrid_TRACHEAL_ANTIFORMANTS ? & my coupling -> tracheal_antiformants :
  2042. formantType == KlattGrid_DELTA_FORMANTS ? & my coupling -> delta_formants : nullptr;
  2043. }
  2044. OrderedOf<structIntensityTier>* KlattGrid_getAddressOfAmplitudes (KlattGrid me, int formantType) {
  2045. return formantType == KlattGrid_ORAL_FORMANTS ? & my vocalTract -> oral_formants_amplitudes :
  2046. formantType == KlattGrid_NASAL_FORMANTS ? & my vocalTract -> nasal_formants_amplitudes :
  2047. formantType == KlattGrid_FRICATION_FORMANTS ? & my frication -> frication_formants_amplitudes :
  2048. formantType == KlattGrid_TRACHEAL_FORMANTS ? & my coupling -> tracheal_formants_amplitudes : nullptr;
  2049. }
  2050. #define KlattGrid_QUERY_ADD_REMOVE(Name) \
  2051. double KlattGrid_get##Name##AtTime (KlattGrid me, int formantType, integer iformant, double t) \
  2052. { \
  2053. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType); \
  2054. return FormantGrid_get##Name##AtTime (fg->get(), iformant, t); \
  2055. } \
  2056. void KlattGrid_add##Name##Point (KlattGrid me, int formantType, integer iformant, double t, double value) \
  2057. { \
  2058. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType); \
  2059. FormantGrid_add##Name##Point (fg->get(), iformant, t, value); \
  2060. } \
  2061. void KlattGrid_remove##Name##Points (KlattGrid me, int formantType, integer iformant, double t1, double t2) \
  2062. { \
  2063. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType); \
  2064. FormantGrid_remove##Name##PointsBetween (fg->get(), iformant, t1, t2); \
  2065. }
  2066. // 6 functions
  2067. KlattGrid_QUERY_ADD_REMOVE (Formant)
  2068. KlattGrid_QUERY_ADD_REMOVE (Bandwidth)
  2069. void KlattGrid_formula_frequencies (KlattGrid me, int formantType, conststring32 expression, Interpreter interpreter) {
  2070. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType);
  2071. FormantGrid_formula_frequencies (fg->get(), expression, interpreter, nullptr);
  2072. }
  2073. void KlattGrid_formula_bandwidths (KlattGrid me, int formantType, conststring32 expression, Interpreter interpreter) {
  2074. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType);
  2075. FormantGrid_formula_bandwidths (fg->get(), expression, interpreter, nullptr);
  2076. }
  2077. void KlattGrid_formula_amplitudes (KlattGrid me, int formantType, conststring32 expression, Interpreter interpreter) {
  2078. try {
  2079. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2080. for (integer irow = 1; irow <= ordered->size; irow ++) {
  2081. IntensityTier amplitudes = ordered->at [irow];
  2082. Formula_compile (interpreter, amplitudes, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
  2083. Formula_Result result;
  2084. for (integer icol = 1; icol <= amplitudes -> points.size; icol ++) {
  2085. Formula_run (irow, icol, & result);
  2086. Melder_require (isdefined (result. numericResult),
  2087. U"Cannot put an undefined value into the tier.\nFormula not finished.");
  2088. amplitudes -> points.at [icol] -> value = result. numericResult;
  2089. }
  2090. }
  2091. } catch (MelderError) {
  2092. Melder_throw (me, U": formula not finished on amplitudes.");
  2093. }
  2094. }
  2095. double KlattGrid_getAmplitudeAtTime (KlattGrid me, int formantType, integer iformant, double t) {
  2096. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2097. if (iformant < 1 || iformant > ordered->size)
  2098. return undefined;
  2099. return RealTier_getValueAtTime (ordered->at [iformant], t);
  2100. }
  2101. void KlattGrid_addAmplitudePoint (KlattGrid me, int formantType, integer iformant, double t, double value) {
  2102. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2103. Melder_require (iformant > 0 && iformant <= ordered -> size, U"Formant amplitude tier ", iformant, U"does not exist.");
  2104. RealTier_addPoint (ordered->at [iformant], t, value);
  2105. }
  2106. void KlattGrid_removeAmplitudePoints (KlattGrid me, int formantType, integer iformant, double t1, double t2) {
  2107. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2108. if (iformant < 1 || iformant > ordered->size)
  2109. return;
  2110. AnyTier_removePointsBetween (ordered->at [iformant]->asAnyTier(), t1, t2);
  2111. }
  2112. autoIntensityTier KlattGrid_extractAmplitudeTier (KlattGrid me, int formantType, integer iformant) {
  2113. try {
  2114. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2115. Melder_require (iformant > 0 && iformant <= ordered -> size,
  2116. U"Formant amplitude tier ", iformant, U"does not exist.");
  2117. autoIntensityTier thee = Data_copy (ordered->at [iformant]);
  2118. return thee;
  2119. } catch (MelderError) {
  2120. Melder_throw (me, U": no IntensityTier extracted.");
  2121. }
  2122. }
  2123. void KlattGrid_replaceAmplitudeTier (KlattGrid me, int formantType, integer iformant, IntensityTier thee) {
  2124. try {
  2125. Melder_require (my xmin == thy xmin && my xmax == thy xmax, U"Domains should be equal.");
  2126. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2127. Melder_require (iformant > 0 && iformant <= ordered -> size,
  2128. U"Formant amplitude tier ", iformant, U" does not exist.");
  2129. autoIntensityTier any = Data_copy (thee);
  2130. ordered -> replaceItem_move (any.move(), iformant);
  2131. } catch (MelderError) {
  2132. Melder_throw (me, U": no ampitude tier replaced.");
  2133. }
  2134. }
  2135. autoFormantGrid KlattGrid_extractFormantGrid (KlattGrid me, int formantType) {
  2136. try {
  2137. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType);
  2138. autoFormantGrid thee = Data_copy (fg->get());
  2139. return thee;
  2140. } catch (MelderError) {
  2141. Melder_throw (me, U": no FormantGrid extracted.");
  2142. }
  2143. }
  2144. void KlattGrid_replaceFormantGrid (KlattGrid me, int formantType, FormantGrid thee) {
  2145. try {
  2146. Melder_require (my xmin == thy xmin && my xmax == thy xmax, U"Domains should be equal");
  2147. autoFormantGrid *fg = KlattGrid_getAddressOfFormantGrid (me, formantType);
  2148. *fg = Data_copy (thee);
  2149. } catch (MelderError) {
  2150. Melder_throw (me, U": no FormantGrid replaced.");
  2151. }
  2152. }
  2153. void KlattGrid_addFormantAmplitudeTier (KlattGrid me, int formantType, integer position) {
  2154. try {
  2155. Melder_require (formantType != KlattGrid_NASAL_ANTIFORMANTS && formantType != KlattGrid_TRACHEAL_ANTIFORMANTS && formantType != KlattGrid_DELTA_FORMANTS,
  2156. U"Cannot add amplitude tier to this formant type.");
  2157. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2158. integer noa = ordered->size;
  2159. if (position > noa || position < 1)
  2160. position = noa + 1;
  2161. autoIntensityTier tier = IntensityTier_create (my xmin, my xmax);
  2162. ordered -> addItemAtPosition_move (tier.move(), position);
  2163. } catch (MelderError) {
  2164. Melder_throw (me, U": no formant amplitude tier added.");
  2165. }
  2166. }
  2167. void KlattGrid_removeFormantAmplitudeTier (KlattGrid me, int formantType, integer position) {
  2168. try {
  2169. Melder_require (formantType != KlattGrid_NASAL_ANTIFORMANTS && formantType != KlattGrid_TRACHEAL_ANTIFORMANTS && formantType != KlattGrid_DELTA_FORMANTS,
  2170. U"Cannot remove amplitude tier from this formant type.");
  2171. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2172. if (position > 0 && position <= ordered->size) {
  2173. ordered -> removeItem (position);
  2174. }
  2175. } catch (MelderError) {
  2176. Melder_throw (me, U": no formant amplitude tier removed.");
  2177. }
  2178. }
  2179. // The following two routines are deprecated.
  2180. // We do this in two separate steps now
  2181. void KlattGrid_addFormant (KlattGrid me, int formantType, integer position) {
  2182. try {
  2183. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType);
  2184. Melder_require (*fg, U"Formant type ", formantType, U" does not exist.");
  2185. integer nof = (*fg) -> formants.size;
  2186. if (position > nof || position < 1) {
  2187. position = nof + 1;
  2188. }
  2189. if (formantType == KlattGrid_NASAL_ANTIFORMANTS || formantType == KlattGrid_TRACHEAL_ANTIFORMANTS ||
  2190. formantType == KlattGrid_DELTA_FORMANTS) {
  2191. FormantGrid_addFormantAndBandwidthTiers (fg->get(), position);
  2192. return;
  2193. }
  2194. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2195. integer noa = ordered->size;
  2196. Melder_require (nof == noa, U"The number of formants (", nof, U") and the number of amplitudes (", noa, U") should be equal.");
  2197. FormantGrid_addFormantAndBandwidthTiers (fg->get(), position);
  2198. try {
  2199. autoIntensityTier tier = IntensityTier_create (my xmin, my xmax);
  2200. ordered -> addItemAtPosition_move (tier.move(), position);
  2201. } catch (MelderError) { // restore original
  2202. FormantGrid_removeFormantAndBandwidthTiers (fg->get(), position);
  2203. }
  2204. } catch (MelderError) {
  2205. Melder_throw (me, U": no formant added.");
  2206. }
  2207. }
  2208. void KlattGrid_removeFormant (KlattGrid me, int formantType, integer position) {
  2209. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType);
  2210. integer nof = (*fg) -> formants.size;
  2211. if (formantType == KlattGrid_NASAL_ANTIFORMANTS || formantType == KlattGrid_TRACHEAL_ANTIFORMANTS ||
  2212. formantType == KlattGrid_DELTA_FORMANTS) {
  2213. if (position < 1 || position > nof) {
  2214. return;
  2215. }
  2216. FormantGrid_removeFormantAndBandwidthTiers (fg->get(), position);
  2217. } else {
  2218. // oral & nasal & tracheal formants can have amplitudes
  2219. // only remove a formant and its amplitude tier if number of formants and amplitudes are the same
  2220. OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
  2221. integer noa = ordered->size;
  2222. if (position < 1 || position > nof || position > noa) {
  2223. if (nof != noa) {
  2224. Melder_warning (U"The number of formant tiers (", nof, U") and the number of amplitude tiers (",
  2225. noa, U") don't match. Nothing removed.");
  2226. }
  2227. return;
  2228. }
  2229. FormantGrid_removeFormantAndBandwidthTiers (fg->get(), position);
  2230. ordered -> removeItem (position);
  2231. }
  2232. }
  2233. void KlattGrid_addFormantFrequencyAndBandwidthTiers (KlattGrid me, int formantType, integer position) {
  2234. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType);
  2235. FormantGrid_addFormantAndBandwidthTiers (fg->get(), position);
  2236. }
  2237. void KlattGrid_removeFormantFrequencyAndBandwidthTiers (KlattGrid me, int formantType, integer position) {
  2238. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, formantType);
  2239. FormantGrid_removeFormantAndBandwidthTiers (fg->get(), position);
  2240. }
  2241. double KlattGrid_getDeltaFormantAtTime (KlattGrid me, integer iformant, double t) {
  2242. return FormantGrid_getFormantAtTime (my coupling -> delta_formants.get(), iformant, t);
  2243. }
  2244. void KlattGrid_addDeltaFormantPoint (KlattGrid me, integer iformant, double t, double value) {
  2245. FormantGrid_addFormantPoint (my coupling -> delta_formants.get(), iformant, t, value);
  2246. }
  2247. void KlattGrid_removeDeltaFormantPoints (KlattGrid me, integer iformant, double t1, double t2) {
  2248. FormantGrid_removeFormantPointsBetween (my coupling -> delta_formants.get(), iformant, t1, t2);
  2249. }
  2250. double KlattGrid_getDeltaBandwidthAtTime (KlattGrid me, integer iformant, double t) {
  2251. return FormantGrid_getBandwidthAtTime (my coupling -> delta_formants.get(), iformant, t);
  2252. }
  2253. void KlattGrid_addDeltaBandwidthPoint (KlattGrid me, integer iformant, double t, double value) {
  2254. FormantGrid_addBandwidthPoint (my coupling -> delta_formants.get(), iformant, t, value);
  2255. }
  2256. void KlattGrid_removeDeltaBandwidthPoints (KlattGrid me, integer iformant, double t1, double t2) {
  2257. FormantGrid_removeBandwidthPointsBetween (my coupling -> delta_formants.get(), iformant, t1, t2);
  2258. }
  2259. autoFormantGrid KlattGrid_extractDeltaFormantGrid (KlattGrid me) {
  2260. try {
  2261. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, KlattGrid_DELTA_FORMANTS);
  2262. autoFormantGrid thee = Data_copy (fg->get());
  2263. return thee;
  2264. } catch (MelderError) {
  2265. Melder_throw (me, U": no delta FormantGrid extracted.");
  2266. }
  2267. }
  2268. void KlattGrid_replaceDeltaFormantGrid (KlattGrid me, FormantGrid thee) {
  2269. try {
  2270. Melder_require (my xmin == thy xmin && my xmax == thy xmax, U"Domains should be equal");
  2271. autoFormantGrid* fg = KlattGrid_getAddressOfFormantGrid (me, KlattGrid_DELTA_FORMANTS);
  2272. autoFormantGrid him = Data_copy (thee);
  2273. *fg = him.move();
  2274. } catch (MelderError) {
  2275. Melder_throw (me, U": no delta FormantGrid replaced.");
  2276. }
  2277. }
  2278. autoFormantGrid KlattGrid_to_oralFormantGrid_openPhases (KlattGrid me, double fadeFraction) {
  2279. try {
  2280. Melder_require (my vocalTract -> oral_formants -> formants.size > 0 || my vocalTract -> oral_formants -> bandwidths.size > 0,
  2281. U"Formant grid should not be empty.");
  2282. if (fadeFraction < 0.0) {
  2283. fadeFraction = 0.0;
  2284. }
  2285. Melder_require (fadeFraction < 0.5, U"Fade fraction should be smaller than 0.5");
  2286. my coupling -> options -> fadeFraction = fadeFraction;
  2287. autoFormantGrid thee = Data_copy ( (FormantGrid) my vocalTract -> oral_formants.get());
  2288. KlattGrid_setGlottisCoupling (me);
  2289. FormantGrid_CouplingGrid_updateOpenPhases (thee.get(), my coupling.get());
  2290. return thee;
  2291. } catch (MelderError) {
  2292. Melder_throw (me, U": no \"open phase\" oral FormantGrid created.");
  2293. }
  2294. }
  2295. autoPointProcess KlattGrid_extractPointProcess_glottalClosures (KlattGrid me) {
  2296. try {
  2297. // Update PhonationTier
  2298. autoPhonationTier pt = PhonationGrid_to_PhonationTier (my phonation.get());
  2299. autoPointProcess thee = PhonationTier_to_PointProcess_closures (pt.get());
  2300. return thee;
  2301. } catch (MelderError) {
  2302. Melder_throw (me, U": no glottal closure points extracted.");
  2303. }
  2304. }
  2305. double KlattGrid_getFricationAmplitudeAtTime (KlattGrid me, double t) {
  2306. return RealTier_getValueAtTime (my frication -> fricationAmplitude.get(), t);
  2307. }
  2308. void KlattGrid_addFricationAmplitudePoint (KlattGrid me, double t, double value) {
  2309. RealTier_addPoint (my frication -> fricationAmplitude.get(), t, value);
  2310. }
  2311. void KlattGrid_removeFricationAmplitudePoints (KlattGrid me, double t1, double t2) {
  2312. AnyTier_removePointsBetween (my frication -> fricationAmplitude.get()->asAnyTier(), t1, t2);
  2313. }
  2314. autoIntensityTier KlattGrid_extractFricationAmplitudeTier (KlattGrid me) {
  2315. return Data_copy (my frication -> fricationAmplitude.get());
  2316. }
  2317. void KlattGrid_replaceFricationAmplitudeTier (KlattGrid me, IntensityTier thee) {
  2318. try {
  2319. Melder_require (my xmin == thy xmin && my xmax == thy xmax, U"Domains should be equal");
  2320. my frication -> fricationAmplitude = Data_copy (thee);
  2321. } catch (MelderError) {
  2322. Melder_throw (me, U": no frication amplitude tier replaced.");
  2323. }
  2324. }
  2325. double KlattGrid_getFricationBypassAtTime (KlattGrid me, double t) {
  2326. return RealTier_getValueAtTime (my frication -> bypass.get(), t);
  2327. }
  2328. void KlattGrid_addFricationBypassPoint (KlattGrid me, double t, double value) {
  2329. RealTier_addPoint (my frication -> bypass.get(), t, value);
  2330. }
  2331. void KlattGrid_removeFricationBypassPoints (KlattGrid me, double t1, double t2) {
  2332. AnyTier_removePointsBetween (my frication -> bypass.get()->asAnyTier(), t1, t2);
  2333. }
  2334. autoIntensityTier KlattGrid_extractFricationBypassTier (KlattGrid me) {
  2335. return Data_copy (my frication -> bypass.get());
  2336. }
  2337. void KlattGrid_replaceFricationBypassTier (KlattGrid me, IntensityTier thee) {
  2338. try {
  2339. Melder_require (my xmin == thy xmin && my xmax == thy xmax, U"Domains should be equal");
  2340. my frication -> bypass = Data_copy (thee);
  2341. } catch (MelderError) {
  2342. Melder_throw (me, U": no frication bypass tier replaced.");
  2343. }
  2344. }
  2345. void KlattGrid_setGlottisCoupling (KlattGrid me) {
  2346. try {
  2347. my coupling -> glottis = PhonationGrid_to_PhonationTier (my phonation.get());
  2348. Melder_require (my coupling -> glottis, U"Phonation tier should not be empty.");
  2349. } catch (MelderError) {
  2350. Melder_throw (me, U": no coupling could be set.");
  2351. }
  2352. }
  2353. #if 0
  2354. static autoSound KlattGrid_to_Sound_aspiration (KlattGrid me, double samplingFrequency) {
  2355. return PhonationGrid_to_Sound_aspiration (my phonation.get(), samplingFrequency);
  2356. }
  2357. #endif
  2358. autoSound KlattGrid_to_Sound_phonation (KlattGrid me) {
  2359. return PhonationGrid_to_Sound (my phonation.get(), 0, my options -> samplingFrequency);
  2360. }
  2361. autoSound KlattGrid_to_Sound (KlattGrid me) {
  2362. try {
  2363. autoSound thee;
  2364. PhonationGridPlayOptions pp = my phonation -> options.get();
  2365. FricationGridPlayOptions pf = my frication -> options.get();
  2366. double samplingFrequency = my options -> samplingFrequency;
  2367. if (pp -> voicing) {
  2368. KlattGrid_setGlottisCoupling (me);
  2369. }
  2370. if (pp -> aspiration || pp -> voicing) { // No vocal tract filtering if no glottal source signal present
  2371. autoSound source = PhonationGrid_to_Sound (my phonation.get(), my coupling.get(), samplingFrequency);
  2372. thee = Sound_VocalTractGrid_CouplingGrid_filter (source.get(), my vocalTract.get(), my coupling.get());
  2373. }
  2374. if (pf -> endFricationFormant > 0 || pf -> bypass) {
  2375. autoSound frication = FricationGrid_to_Sound (my frication.get(), samplingFrequency);
  2376. if (thee) {
  2377. _Sounds_add_inplace (thee.get(), frication.get());
  2378. } else {
  2379. thee = frication.move();
  2380. }
  2381. }
  2382. if (thee) {
  2383. Vector_scale (thee.get(), 0.99);
  2384. } else if (my options -> scalePeak) {
  2385. thee = Sound_createEmptyMono (my xmin, my xmax, samplingFrequency);
  2386. }
  2387. return thee;
  2388. } catch (MelderError) {
  2389. Melder_throw (me, U": no Sound created.");
  2390. }
  2391. }
  2392. void KlattGrid_playSpecial (KlattGrid me) {
  2393. try {
  2394. autoSound thee = KlattGrid_to_Sound (me);
  2395. KlattGridPlayOptions him = my options.get();
  2396. if (his scalePeak) {
  2397. Vector_scale (thee.get(), 0.99);
  2398. }
  2399. if (his xmin == 0.0 && his xmax == 0.0) {
  2400. his xmin = my xmin;
  2401. his xmax = my xmax;
  2402. }
  2403. Sound_playPart (thee.get(), his xmin, his xmax, nullptr, nullptr);
  2404. } catch (MelderError) {
  2405. Melder_throw (me, U": not played.");
  2406. }
  2407. }
  2408. void KlattGrid_play (KlattGrid me) {
  2409. KlattGrid_setDefaultPlayOptions (me);
  2410. KlattGrid_playSpecial (me);
  2411. }
  2412. /************************* Sound(s) & KlattGrid **************************************************/
  2413. autoSound Sound_KlattGrid_filter_frication (Sound me, KlattGrid thee) {
  2414. return Sound_FricationGrid_filter (me, thy frication.get());
  2415. }
  2416. autoSound Sound_KlattGrid_filterByVocalTract (Sound me, KlattGrid thee, int filterModel) {
  2417. try {
  2418. Melder_require (my xmin == thy xmin && my xmax == thy xmax, U"Domains should be equal.");
  2419. KlattGrid_setDefaultPlayOptions (thee);
  2420. thy coupling -> options -> openglottis = 0; // don't trust openglottis info!
  2421. thy vocalTract -> options -> filterModel = filterModel;
  2422. return Sound_VocalTractGrid_CouplingGrid_filter (me, thy vocalTract.get(), thy coupling.get());
  2423. } catch (MelderError) {
  2424. Melder_throw (me, U": not filtered by KlattGrid.");
  2425. }
  2426. }
  2427. /******************* KlattTable to KlattGrid *********************/
  2428. autoKlattGrid KlattTable_to_KlattGrid (KlattTable me, double frameDuration) {
  2429. try {
  2430. Table kt = (Table) me;
  2431. integer numberOfRows = my rows.size;
  2432. double tmin = 0, tmax = numberOfRows * frameDuration;
  2433. double dBNul = -300;
  2434. double dB_offset = -20.0 * log10 (2.0e-5) - 87.0; // in KlattTable maximum in DB_to_LIN is at 87 dB : 32767
  2435. double dB_offset_voicing = 20.0 * log10 (320000 / 32767); // V' [n] in range (-320000,32000)
  2436. double dB_offset_noise = -20.0 * log10 (32.767 / 8.192); // noise in range (-8192,8192)
  2437. // double dB_offset_noise = -20 * log10 (320000/32767) - 20 * log10 (32.767 / 8.192);
  2438. double ap [7] = {0, 0.4, 0.15, 0.06, 0.04, 0.022, 0.03 };
  2439. integer numberOfFormants = 6;
  2440. integer numberOfNasalFormants = 1;
  2441. integer numberOfNasalAntiFormants = numberOfNasalFormants;
  2442. integer numberOfTrachealFormants = 0;
  2443. integer numberOfTrachealAntiFormants = numberOfTrachealFormants;
  2444. integer numberOfFricationFormants = 6;
  2445. integer numberOfDeltaFormants = 1;
  2446. autoKlattGrid thee = KlattGrid_create (tmin, tmax, numberOfFormants, numberOfNasalFormants,
  2447. numberOfNasalAntiFormants, numberOfTrachealFormants, numberOfTrachealAntiFormants,
  2448. numberOfFricationFormants, numberOfDeltaFormants);
  2449. for (integer irow = 1; irow <= numberOfRows; irow ++) {
  2450. double t = (irow - 1) * frameDuration;
  2451. integer icol = 1;
  2452. double val = Table_getNumericValue_Assert (kt, irow, icol) / 10.0; // F0hz10
  2453. double f0 = val;
  2454. RealTier_addPoint (thy phonation -> pitch.get(), t, f0);
  2455. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // AVdb
  2456. // dB values below 13 were put to zero in the DBtoLIN function
  2457. val -= 7.0;
  2458. if (val < 13.0) {
  2459. val = dBNul;
  2460. }
  2461. // RealTier_addPoint (thy source -> voicingAmplitude, t, val);
  2462. for (integer kf = 1; kf <= 6; kf ++) {
  2463. double fk = val = Table_getNumericValue_Assert (kt, irow, ++ icol); // Fhz
  2464. RealTier_addPoint (thy vocalTract -> oral_formants -> formants.at [kf], t, val);
  2465. RealTier_addPoint (thy frication -> frication_formants -> formants.at [kf], t, val); // only amplitudes and bandwidths in frication section
  2466. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // Bhz
  2467. if (val <= 0.0) {
  2468. val = fk / 10.0;
  2469. }
  2470. RealTier_addPoint (thy vocalTract -> oral_formants -> bandwidths.at [kf], t, val);
  2471. }
  2472. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // FNZhz
  2473. RealTier_addPoint (thy vocalTract -> nasal_antiformants -> formants.at [1], t, val);
  2474. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // BNZhz
  2475. RealTier_addPoint (thy vocalTract -> nasal_antiformants -> bandwidths.at [1], t, val);
  2476. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // FNPhz
  2477. RealTier_addPoint (thy vocalTract -> nasal_formants -> formants.at [1], t, val);
  2478. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // BNPhz
  2479. RealTier_addPoint (thy vocalTract -> nasal_formants -> bandwidths.at [1], t, val);
  2480. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // ah
  2481. if (val < 13.0) {
  2482. val = dBNul;
  2483. } else {
  2484. val += 20.0 * log10 (0.05) + dB_offset_noise;
  2485. }
  2486. RealTier_addPoint (thy phonation -> aspirationAmplitude.get(), t, val);
  2487. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // Kopen
  2488. double openPhase = ( f0 > 0.0 ? (val / 16000.0) * f0 : 0.7 );
  2489. RealTier_addPoint (thy phonation -> openPhase.get(), t, openPhase);
  2490. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // Aturb breathinessAmplitude during voicing (max is 8192)
  2491. if (val < 13.0) {
  2492. val = dBNul;
  2493. } else {
  2494. val += 20.0 * log10 (0.1) + dB_offset_noise;
  2495. }
  2496. RealTier_addPoint (thy phonation -> breathinessAmplitude.get(), t, val);
  2497. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // TLTdb
  2498. RealTier_addPoint (thy phonation -> spectralTilt.get(), t, val);
  2499. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // AF
  2500. if (val < 13.0) {
  2501. val = dBNul;
  2502. } else {
  2503. val += 20.0 * log10 (0.25) + dB_offset_noise;
  2504. }
  2505. RealTier_addPoint (thy frication -> fricationAmplitude.get(), t, val);
  2506. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // Kskew ???
  2507. //RealTier_addPoint (, t, val);
  2508. for (integer kf = 1; kf <= 6; kf ++) {
  2509. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // Ap
  2510. if (val < 13.0) {
  2511. val = dBNul;
  2512. } else {
  2513. val += 20.0 * log10 (ap [kf]) + dB_offset;
  2514. }
  2515. RealTier_addPoint (thy vocalTract -> oral_formants_amplitudes.at [kf], t, val);
  2516. RealTier_addPoint (thy frication -> frication_formants_amplitudes.at [kf], t, val);
  2517. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // Bhz
  2518. RealTier_addPoint (thy frication -> frication_formants -> bandwidths.at [kf], t, val);
  2519. }
  2520. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // ANP
  2521. if (val < 13.0) {
  2522. val = dBNul;
  2523. } else {
  2524. val += 20.0 * log10 (0.6) + dB_offset;
  2525. }
  2526. RealTier_addPoint (thy vocalTract -> nasal_formants_amplitudes.at [1], t, val);
  2527. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // AB
  2528. if (val < 13.0) {
  2529. val = dBNul;
  2530. } else {
  2531. val += 20.0 * log10 (0.05) + dB_offset_noise;
  2532. }
  2533. RealTier_addPoint (thy frication -> bypass.get(), t, val);
  2534. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // AVpdb
  2535. RealTier_addPoint (thy phonation -> voicingAmplitude.get(), t, val + dB_offset_voicing);
  2536. val = Table_getNumericValue_Assert (kt, irow, ++ icol); // Gain0
  2537. val -= 3.0;
  2538. if (val <= 0.0) {
  2539. val = 57.0;
  2540. }
  2541. RealTier_addPoint (thy gain.get(), t, val + dB_offset);
  2542. }
  2543. // We don't need the following low-pass: we do not use oversampling !!
  2544. //RealTier_addPoint (thy tracheal_formants -> formants->at [1], 0.5*(tmin+tmax), 0.095*samplingFrequency);
  2545. //RealTier_addPoint (thy tracheal_formants -> bandwidths->at [1], 0.5*(tmin+tmax), 0.063*samplingFrequency);
  2546. return thee;
  2547. } catch (MelderError) {
  2548. Melder_throw (me, U": no KlattGrid created.");
  2549. }
  2550. }
  2551. autoKlattGrid Sound_to_KlattGrid_simple (Sound me, double timeStep, integer maximumNumberOfFormants, double maximumFormantFrequency, double windowLength, double preEmphasisFrequency, double minimumPitch, double maximumPitch, double pitchFloorIntensity, int subtractMean) {
  2552. try {
  2553. integer numberOfFormants = maximumNumberOfFormants;
  2554. integer numberOfNasalFormants = 1;
  2555. integer numberOfNasalAntiFormants = numberOfNasalFormants;
  2556. integer numberOfTrachealFormants = 1;
  2557. integer numberOfTrachealAntiFormants = numberOfTrachealFormants;
  2558. integer numberOfFricationFormants = maximumNumberOfFormants;
  2559. integer numberOfDeltaFormants = 1;
  2560. autoSound sound = Data_copy (me);
  2561. Vector_subtractMean (sound.get());
  2562. autoFormant f = Sound_to_Formant_burg (sound.get(), timeStep, maximumNumberOfFormants,
  2563. maximumFormantFrequency, windowLength, preEmphasisFrequency);
  2564. autoFormantGrid fgrid = Formant_downto_FormantGrid (f.get());
  2565. autoPitch p = Sound_to_Pitch (sound.get(), timeStep, minimumPitch, maximumPitch);
  2566. autoPitchTier ptier = Pitch_to_PitchTier (p.get());
  2567. autoIntensity i = Sound_to_Intensity (sound.get(), pitchFloorIntensity, timeStep, subtractMean);
  2568. autoIntensityTier itier = Intensity_downto_IntensityTier (i.get());
  2569. autoKlattGrid thee = KlattGrid_create (my xmin, my xmax, numberOfFormants, numberOfNasalFormants, numberOfNasalAntiFormants, numberOfTrachealFormants, numberOfTrachealAntiFormants, numberOfFricationFormants, numberOfDeltaFormants);
  2570. KlattGrid_replacePitchTier (thee.get(), ptier.get());
  2571. KlattGrid_replaceFormantGrid (thee.get(), KlattGrid_ORAL_FORMANTS, fgrid.get());
  2572. KlattGrid_replaceVoicingAmplitudeTier (thee.get(), itier.get());
  2573. return thee;
  2574. } catch (MelderError) {
  2575. Melder_throw (me, U": no simple KlattGrid created.");
  2576. }
  2577. }
  2578. /* End of file KlattGrid.cpp */