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.

spectdisplay.cpp 22KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. /***************************************************************************
  2. * Copyright (C) 2005,2006 by Jonathan Duddington *
  3. * [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 2 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 to the *
  17. * Free Software Foundation, Inc., *
  18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  19. ***************************************************************************/
  20. #include "wx/wx.h"
  21. #include "wx/wfstream.h"
  22. #include "wx/filename.h"
  23. #include "wx/datstrm.h"
  24. #include "wx/listimpl.cpp"
  25. #include "wx/numdlg.h"
  26. #include "wx/utils.h"
  27. #include <ctype.h>
  28. #include "main.h"
  29. #include "speech.h"
  30. #include "voice.h"
  31. #include "spect.h"
  32. #include "options.h"
  33. extern MyFrame *frame ;
  34. #define SCROLLUNITS 20
  35. #define N_CANVASLIST 50
  36. static int canvaslistix=0;
  37. static SpectDisplay *canvaslist[N_CANVASLIST];
  38. SpectSeq *clipboard_spect=NULL;
  39. wxMenu *menu_spectdisplay=NULL;
  40. BEGIN_EVENT_TABLE(SpectDisplay, wxScrolledWindow)
  41. EVT_LEFT_DOWN(SpectDisplay::OnMouse)
  42. EVT_RIGHT_DOWN(SpectDisplay::OnMouse)
  43. EVT_KEY_DOWN(SpectDisplay::OnKey)
  44. EVT_MENU(-1, SpectDisplay::OnMenu)
  45. END_EVENT_TABLE()
  46. // Define a constructor for my canvas
  47. SpectDisplay::SpectDisplay(wxWindow *parent, const wxPoint& pos, const wxSize& size, SpectSeq *spect)
  48. : wxScrolledWindow(parent, -1, pos, size,
  49. wxSUNKEN_BORDER | wxNO_FULL_REPAINT_ON_RESIZE)
  50. {
  51. wxString filename;
  52. // SetCursor(wxCursor(wxCURSOR_PENCIL));
  53. SetBackgroundColour(* wxWHITE);
  54. zoom = 2;
  55. zoomx = 0.5;
  56. zoomy = 0.5;
  57. savepath = _T("");
  58. spectseq = spect;
  59. sframe = 0;
  60. pk_num = 1;
  61. SetExtent();
  62. if(canvaslistix < N_CANVASLIST-1)
  63. canvaslist[canvaslistix++] = this;
  64. // WavegenInitPkData(0);
  65. } // end of SpectDisplay::SpectDisplay
  66. SpectDisplay::~SpectDisplay()
  67. {//==========================
  68. // delete this from the canvaslist
  69. int ix;
  70. for(ix=0; ix<canvaslistix; ix++)
  71. {
  72. if(canvaslist[ix] == this)
  73. {
  74. for(ix=ix+1; ix<canvaslistix; ix++)
  75. canvaslist[ix-1] = canvaslist[ix];
  76. canvaslistix--;
  77. break;
  78. }
  79. }
  80. if(currentcanvas==this)
  81. {
  82. if(canvaslistix > 0)
  83. currentcanvas = canvaslist[0];
  84. else
  85. currentcanvas = NULL;
  86. }
  87. }
  88. void SpectDisplay::SetExtent()
  89. {//===========================
  90. SetScrollbars(SCROLLUNITS,SCROLLUNITS,
  91. (int)(FRAME_WIDTH*zoomx/SCROLLUNITS)+1,
  92. (int)(spectseq->numframes*FRAME_HEIGHT*zoomy/SCROLLUNITS)+1);
  93. Refresh();
  94. } // end of SpectDisplay::SetExtent
  95. void SpectDisplay::OnDraw(wxDC& dc)
  96. {//================================
  97. wxRegion region;
  98. dc.SetUserScale(zoomx,zoomy);
  99. int f1 = 0x7fffffff, f2 = -1;
  100. int x1,x2,y1,y2;
  101. int vX,vY,vW,vH; // Dimensions of client area in pixels
  102. wxRegionIterator upd(GetUpdateRegion()); // get the update rect list
  103. while (upd)
  104. {
  105. vX = upd.GetX();
  106. vY = upd.GetY();
  107. vW = upd.GetW();
  108. vH = upd.GetH();
  109. CalcUnscrolledPosition(vX,vY,&x1,&y1);
  110. CalcUnscrolledPosition(vX+vW,vY+vH,&x2,&y2);
  111. // Repaint this rectangle
  112. if(y1 < f1) f1 = int(y1/zoomy);
  113. if(y2 > f2) f2 = int(y2/zoomy);
  114. upd ++ ;
  115. }
  116. if(spectseq != NULL)
  117. spectseq->Draw(dc,f1,f2);
  118. }
  119. void SpectDisplay::OnActivate(int active)
  120. {//======================================
  121. if(active)
  122. {
  123. currentcanvas = this;
  124. SetFocus(); // this doesn't seem to work
  125. if(sframe >= 0)
  126. formantdlg->ShowFrame(spectseq,sframe,pk_num,0xff);
  127. WriteDialogValues();
  128. if(wxGetKeyState(WXK_CONTROL))
  129. {
  130. ReadDialogValues();
  131. spectseq->MakeWave(0,spectseq->numframes-1,voicedlg->pitchenv);
  132. }
  133. }
  134. else
  135. {
  136. ReadDialogValues();
  137. }
  138. }
  139. void SetNumeric(wxTextCtrl *t, int value)
  140. //{=====================================
  141. {
  142. wxString string;
  143. string.Printf(_T("%d"),value);
  144. t->SetValue(string);
  145. }
  146. void SetSpinCtrl(wxSpinCtrl *t, int value)
  147. //{=======================================
  148. {
  149. wxString string;
  150. string.Printf(_T("%d"),value);
  151. t->SetValue(string);
  152. }
  153. int GetNumeric(wxTextCtrl *t)
  154. //{==========================
  155. {
  156. return(atoi(t->GetValue().mb_str(wxConvLocal)));
  157. }
  158. void SpectDisplay::WriteDialogLength()
  159. {//===================================
  160. wxString string;
  161. string.Printf(_T("%d mS"),int(spectseq->GetKeyedLength()+0.5));
  162. formantdlg->t_orig_seq->SetLabel(string);
  163. }
  164. void SpectDisplay::WriteDialogValues()
  165. //{===============================
  166. {
  167. wxString string;
  168. SetSpinCtrl(formantdlg->t_amplitude,spectseq->amplitude);
  169. string.Printf(_T("%d - %d Hz %d mS"),
  170. spectseq->pitch1,spectseq->pitch2,spectseq->duration);
  171. formantdlg->t_pitch->SetLabel(string);
  172. pitchgraph->SetData(128,spectseq->pitchenv.env);
  173. voicedlg->SetFromSpect(spectseq);
  174. WriteDialogLength();
  175. }
  176. void SpectDisplay::ReadDialogValues()
  177. //{==================================
  178. {
  179. spectseq->amplitude = formantdlg->t_amplitude->GetValue();
  180. spectseq->duration = GetNumeric(voicedlg->vd_duration);
  181. voicedlg->ReadParams();
  182. }
  183. void SpectDisplay::RefreshDialogValues(int type)
  184. //{=============================================
  185. {
  186. spectseq->amplitude = formantdlg->t_amplitude->GetValue();
  187. spectseq->frames[sframe]->amp_adjust = formantdlg->t_ampframe->GetValue();
  188. spectseq->frames[sframe]->length_adjust =
  189. formantdlg->t_timeframe->GetValue() - spectseq->GetFrameLength(sframe,0,NULL);
  190. if(type==0)
  191. {
  192. WriteDialogLength();
  193. Refresh();
  194. }
  195. else
  196. RefreshFrame(sframe);
  197. }
  198. void SpectDisplay::RefreshFrame(int frame)
  199. {//=======================================
  200. int frame_x, frame_y;
  201. CalcScrolledPosition(0,int(frame*FRAME_HEIGHT*zoomy),
  202. &frame_x,&frame_y);
  203. RefreshRect(wxRect(0,frame_y,int(1000*zoomx),int(FRAME_HEIGHT*zoomy)));
  204. }
  205. int SpectDisplay::ScrollToFrame(int frame, int centre)
  206. {//===================================================
  207. int scrollx, scrolly;
  208. int x, y;
  209. int scrolled = 0;
  210. GetClientSize(&x,&y);
  211. GetViewStart(&scrollx,&scrolly);
  212. scrolly *= SCROLLUNITS;
  213. if(centre)
  214. {
  215. Scroll(-1, int(((frame+0.5)*FRAME_HEIGHT*zoomy - y/2) /SCROLLUNITS));
  216. return(1);
  217. }
  218. if(scrolly > frame * FRAME_HEIGHT * zoomy)
  219. {
  220. Scroll(-1, int((frame * FRAME_HEIGHT * zoomy) / SCROLLUNITS));
  221. scrolled = 1;
  222. }
  223. else
  224. {
  225. if(((frame+1) * FRAME_HEIGHT * zoomy) > (scrolly + y))
  226. {
  227. Scroll(-1, int(((frame+1)*FRAME_HEIGHT*zoomy - y) /SCROLLUNITS)+1);
  228. scrolled = 1;
  229. }
  230. }
  231. return(scrolled);
  232. } // end of SpectDisplay::ScrollToFrame
  233. void SpectDisplay::SelectFrame(int frame)
  234. {//======================================
  235. sframe = frame;
  236. spectseq->SelectAll(0);
  237. spectseq->frames[frame]->selected = 1;
  238. formantdlg->ShowFrame(spectseq,frame,1,0xff);
  239. ScrollToFrame(frame,1);
  240. Refresh();
  241. SetFocus();
  242. } // end of SpectDisplay::SelectFrame
  243. void SpectDisplay::OnZoom(int command)
  244. {//===============================
  245. static float zoomtab[] = {0.25,0.3536,0.5,0.7071,1,1.14142};
  246. int f1, f2, frame;
  247. int x,y;
  248. int height,width;
  249. GetClientSize(&width,&height);
  250. CalcScrolledPosition(0,0,&x,&y);
  251. // centre on a visible selected frame, or if none keep the centred frame centred
  252. f1 = int(-y/(FRAME_HEIGHT*zoomy));
  253. f2 = int((-y+height)/(FRAME_HEIGHT*zoomy));
  254. for(frame=f1; frame<=f2 && frame<spectseq->numframes; frame++)
  255. {
  256. if(spectseq->frames[frame]->selected) break;
  257. }
  258. if(frame > f2)
  259. frame = int((-y+height/2)/(FRAME_HEIGHT*zoomy)); // keep centred frame
  260. switch(command)
  261. {
  262. case T_ZOOMIN:
  263. if(zoom < 5) zoom++;
  264. break;
  265. case T_ZOOMOUT:
  266. if(zoom > 0) zoom--;
  267. break;
  268. }
  269. zoomx = zoomy = zoomtab[zoom];
  270. SetExtent();
  271. ScrollToFrame(frame,1);
  272. Refresh();
  273. } // end of OnZoom
  274. void SpectDisplay::Save(const wxString &path, int selection)
  275. {//=========================================================
  276. wxString filename;
  277. wxFrame *parent;
  278. wxString msg;
  279. wxString fname = _T("");
  280. wxFileName f;
  281. if(selection)
  282. msg = _T("Save selected frames");
  283. else
  284. {
  285. msg = _T("Save spectrum sequence");
  286. fname = spectseq->name;
  287. }
  288. if(path.empty())
  289. {
  290. filename = wxFileSelector(msg,wxFileName(savepath).GetPath(),fname,_T(""),_T("*"),wxSAVE);
  291. }
  292. else
  293. filename = path;
  294. if(filename.IsEmpty())
  295. return;
  296. wxFileOutputStream stream(filename);
  297. if(stream.Ok() == FALSE)
  298. {
  299. wxLogError(_T("Failed to write '%s'"),filename.c_str());
  300. return;
  301. }
  302. spectseq->Save(stream,selection);
  303. savepath = filename;
  304. if((parent = (wxFrame *)GetParent()) != NULL)
  305. {
  306. f = wxFileName(filename);
  307. parent->SetTitle(f.GetName());
  308. spectseq->name = f.GetName();
  309. }
  310. Refresh(); // Shouldn't need this, but redraw problem
  311. if(path.empty())
  312. {
  313. wxFileName p(filename);
  314. }
  315. } // end of Save
  316. void SpectDisplay::SavePitchenv(PitchEnvelope &pitch)
  317. {//==============================================
  318. // save the pitch envelope
  319. int ix;
  320. wxString filename;
  321. filename = wxFileSelector(_T("(Save pitch envelope"),path_pitches,_T(""),_T(""),_T("*"),wxSAVE);
  322. if(filename.IsEmpty())
  323. return;
  324. wxFileOutputStream stream(filename);
  325. if(stream.Ok() == FALSE)
  326. {
  327. wxLogError(_T("Failed to write '%s'"),filename.c_str());
  328. return;
  329. }
  330. wxDataOutputStream s(stream);
  331. s.Write32(FILEID1_PITCHENV);
  332. s.Write32(FILEID2_PITCHENV);
  333. s.Write16(pitch.pitch1); // Hz
  334. s.Write16(pitch.pitch2); // Hz
  335. for(ix=0; ix<128; ix++)
  336. s.Write8(pitch.env[ix]);
  337. } // end of SpectDisplay::SavePitchenv
  338. // WX_DECLARE_LIST(MyChild,ChildList);
  339. // WX_DEFINE_LIST(ChildList);
  340. void SpectDisplay::PlayChild(int number, PitchEnvelope pitchenv)
  341. {//=========================================================
  342. SpectSeq *seq;
  343. if(number >= canvaslistix) return;
  344. if((seq = canvaslist[number]->spectseq) == NULL)
  345. return;
  346. ReadDialogValues();
  347. seq->MakeWave(0,seq->numframes-1,pitchenv);
  348. } // end of PlayChild
  349. void SpectDisplay::SetKeyframe(SpectFrame *sf, int yes)
  350. {//====================================================
  351. if(sf->keyframe == yes) return; // already done
  352. sf->keyframe = yes;
  353. pitchgraph->Refresh();
  354. WriteDialogLength();
  355. }
  356. void SpectDisplay::OnMenu(wxCommandEvent& event)
  357. {//=============================================
  358. int id;
  359. int code;
  360. wxKeyEvent keyevent;
  361. SpectFrame *sf;
  362. static int key[] = {0x1044,0x3044,0x104e,0x1047,0x105a,0x1051,0x3051,WXK_F1,WXK_F2,0x1049,WXK_F10};
  363. id = event.GetId();
  364. if(id >= 300)
  365. {
  366. sf = spectseq->frames[sframe];
  367. sf->ToggleMarker(id-300);
  368. Refresh();
  369. return;
  370. }
  371. // simulate a KeyEvent that corresponds to this menu entry
  372. code = key[id - 201];
  373. keyevent.m_keyCode = code & 0xfff;
  374. if(code & 0x1000)
  375. keyevent.m_controlDown = TRUE;
  376. else
  377. keyevent.m_controlDown = FALSE;
  378. if(code & 0x2000)
  379. keyevent.m_shiftDown = TRUE;
  380. else
  381. keyevent.m_shiftDown = FALSE;
  382. OnKey(keyevent);
  383. }
  384. void SpectDisplay::OnKey(wxKeyEvent& event)
  385. {//====================================
  386. int key;
  387. int display=0; // 1=change one peak 2=one frame, 3=all
  388. int direction=0;
  389. int x_inc;
  390. int y_inc;
  391. int i;
  392. int field=0xff;
  393. int keyfr;
  394. int control;
  395. int number;
  396. double value;
  397. SpectFrame *sf;
  398. peak_t *pk;
  399. // static short pk_inc1[N_PEAKS] = {2,2,2,5,5,5,5,5,5};
  400. static short pk_inc1[N_PEAKS] = {4,4,4,8,8,8,8,8,8};
  401. static short pk_inc2[N_PEAKS] = {8,8,20,20,20,20,25,25,25};
  402. sf = spectseq->frames[sframe];
  403. pk = &sf->peaks[pk_num];
  404. key = event.GetKeyCode();
  405. control = event.ControlDown();
  406. if(control && isalnum(key)) key |= 0x1000;
  407. if(event.ShiftDown())
  408. {
  409. x_inc = pk_inc1[pk_num];
  410. y_inc = 0x40;
  411. }
  412. else
  413. {
  414. x_inc = pk_inc2[pk_num];
  415. y_inc = 0x100;
  416. }
  417. switch(key)
  418. {
  419. case WXK_NEXT:
  420. if(sframe < spectseq->numframes-1)
  421. {
  422. spectseq->SelectAll(0);
  423. sframe++;
  424. spectseq->frames[sframe]->selected = 1;
  425. display = 3;
  426. }
  427. break;
  428. case WXK_PRIOR:
  429. if(sframe > 0)
  430. {
  431. spectseq->SelectAll(0);
  432. sframe--;
  433. spectseq->frames[sframe]->selected = 1;
  434. display = 3;
  435. }
  436. break;
  437. case 'Z':
  438. if(pk_num > 0)
  439. {
  440. pk_num--;
  441. display = 2;
  442. }
  443. break;
  444. case 'X':
  445. if(pk_num < N_PEAKS-1)
  446. {
  447. pk_num++;
  448. display = 2;
  449. }
  450. break;
  451. case WXK_RIGHT:
  452. pk->pkfreq = pk->pkfreq - (pk->pkfreq % x_inc) + x_inc;
  453. if(pk->pkfreq >= MAX_DISPLAY_FREQ)
  454. pk->pkfreq = MAX_DISPLAY_FREQ;
  455. display = 1;
  456. direction = 1;
  457. field = 1;
  458. break;
  459. case WXK_LEFT:
  460. pk->pkfreq = pk->pkfreq - (pk->pkfreq % x_inc) - x_inc;
  461. if(pk->pkfreq < 50)
  462. pk->pkfreq = 50;
  463. display = 1;
  464. direction = -1;
  465. field = 1;
  466. break;
  467. case WXK_UP:
  468. pk->pkheight = pk->pkheight - (pk->pkheight % y_inc) + y_inc;
  469. if(pk->pkheight >= 0x7fff)
  470. pk->pkheight = 0x7fff;
  471. display = 1;
  472. field = 2;
  473. SetKeyframe(sf,1);
  474. break;
  475. case WXK_DOWN:
  476. pk->pkheight = pk->pkheight - (pk->pkheight % y_inc) - y_inc;
  477. if(pk->pkheight <= 0)
  478. {
  479. pk->pkheight = 0;
  480. keyfr = 0; // but only if all the other peaks are zero
  481. for(i=0; i<N_PEAKS; i++)
  482. {
  483. if(sf->peaks[i].pkheight > 0)
  484. keyfr = 1;
  485. }
  486. SetKeyframe(sf,keyfr);
  487. }
  488. display = 1;
  489. field = 2;
  490. break;
  491. case ',': // width--
  492. if(event.ControlDown())
  493. {
  494. // CTRL, rotate, make right slope steeper
  495. pk->pkright-= 5;
  496. pk->pkwidth += 5;
  497. }
  498. else
  499. {
  500. pk->pkright -= 10;
  501. pk->pkwidth -= 10;
  502. }
  503. field = 4;
  504. display = 1;
  505. break;
  506. case '.': // width++
  507. if(event.ControlDown())
  508. {
  509. // CTRL: rotate, make left slope steeper
  510. pk->pkright += 5;
  511. pk->pkwidth -= 5;
  512. }
  513. else
  514. {
  515. pk->pkright += 10;
  516. pk->pkwidth += 10;
  517. }
  518. field = 4;
  519. display = 1;
  520. break;
  521. case '<': // width--
  522. pk->pkright -= 2;
  523. pk->pkwidth -= 2;
  524. display = 1;
  525. field = 4;
  526. break;
  527. case '>': // width++
  528. pk->pkright += 2;
  529. pk->pkwidth += 2;
  530. display = 1;
  531. field = 4;
  532. break;
  533. case '/': // make left=right
  534. i = pk->pkwidth + pk->pkright;
  535. pk->pkwidth = pk->pkright = i/2;
  536. display = 1;
  537. field = 4;
  538. break;
  539. case 0x1041: // CTRL-A
  540. spectseq->SelectAll(1);
  541. Refresh();
  542. break;
  543. case 0x1042: // CTRL-B
  544. // toggle bass reduction
  545. spectseq->bass_reduction ^= 1;
  546. Refresh();
  547. break;
  548. case 0x1043: // CTRL-C
  549. spectseq->ClipboardCopy();
  550. break;
  551. case 0x1044: // CTRL-D
  552. // copy peaks down from previous/next keyframe
  553. if(event.ShiftDown())
  554. spectseq->CopyDown(sframe,1);
  555. else
  556. spectseq->CopyDown(sframe,-1);
  557. SetKeyframe(sf,1);
  558. display = 2;
  559. break;
  560. case 0x1047: // CTRL-G toggle grid
  561. spectseq->grid ^= 1;
  562. Refresh();
  563. break;
  564. case 0x1049: // CTRL-I interpolate between two frames
  565. spectseq->InterpolateAdjacent();
  566. display = 2;
  567. break;
  568. case 0x104d: // CTRL-M
  569. sf->ToggleMarker(1);
  570. display = 2;
  571. break;
  572. case 0x104e: // CTRL-N
  573. number = wxGetNumberFromUser(_T("Toggle Marker"),_T("Marker"),_T(""),1,0,7);
  574. sf->ToggleMarker(number);
  575. display = 2;
  576. break;
  577. case 0x104f: // CTRL-O
  578. spectseq->ConstructVowel();
  579. break;
  580. case 0x1051: // CTRL-Q
  581. if(event.ShiftDown())
  582. spectseq->InterpolatePeaks(0); // remove interpolation
  583. else
  584. spectseq->InterpolatePeaks(1); // show interpolation
  585. display = 3;
  586. break;
  587. case 0x1052: // CTRL-R
  588. value = sf->GetRms(spectseq->amplitude);
  589. break;
  590. case 0x1053: // CTRL-S
  591. Save(savepath);
  592. break;
  593. case 0x1056: // CTRL-V
  594. if(event.ShiftDown())
  595. {
  596. // insert frames from the clipboard
  597. sframe = spectseq->ClipboardInsert(sframe);
  598. SetExtent();
  599. display = 3;
  600. pitchgraph->Refresh();
  601. break;
  602. }
  603. // overwrite just the peaks
  604. if(clipboard_spect == NULL)
  605. break;
  606. i = 0;
  607. while((i < clipboard_spect->numframes) && ((sframe+i) < spectseq->numframes))
  608. {
  609. spectseq->frames[sframe+i]->CopyPeaks(clipboard_spect->frames[i]);
  610. i++;
  611. }
  612. display = 3;
  613. break;
  614. case 0x1058: // CTRL-X
  615. spectseq->ClipboardCopy();
  616. spectseq->DeleteSelected();
  617. SetExtent();
  618. sframe = 0;
  619. display = 3;
  620. pitchgraph->Refresh();
  621. break;
  622. case 0x105a: // CTRK-Z
  623. sf->ZeroPeaks();
  624. SetKeyframe(sf,0);
  625. display = 2;
  626. break;
  627. case WXK_F10:
  628. sf->ApplyVoiceMods();
  629. display = 2;
  630. break;
  631. case WXK_F2:
  632. // make and play sequence
  633. ReadDialogValues();
  634. spectseq->MakeWave(0,spectseq->numframes-1,voicedlg->pitchenv);
  635. break;
  636. case WXK_F1:
  637. // make and play selected
  638. ReadDialogValues();
  639. sf->MakeWave(0,voicedlg->pitchenv,spectseq->amplitude,spectseq->duration);
  640. break;
  641. case WXK_F3:
  642. // make and play selected
  643. ReadDialogValues();
  644. sf->MakeWave(1,voicedlg->pitchenv,spectseq->amplitude,spectseq->duration);
  645. break;
  646. default:
  647. if(key>='0' && key<='9')
  648. {
  649. i = key-'0';
  650. if(event.ControlDown())
  651. {
  652. if(i==0) i=10;
  653. PlayChild(i-1,voicedlg->pitchenv);
  654. }
  655. else
  656. {
  657. // select peak number
  658. if((pk_num = i) >= N_PEAKS) pk_num = N_PEAKS-1;
  659. }
  660. display=2;
  661. }
  662. event.Skip();
  663. break;
  664. }
  665. if(display)
  666. {
  667. pk_select = pk_num;
  668. sf = spectseq->frames[sframe];
  669. pk = &sf->peaks[pk_num];
  670. if(pk->pkwidth < 50) pk->pkwidth = 50; // min. width
  671. if(pk->pkright < 50) pk->pkright = 50;
  672. // ensure minimum separation between peaks & prevent crossover
  673. if(direction > 0)
  674. {
  675. for(i=pk_num+1; i<N_PEAKS; i++)
  676. {
  677. if(sf->peaks[i].pkfreq < sf->peaks[i-1].pkfreq + 100)
  678. sf->peaks[i].pkfreq = sf->peaks[i-1].pkfreq + 100;
  679. }
  680. }
  681. else
  682. if(direction < 0)
  683. {
  684. for(i=pk_num-1; i>=0; i--)
  685. {
  686. if(sf->peaks[i].pkfreq > sf->peaks[i+1].pkfreq - 100)
  687. sf->peaks[i].pkfreq = sf->peaks[i+1].pkfreq - 100;
  688. }
  689. }
  690. if(display==3)
  691. {
  692. formantdlg->ShowFrame(spectseq,sframe,pk_num,0xff);
  693. Refresh();
  694. }
  695. else
  696. {
  697. // only one frame needs to be redrawn
  698. formantdlg->ShowFrame(spectseq,sframe,pk_num,field);
  699. RefreshFrame(sframe);
  700. }
  701. if(sframe >= 0)
  702. {
  703. if(ScrollToFrame(sframe,0))
  704. Refresh(); // shouldn't need this, but we have redraw problems
  705. }
  706. }
  707. } // end of SpectDisplay::OnKey
  708. void SpectDisplay::OnMouse(wxMouseEvent& event)
  709. {//========================================
  710. int frame;
  711. int ix;
  712. if(event.RightDown())
  713. {
  714. PopupMenu(menu_spectdisplay);
  715. return;
  716. }
  717. wxClientDC dc(this);
  718. PrepareDC(dc);
  719. wxPoint pt(event.GetLogicalPosition(dc));
  720. if(spectseq->numframes==0) return;
  721. frame = (int)(pt.y/(FRAME_HEIGHT*zoomy));
  722. if(!event.ControlDown())
  723. spectseq->SelectAll(0);
  724. if(event.ShiftDown())
  725. {
  726. if(sframe >= 0)
  727. {
  728. if(frame < sframe)
  729. for(ix=frame; ix<=sframe; ix++)
  730. spectseq->frames[ix]->selected =1;
  731. else
  732. for(ix=sframe; ix<=frame && ix<spectseq->numframes; ix++)
  733. spectseq->frames[ix]->selected =1;
  734. Refresh();
  735. }
  736. }
  737. else
  738. {
  739. if(frame < spectseq->numframes)
  740. spectseq->frames[frame]->selected ^= 1;
  741. Refresh();
  742. }
  743. if(frame < spectseq->numframes)
  744. {
  745. if(sframe != frame)
  746. formantdlg->ShowFrame(spectseq,frame,pk_num,0xff);
  747. sframe = frame;
  748. }
  749. } // end of SpectDisplay::OnMouse
  750. void MyFrame::OnNewWindow(wxCommandEvent& event)
  751. {//=============================================
  752. SpectSeq *spectseq;
  753. wxString leaf;
  754. wxString pathload;
  755. if(event.GetId() == MENU_SPECTRUM)
  756. pathload = path_spectload;
  757. else
  758. pathload = path_spectload2;
  759. wxString filename = wxFileSelector(_T("Read spectrum or praat data"),pathload,
  760. _T(""),_T(""),_T("*"),wxOPEN);
  761. if(filename.IsEmpty())
  762. {
  763. return;
  764. }
  765. // create SpectSeq and import data
  766. spectseq = new SpectSeq;
  767. if(spectseq == NULL)
  768. {
  769. wxLogError(_T("Failed to create SpectSeq"));
  770. return;
  771. }
  772. wxFileInputStream stream(filename);
  773. if(stream.Ok() == FALSE)
  774. {
  775. wxLogError(_T("Failed to open '%s'"),filename.c_str());
  776. return;
  777. }
  778. wxFileName path = wxFileName(filename);
  779. leaf = path.GetName();
  780. spectseq->Load(stream);
  781. spectseq->name = leaf;
  782. spectseq->MakePitchenv(spectseq->pitchenv);
  783. if(event.GetId() == MENU_SPECTRUM)
  784. path_spectload = path.GetPath();
  785. else
  786. path_spectload2 = path.GetPath();
  787. // Make another frame, containing a canvas
  788. MyChild *subframe = new MyChild(myframe, _T("Spectrum"),
  789. wxPoint(10, 10), wxSize(300, 300),
  790. wxDEFAULT_FRAME_STYLE | wxMAXIMIZE |
  791. wxNO_FULL_REPAINT_ON_RESIZE);
  792. subframe->SetTitle(leaf);
  793. // Give it a status line
  794. subframe->CreateStatusBar();
  795. int width, height;
  796. subframe->GetClientSize(&width, &height);
  797. SpectDisplay *canvas = new SpectDisplay(subframe, wxPoint(0, 0), wxSize(width, height), spectseq);
  798. canvas->savepath = filename;
  799. currentcanvas = canvas;
  800. // Associate the menu bar with the frame
  801. subframe->SetMenuBar(MakeMenu(1));
  802. subframe->canvas = canvas;
  803. subframe->Show(TRUE);
  804. }
  805. void InitSpectrumDisplay()
  806. {//=======================
  807. wxMenu *menu_markers = new wxMenu;
  808. menu_spectdisplay = new wxMenu;
  809. menu_markers->Append(301,_T("1 Vowel break point"));
  810. menu_markers->Append(302,_T("2 Reduce length changes"));
  811. menu_markers->Append(303,_T("3 Break F0 to F2"));
  812. menu_markers->Append(304,_T("4 Break. All formants"));
  813. menu_markers->Append(305,_T("5 Allow greater rate of formant change"));
  814. menu_markers->Append(306,_T("6 Trill"));
  815. menu_markers->Append(307,_T("7 Defer wav mixing"));
  816. menu_spectdisplay->Append(201,_T("Copy Peaks Down CTRL+D"));
  817. menu_spectdisplay->Append(202,_T("Copy Peaks Up SHIFT+CTRL+D"));
  818. menu_spectdisplay->Append(204,_T("Grid (toggle) CTRL+G"));
  819. menu_spectdisplay->Append(210,_T("Interpolate (percentage) CTRL+I"));
  820. menu_spectdisplay->Append(203,_T("Marker (toggle) CTRL+N"));
  821. menu_spectdisplay->Append(206,_T("Show Interpolation CTRL+Q"));
  822. menu_spectdisplay->Append(207,_T("Hide Interpolation CTRL+SHIFT+Q"));
  823. menu_spectdisplay->Append(205,_T("Zero Peaks CTRL+Z"));
  824. menu_spectdisplay->Append(210,_T("Toggle Marker"),menu_markers);
  825. menu_spectdisplay->Append(211,_T("Apply the formant adjustments from current voice"));
  826. menu_spectdisplay->AppendSeparator();
  827. menu_spectdisplay->Append(208,_T("Play Selected Frame F1"));
  828. menu_spectdisplay->Append(209,_T("Play All F2"));
  829. }