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

formantdlg.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /***************************************************************************
  2. * Copyright (C) 2006 to 2007 by Jonathan Duddington *
  3. * email: [email protected] *
  4. * *
  5. * This program 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 3 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write see: *
  17. * <http://www.gnu.org/licenses/>. *
  18. ***************************************************************************/
  19. // For compilers that support precompilation, includes "wx/wx.h".
  20. #include "wx/wx.h"
  21. #include "wx/mdi.h"
  22. #include "speak_lib.h"
  23. #include "main.h"
  24. #include "speech.h"
  25. #include "phoneme.h"
  26. #include "synthesize.h"
  27. #include "voice.h"
  28. #include "spect.h"
  29. #include "wx/textctrl.h"
  30. #include "wx/checkbox.h"
  31. FormantDlg *formantdlg=NULL;
  32. ByteGraph *pitchgraph=NULL;
  33. BEGIN_EVENT_TABLE(FormantDlg, wxPanel)
  34. EVT_BUTTON(T_ZOOMOUT,FormantDlg::OnCommand)
  35. EVT_BUTTON(T_ZOOMIN,FormantDlg::OnCommand)
  36. EVT_SPINCTRL(-1,FormantDlg::OnSpin)
  37. // EVT_SPINCTRL(T_TIMESEQ,FormantDlg::OnSpin)
  38. // EVT_SPINCTRL(T_AMPFRAME,FormantDlg::OnSpin)
  39. // EVT_SPINCTRL(T_TIMEFRAME,FormantDlg::OnSpin)
  40. END_EVENT_TABLE()
  41. void FormantDlg::OnCommand(wxCommandEvent& event)
  42. {//=============================================
  43. int id;
  44. if(currentcanvas == NULL)
  45. return;
  46. switch(id = event.GetId())
  47. {
  48. case T_ZOOMIN:
  49. case T_ZOOMOUT:
  50. currentcanvas->OnZoom(id);
  51. break;
  52. case T_AMPLITUDE:
  53. currentcanvas->RefreshDialogValues(0);
  54. break;
  55. case T_TIMEFRAME:
  56. case T_AMPFRAME:
  57. currentcanvas->RefreshDialogValues(1);
  58. break;
  59. }
  60. currentcanvas->SetFocus();
  61. }
  62. void FormantDlg::OnSpin(wxSpinEvent& event)
  63. {//=============================================
  64. int id;
  65. if(currentcanvas == NULL)
  66. return;
  67. switch(id = event.GetId())
  68. {
  69. case T_AMPFRAME:
  70. currentcanvas->RefreshDialogValues(1);
  71. break;
  72. default:
  73. currentcanvas->RefreshDialogValues(0);
  74. break;
  75. }
  76. currentcanvas->SetFocus();
  77. }
  78. FormantDlg::FormantDlg(wxWindow *parent) : wxPanel(parent,-1,wxDefaultPosition,wxSize(400,1000))
  79. {//=============================================================================================
  80. int ix;
  81. int y;
  82. int xplace;
  83. int id;
  84. wxString string;
  85. int height;
  86. int width;
  87. int x;
  88. int y2 = 420;
  89. int y3 = 520;
  90. wxClientDisplayRect(&x,&y,&width, &height);
  91. #ifdef PLATFORM_WINDOWS
  92. if(height <= 768)
  93. {
  94. y2 = 410;
  95. y3 = 508;
  96. }
  97. #else
  98. if(height <= 800)
  99. {
  100. y2 = 378;
  101. y3 = 456;
  102. }
  103. #endif
  104. y = 24;
  105. xplace = 28;
  106. id = 201;
  107. new wxStaticText(this,-1,_T("Formants"),wxPoint(4,5));
  108. new wxStaticText(this,-1,_T(" Ht Width (Klatt)"),wxPoint(78,5),wxSize(300,20));
  109. new wxStaticText(this,-1,_T("Bw Ap Bp"),wxPoint(188,29),wxSize(300,20));
  110. for(ix=0; ix < 8; ix++)
  111. {
  112. string.Printf(_T("%d"),ix);
  113. t_labpk[ix] = new wxStaticText(this,id++,string,
  114. wxPoint(xplace-22,y+1+24*ix));
  115. if(ix < 7)
  116. {
  117. t_pkfreq[ix] = new wxTextCtrl(this,id++,_T(""),
  118. wxPoint(xplace,y+24*ix),wxSize(44,20),
  119. wxTE_CENTRE);
  120. }
  121. t_pkheight[ix] = new wxTextCtrl(this,id++,_T(""),
  122. wxPoint(xplace+46,y+24*ix),wxSize(36,20),
  123. wxTE_CENTRE);
  124. if(ix < 6)
  125. {
  126. t_pkwidth[ix] = new wxTextCtrl(this,id++,_T(""),
  127. wxPoint(xplace+84,y+24*ix),wxSize(60,20),
  128. wxTE_CENTRE);
  129. }
  130. if((ix == 0) || (ix > 6)) continue;
  131. if(ix < 4)
  132. {
  133. t_klt_bw[ix] = new wxTextCtrl(this,id++,_T(""),
  134. wxPoint(xplace+150,y+24*ix),wxSize(40,20),
  135. wxTE_CENTRE);
  136. }
  137. t_klt_ap[ix] = new wxTextCtrl(this,id++,_T(""),
  138. wxPoint(xplace+192,y+24*ix),wxSize(36,20),
  139. wxTE_CENTRE);
  140. t_klt_bp[ix] = new wxTextCtrl(this,id++,_T(""),
  141. wxPoint(xplace+230,y+24*ix),wxSize(40,20),
  142. wxTE_CENTRE);
  143. }
  144. y=224;
  145. t_timeframe = new wxSpinCtrl(this,T_TIMEFRAME,_T(""), wxPoint(6,y+0), wxSize(52,24), wxTE_CENTRE,0,500);
  146. t_orig_frame = new wxStaticText(this,-1,_T("mS"),wxPoint(61,y+8));
  147. t_ampframe = new wxSpinCtrl(this,T_AMPFRAME,_T(""), wxPoint(104,y+0), wxSize(52,24), wxTE_CENTRE,0,500);
  148. t_lab[3] = new wxStaticText(this,-1,_T("% amp - Frame"),wxPoint(159,y+8));
  149. y += 40;
  150. s_klatt[KLATT_AV] = new wxSpinCtrl(this,T_AV,_T(""), wxPoint(6,y), wxSize(52,24), wxTE_CENTRE,0,500);
  151. t_klatt[KLATT_AV] = new wxStaticText(this,-1,_T("AV"),wxPoint(61,y+4));
  152. s_klatt[KLATT_FNZ] = new wxSpinCtrl(this,T_FNZ,_T(""), wxPoint(104,y), wxSize(52,24), wxTE_CENTRE,0,500);
  153. t_klatt[KLATT_FNZ] = new wxStaticText(this,-1,_T("FNZ"),wxPoint(159,y+4));
  154. y += 28;
  155. s_klatt[KLATT_Tilt] = new wxSpinCtrl(this,T_TILT,_T(""), wxPoint(6,y), wxSize(52,24), wxTE_CENTRE,0,500);
  156. t_klatt[KLATT_Tilt] = new wxStaticText(this,-1,_T("Tilt"),wxPoint(61,y+4));
  157. s_klatt[KLATT_Aspr] = new wxSpinCtrl(this,T_ASPR,_T(""), wxPoint(104,y), wxSize(52,24), wxTE_CENTRE,0,500);
  158. t_klatt[KLATT_Aspr] = new wxStaticText(this,-1,_T("Aspr"),wxPoint(159,y+4));
  159. s_klatt[KLATT_Skew] = new wxSpinCtrl(this,T_SKEW,_T(""), wxPoint(202,y), wxSize(52,24), wxTE_CENTRE,0,500);
  160. t_klatt[KLATT_Skew] = new wxStaticText(this,-1,_T("Skew"),wxPoint(257,y+4));
  161. y += 28;
  162. s_klatt[KLATT_AVp] = new wxSpinCtrl(this,T_AVP,_T(""), wxPoint(6,y), wxSize(52,24), wxTE_CENTRE,0,500);
  163. t_klatt[KLATT_AVp] = new wxStaticText(this,-1,_T("AVp"),wxPoint(61,y+4));
  164. s_klatt[KLATT_Fric] = new wxSpinCtrl(this,T_FRIC,_T(""), wxPoint(104,y), wxSize(52,24), wxTE_CENTRE,0,500);
  165. t_klatt[KLATT_Fric] = new wxStaticText(this,-1,_T("Fric"),wxPoint(159,y+4));
  166. s_klatt[KLATT_FricBP] = new wxSpinCtrl(this,T_FRICBP,_T(""), wxPoint(202,y), wxSize(52,24), wxTE_CENTRE,0,500);
  167. t_klatt[KLATT_FricBP] = new wxStaticText(this,-1,_T("FricBP"),wxPoint(257,y+4));
  168. y += 28;
  169. s_klatt[KLATT_Kopen] = new wxSpinCtrl(this,T_KOPEN,_T(""), wxPoint(6,y), wxSize(52,24), wxTE_CENTRE,0,500);
  170. t_klatt[KLATT_Kopen] = new wxStaticText(this,-1,_T("kopen"),wxPoint(61,y+4));
  171. s_klatt[KLATT_Turb] = new wxSpinCtrl(this,T_TURB,_T(""), wxPoint(104,y), wxSize(52,24), wxTE_CENTRE,0,500);
  172. t_klatt[KLATT_Turb] = new wxStaticText(this,-1,_T("Turb"),wxPoint(159,y+4));
  173. t_zoomout = new wxButton(this,T_ZOOMOUT,_T("Zoom-"),wxPoint(16,y2));
  174. t_zoomin = new wxButton(this,T_ZOOMIN,_T("Zoom+"),wxPoint(106,y2));
  175. y = y2 + 46;
  176. t_amplitude = new wxSpinCtrl(this,T_AMPLITUDE,_T(""),
  177. wxPoint(6,y),wxSize(52,24),wxTE_CENTRE,0,y+130);
  178. t_lab[2] = new wxStaticText(this,-1,_T("% amp - Sequence"),wxPoint(61,y+4));
  179. // t_timeseq = new wxSpinCtrl(this,T_TIMESEQ,_T(""),
  180. // wxPoint(6,400),wxSize(52,24),wxTE_CENTRE,0,500);
  181. t_orig_seq = new wxStaticText(this,-1,_T("mS"),wxPoint(61,y+30));
  182. t_pitch = new wxStaticText(this,-1,_T(""),wxPoint(4,y3),wxSize(192,24));
  183. pitchgraph = new ByteGraph(this,wxPoint(0,y3+18),wxSize(200,140));
  184. pitchgraph->SetData(128,env_fall);
  185. pitchgraph->ShowSpectrum(1);
  186. pitchgraph->Show();
  187. }
  188. void FormantDlg::GetValues(SpectSeq *spectseq, int frame)
  189. {//======================================================
  190. int ix;
  191. wxString value;
  192. long num;
  193. SpectFrame *sf;
  194. if(spectseq->frames == NULL)
  195. return;
  196. sf = spectseq->frames[frame];
  197. for(ix=0; ix < 8; ix++)
  198. {
  199. if(ix < 7)
  200. {
  201. num = 0;
  202. value = t_pkfreq[ix]->GetValue();
  203. value.ToLong(&num);
  204. sf->peaks[ix].pkfreq = num;
  205. }
  206. num = 0;
  207. value = t_pkheight[ix]->GetValue();
  208. value.ToLong(&num);
  209. sf->peaks[ix].pkheight = num << 6;
  210. if(ix < 6)
  211. {
  212. num = 0;
  213. value = t_pkwidth[ix]->GetValue();
  214. value.ToLong(&num);
  215. sf->peaks[ix].pkwidth = sf->peaks[ix].pkright = num*2;
  216. if((ix < 3) && ((value = value.AfterFirst('/')) != wxEmptyString))
  217. {
  218. num = 0;
  219. value.ToLong(&num);
  220. sf->peaks[ix].pkright = num*2;
  221. }
  222. }
  223. }
  224. for(ix=1; ix < 6; ix++)
  225. {
  226. if(ix < 3)
  227. {
  228. num = 0;
  229. value = t_klt_bw[ix]->GetValue();
  230. value.ToLong(&num);
  231. sf->peaks[ix].klt_bw = num;
  232. }
  233. num = 0;
  234. value = t_klt_ap[ix]->GetValue();
  235. value.ToLong(&num);
  236. sf->peaks[ix].klt_ap = num;
  237. num = 0;
  238. value = t_klt_bp[ix]->GetValue();
  239. value.ToLong(&num);
  240. sf->peaks[ix].klt_bp = num;
  241. }
  242. } // end of FormantDlg::GetValues
  243. void FormantDlg::ShowFrame(SpectSeq *spectseq, int frame, int pk, int field)
  244. {//==============================================================
  245. int ix;
  246. SpectFrame *sf;
  247. wxString value;
  248. int original_mS;
  249. peak_t *peak;
  250. if(spectseq->frames == NULL)
  251. return;
  252. sf = spectseq->frames[frame];
  253. if(field == 0xff)
  254. {
  255. // indicate the selected peak
  256. // t_select_peak[pk]->SetValue(TRUE);
  257. }
  258. for(ix=0; ix < 8; ix++)
  259. {
  260. if(field != 0xff && pk!=ix)
  261. continue;
  262. if(field == 0xff)
  263. {
  264. if(pk==ix)
  265. value.Printf(_T("%d="),ix);
  266. else
  267. value.Printf(_T("%d"),ix);
  268. t_labpk[ix]->SetLabel(value);
  269. }
  270. peak = &(sf->peaks[ix]);
  271. if((field & 1) && (ix < 7))
  272. {
  273. value.Printf(_T("%4d"),sf->peaks[ix].pkfreq);
  274. t_pkfreq[ix]->SetValue(value);
  275. }
  276. if(field & 2)
  277. {
  278. value.Printf(_T("%3d"),sf->peaks[ix].pkheight >> 6);
  279. t_pkheight[ix]->SetValue(value);
  280. }
  281. if((field & 4) && (ix < 6))
  282. {
  283. if(sf->peaks[ix].pkwidth == sf->peaks[ix].pkright)
  284. value.Printf(_T("%3d"),sf->peaks[ix].pkwidth/2);
  285. else
  286. value.Printf(_T("%3d/%3d"),sf->peaks[ix].pkwidth/2, sf->peaks[ix].pkright/2);
  287. t_pkwidth[ix]->SetValue(value);
  288. }
  289. if((ix > 0) && (ix < 7))
  290. {
  291. if((field & 8) && (ix < 4))
  292. {
  293. value.Printf(_T("%3d"),peak->klt_bw);
  294. t_klt_bw[ix]->SetValue(value);
  295. }
  296. if(field & 16)
  297. {
  298. value.Printf(_T("%3d"),peak->klt_ap);
  299. t_klt_ap[ix]->SetValue(value);
  300. }
  301. if(field & 32)
  302. {
  303. value.Printf(_T("%3d"),peak->klt_bp);
  304. t_klt_bp[ix]->SetValue(value);
  305. }
  306. }
  307. }
  308. // find the time until the next keyframe
  309. SetSpinCtrl(t_timeframe,int(spectseq->GetFrameLength(frame,1,&original_mS)+0.5)); // round to nearest integer
  310. value.Printf(_T("%d mS"),original_mS);
  311. t_orig_frame->SetLabel(value);
  312. value.Printf(_T("%3d"),sf->amp_adjust);
  313. t_ampframe->SetValue(value);
  314. for(ix=0; ix<N_KLATTP; ix++)
  315. {
  316. SetSpinCtrl(s_klatt[ix], sf->klatt_param[ix]);
  317. }
  318. } // end of FormantDlg::ShowFrame
  319. BEGIN_EVENT_TABLE(ByteGraph,wxScrolledWindow)
  320. EVT_LEFT_DOWN(ByteGraph::OnMouse)
  321. END_EVENT_TABLE()
  322. static wxBrush BRUSH_FORMANT(wxColour(255,100,50),wxSOLID);
  323. static wxPen PEN_KEYFRAME(wxColour(255,220,100),2,wxSOLID);
  324. static wxPen PEN_KEYFORMANT(wxColour(0,0,0),2,wxSOLID);
  325. ByteGraph::ByteGraph(wxWindow *parent, const wxPoint& pos, const wxSize &size):
  326. wxScrolledWindow(parent,-1,pos,size,wxSUNKEN_BORDER)
  327. {//============================================================
  328. npoints = 0;
  329. show_spectrum = 0;
  330. } // end of ByteGraph::ByteGraph
  331. void ByteGraph::SetData(int nx, unsigned char *data)
  332. {//=================================================
  333. npoints = nx;
  334. graph = data;
  335. Refresh();
  336. } // end of ByteGraph::SetData
  337. void ByteGraph::ShowSpectrum(int yes)
  338. {//==================================
  339. show_spectrum = yes;
  340. }
  341. void ByteGraph::DrawSpectrum(wxDC& dc)
  342. {//===================================
  343. SpectSeq *seq;
  344. SpectFrame *sf;
  345. int ix;
  346. int x, y;
  347. int pk;
  348. double length;
  349. int numframes;
  350. int width, height;
  351. double xscale, yscale;
  352. spectrum_scale = 0;
  353. if(currentcanvas==NULL) return;
  354. if((seq = currentcanvas->spectseq) == NULL) return;
  355. numframes = seq->numframes;
  356. if(numframes == 0) return;
  357. GetClientSize(&width,&height);
  358. if(((length = seq->frames[numframes-1]->time)==0) && (numframes>1))
  359. length = seq->frames[numframes-2]->time;
  360. length = length - seq->frames[0]->time;
  361. yscale = height/3000.0;
  362. spectrum_scale = xscale = width/length;
  363. dc.SetBrush(BRUSH_FORMANT);
  364. dc.SetPen(*wxTRANSPARENT_PEN);
  365. for(ix=0; ix<numframes; ix++)
  366. {
  367. sf = seq->frames[ix];
  368. x = int(sf->time*xscale);
  369. if(sf->keyframe)
  370. {
  371. dc.SetPen(PEN_KEYFRAME);
  372. dc.DrawLine(x,0,x,height);
  373. }
  374. dc.SetPen(*wxTRANSPARENT_PEN);
  375. dc.DrawCircle(x,int(height-(sf->formants[1].freq-200)*yscale),3);
  376. dc.DrawCircle(x,int(height-(sf->formants[2].freq-200)*yscale),3);
  377. dc.DrawCircle(x,int(height-(sf->formants[3].freq-200)*yscale),3);
  378. if(sf->keyframe)
  379. {
  380. dc.SetPen(PEN_KEYFORMANT);
  381. for(pk=1; pk<6; pk++)
  382. {
  383. y = height-int((sf->peaks[pk].pkfreq-200)*yscale);
  384. dc.DrawLine(x-3,y,x+3,y);
  385. }
  386. }
  387. }
  388. }
  389. void ByteGraph::OnDraw(wxDC &dc)
  390. {//============================
  391. int x, y, x2, y2, ix;
  392. int width, height;
  393. double xscale, yscale;
  394. if(show_spectrum) DrawSpectrum(dc);
  395. if(npoints==0) return;
  396. GetClientSize(&width,&height);
  397. xscale = double(width) / npoints;
  398. yscale = double(height) / 256.0;
  399. if(npoints > 8)
  400. {
  401. // draw pitch profile
  402. dc.SetPen(*wxMEDIUM_GREY_PEN);
  403. x = 0;
  404. y = height - int(graph[0]*yscale);
  405. for(ix=1; ix<npoints; ix++)
  406. {
  407. dc.DrawLine(x,y,x2=int(ix*xscale),y2=height - int(graph[ix]*yscale));
  408. x = x2;
  409. y = y2;
  410. }
  411. }
  412. } // end of ByteGraph::OnDraw
  413. void ByteGraph::OnMouse(wxMouseEvent& event)
  414. {//========================================
  415. int ix;
  416. SpectSeq *seq;
  417. double time;
  418. double t0, t1;
  419. double t2=0;
  420. if(currentcanvas==NULL) return;
  421. if((seq = currentcanvas->spectseq) == NULL) return;
  422. wxClientDC dc(this);
  423. PrepareDC(dc);
  424. wxPoint pt(event.GetLogicalPosition(dc));
  425. t0 = t2 = seq->frames[0]->time;
  426. time = (double(pt.x) / spectrum_scale) + t0;
  427. for(ix=1; ix<seq->numframes; ix++)
  428. {
  429. t1=t2;
  430. t2 = seq->frames[ix]->time;
  431. if(time <= t1 + (t2-t1)/2)
  432. {
  433. currentcanvas->SelectFrame(ix-1);
  434. break;
  435. }
  436. }
  437. } // end of ByteGraph::OnMouse