mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-06 23:16:21 +00:00
Indicate language changes in IPA phoneme output. Phoneme definitions FMT(), second parameter is amplitude percentage. Phoneme definitions CALL(), If phoneme type is not defined, copy the static attributes from the called phoneme. Unpronouncable word check: stop when an apostrophe is reached. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@250 d46cf337-b52f-0410-862d-fd96e6ae7743
1079 lines
23 KiB
C++
1079 lines
23 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2005 to 2007 by Jonathan Duddington *
|
|
* email: jonsd@users.sourceforge.net *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 3 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write see: *
|
|
* <http://www.gnu.org/licenses/>. *
|
|
***************************************************************************/
|
|
|
|
|
|
#include "wx/wx.h"
|
|
|
|
#include "wx/wfstream.h"
|
|
#include "wx/filename.h"
|
|
#include "wx/datstrm.h"
|
|
#include "wx/listimpl.cpp"
|
|
#include "wx/numdlg.h"
|
|
#include "wx/utils.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "speak_lib.h"
|
|
#include "speech.h"
|
|
#include "main.h"
|
|
#include "phoneme.h"
|
|
#include "synthesize.h"
|
|
#include "voice.h"
|
|
#include "translate.h"
|
|
#include "spect.h"
|
|
#include "options.h"
|
|
|
|
extern MyFrame *frame ;
|
|
#define SCROLLUNITS 20
|
|
|
|
#define N_CANVASLIST 50
|
|
static int canvaslistix=0;
|
|
static SpectDisplay *canvaslist[N_CANVASLIST];
|
|
SpectSeq *clipboard_spect=NULL;
|
|
wxMenu *menu_spectdisplay=NULL;
|
|
|
|
BEGIN_EVENT_TABLE(SpectDisplay, wxScrolledWindow)
|
|
EVT_LEFT_DOWN(SpectDisplay::OnMouse)
|
|
EVT_RIGHT_DOWN(SpectDisplay::OnMouse)
|
|
EVT_KEY_DOWN(SpectDisplay::OnKey)
|
|
|
|
EVT_MENU(-1, SpectDisplay::OnMenu)
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
// Define a constructor for my canvas
|
|
SpectDisplay::SpectDisplay(wxWindow *parent, const wxPoint& pos, const wxSize& size, SpectSeq *spect)
|
|
: wxScrolledWindow(parent, -1, pos, size,
|
|
wxSUNKEN_BORDER | wxNO_FULL_REPAINT_ON_RESIZE)
|
|
{
|
|
wxString filename;
|
|
|
|
// SetCursor(wxCursor(wxCURSOR_PENCIL));
|
|
SetBackgroundColour(* wxWHITE);
|
|
|
|
zoom = 2;
|
|
zoomx = 0.5;
|
|
zoomy = 0.5;
|
|
|
|
savepath = _T("");
|
|
spectseq = spect;
|
|
sframe = 0;
|
|
pk_num = 1;
|
|
|
|
SetExtent();
|
|
|
|
if(canvaslistix < N_CANVASLIST-1)
|
|
canvaslist[canvaslistix++] = this;
|
|
// WavegenInitPkData(0);
|
|
} // end of SpectDisplay::SpectDisplay
|
|
|
|
|
|
|
|
SpectDisplay::~SpectDisplay()
|
|
{//==========================
|
|
// delete this from the canvaslist
|
|
int ix;
|
|
|
|
for(ix=0; ix<canvaslistix; ix++)
|
|
{
|
|
if(canvaslist[ix] == this)
|
|
{
|
|
for(ix=ix+1; ix<canvaslistix; ix++)
|
|
canvaslist[ix-1] = canvaslist[ix];
|
|
canvaslistix--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(currentcanvas==this)
|
|
{
|
|
if(canvaslistix > 0)
|
|
currentcanvas = canvaslist[0];
|
|
else
|
|
currentcanvas = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void SpectDisplay::SetExtent()
|
|
{//===========================
|
|
SetScrollbars(SCROLLUNITS,SCROLLUNITS,
|
|
(int)(FRAME_WIDTH*zoomx/SCROLLUNITS)+1,
|
|
(int)(spectseq->numframes*FRAME_HEIGHT*zoomy/SCROLLUNITS)+1);
|
|
Refresh();
|
|
} // end of SpectDisplay::SetExtent
|
|
|
|
|
|
void SpectDisplay::OnDraw(wxDC& dc)
|
|
{//================================
|
|
wxRegion region;
|
|
|
|
dc.SetUserScale(zoomx,zoomy);
|
|
|
|
int f1 = 0x7fffffff, f2 = -1;
|
|
int x1,x2,y1,y2;
|
|
int vX,vY,vW,vH; // Dimensions of client area in pixels
|
|
wxRegionIterator upd(GetUpdateRegion()); // get the update rect list
|
|
|
|
while (upd)
|
|
{
|
|
vX = upd.GetX();
|
|
vY = upd.GetY();
|
|
vW = upd.GetW();
|
|
vH = upd.GetH();
|
|
|
|
CalcUnscrolledPosition(vX,vY,&x1,&y1);
|
|
CalcUnscrolledPosition(vX+vW,vY+vH,&x2,&y2);
|
|
// Repaint this rectangle
|
|
|
|
if(y1 < f1) f1 = int(y1/zoomy);
|
|
if(y2 > f2) f2 = int(y2/zoomy);
|
|
|
|
upd ++ ;
|
|
}
|
|
|
|
if(spectseq != NULL)
|
|
spectseq->Draw(dc,f1,f2);
|
|
}
|
|
|
|
|
|
void SpectDisplay::OnActivate(int active)
|
|
{//======================================
|
|
if(active)
|
|
{
|
|
currentcanvas = this;
|
|
SetFocus(); // this doesn't seem to work
|
|
|
|
if(sframe >= 0)
|
|
formantdlg->ShowFrame(spectseq,sframe,pk_num,0xff);
|
|
WriteDialogValues();
|
|
|
|
if(wxGetKeyState(WXK_CONTROL))
|
|
{
|
|
ReadDialogValues();
|
|
spectseq->MakeWave(0,spectseq->numframes-1,voicedlg->pitchenv);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
formantdlg->GetValues(spectseq, sframe);
|
|
ReadDialogValues();
|
|
}
|
|
}
|
|
|
|
|
|
void SetNumeric(wxTextCtrl *t, int value)
|
|
//{=====================================
|
|
{
|
|
wxString string;
|
|
|
|
string.Printf(_T("%d"),value);
|
|
t->SetValue(string);
|
|
}
|
|
|
|
void SetSpinCtrl(wxSpinCtrl *t, int value)
|
|
//{=======================================
|
|
{
|
|
wxString string;
|
|
|
|
string.Printf(_T("%d"),value);
|
|
t->SetValue(string);
|
|
}
|
|
|
|
|
|
|
|
|
|
int GetNumeric(wxTextCtrl *t)
|
|
//{==========================
|
|
{
|
|
return(atoi(t->GetValue().mb_str(wxConvLocal)));
|
|
}
|
|
|
|
|
|
void SpectDisplay::WriteDialogLength()
|
|
{//===================================
|
|
wxString string;
|
|
|
|
string.Printf(_T("%d mS"),int(spectseq->GetKeyedLength()+0.5));
|
|
formantdlg->t_orig_seq->SetLabel(string);
|
|
}
|
|
|
|
|
|
|
|
void SpectDisplay::WriteDialogValues()
|
|
//{===============================
|
|
{
|
|
wxString string;
|
|
|
|
SetSpinCtrl(formantdlg->t_amplitude,spectseq->amplitude);
|
|
|
|
string.Printf(_T("%d - %d Hz %d mS"),
|
|
spectseq->pitch1,spectseq->pitch2,spectseq->duration);
|
|
formantdlg->t_pitch->SetLabel(string);
|
|
|
|
pitchgraph->SetData(128,spectseq->pitchenv.env);
|
|
voicedlg->SetFromSpect(spectseq);
|
|
|
|
WriteDialogLength();
|
|
}
|
|
|
|
|
|
void SpectDisplay::ReadDialogValues()
|
|
//{==================================
|
|
{
|
|
spectseq->amplitude = formantdlg->t_amplitude->GetValue();
|
|
spectseq->duration = GetNumeric(voicedlg->vd_duration);
|
|
voicedlg->ReadParams();
|
|
}
|
|
|
|
|
|
void SpectDisplay::RefreshDialogValues(int type)
|
|
//{=============================================
|
|
{
|
|
int ix;
|
|
long int value;
|
|
SpectFrame *sf;
|
|
|
|
if(spectseq == NULL)
|
|
return;
|
|
|
|
sf = spectseq->frames[sframe];
|
|
|
|
spectseq->amplitude = formantdlg->t_amplitude->GetValue();
|
|
sf->amp_adjust = formantdlg->t_ampframe->GetValue();
|
|
|
|
if(use_spin_controls)
|
|
value = formantdlg->t_timeframe->GetValue();
|
|
else
|
|
formantdlg->tt_timeframe->GetValue().ToLong(&value);
|
|
|
|
sf->length_adjust = value - spectseq->GetFrameLength(sframe,0,NULL);
|
|
|
|
for(ix=0; ix < N_KLATTP; ix++)
|
|
{
|
|
sf->klatt_param[ix] = formantdlg->s_klatt[ix]->GetValue();
|
|
}
|
|
|
|
if(type==0)
|
|
{
|
|
WriteDialogLength();
|
|
Refresh();
|
|
}
|
|
else
|
|
RefreshFrame(sframe); // frame amplitude
|
|
}
|
|
|
|
|
|
void SpectDisplay::RefreshFrame(int frame)
|
|
{//=======================================
|
|
int frame_x, frame_y;
|
|
|
|
CalcScrolledPosition(0,int(frame*FRAME_HEIGHT*zoomy),
|
|
&frame_x,&frame_y);
|
|
|
|
RefreshRect(wxRect(0,frame_y,int(1000*zoomx),int(FRAME_HEIGHT*zoomy)));
|
|
}
|
|
|
|
|
|
|
|
int SpectDisplay::ScrollToFrame(int frame, int centre)
|
|
{//===================================================
|
|
int scrollx, scrolly;
|
|
int x, y;
|
|
int scrolled = 0;
|
|
|
|
GetClientSize(&x,&y);
|
|
GetViewStart(&scrollx,&scrolly);
|
|
scrolly *= SCROLLUNITS;
|
|
|
|
if(centre)
|
|
{
|
|
Scroll(-1, int(((frame+0.5)*FRAME_HEIGHT*zoomy - y/2) /SCROLLUNITS));
|
|
return(1);
|
|
}
|
|
|
|
if(scrolly > frame * FRAME_HEIGHT * zoomy)
|
|
{
|
|
Scroll(-1, int((frame * FRAME_HEIGHT * zoomy) / SCROLLUNITS));
|
|
scrolled = 1;
|
|
}
|
|
else
|
|
{
|
|
if(((frame+1) * FRAME_HEIGHT * zoomy) > (scrolly + y))
|
|
{
|
|
Scroll(-1, int(((frame+1)*FRAME_HEIGHT*zoomy - y) /SCROLLUNITS)+1);
|
|
scrolled = 1;
|
|
}
|
|
}
|
|
return(scrolled);
|
|
} // end of SpectDisplay::ScrollToFrame
|
|
|
|
|
|
void SpectDisplay::SelectFrame(int frame)
|
|
{//======================================
|
|
sframe = frame;
|
|
spectseq->SelectAll(0);
|
|
spectseq->frames[frame]->selected = 1;
|
|
formantdlg->ShowFrame(spectseq,frame,1,0xff);
|
|
ScrollToFrame(frame,1);
|
|
Refresh();
|
|
SetFocus();
|
|
} // end of SpectDisplay::SelectFrame
|
|
|
|
|
|
void SpectDisplay::OnZoom(int command)
|
|
{//===============================
|
|
static float zoomtab[] = {0.25,0.3536,0.5,0.7071,1,1.14142};
|
|
int f1, f2, frame;
|
|
int x,y;
|
|
int height,width;
|
|
|
|
GetClientSize(&width,&height);
|
|
CalcScrolledPosition(0,0,&x,&y);
|
|
|
|
// centre on a visible selected frame, or if none keep the centred frame centred
|
|
f1 = int(-y/(FRAME_HEIGHT*zoomy));
|
|
f2 = int((-y+height)/(FRAME_HEIGHT*zoomy));
|
|
for(frame=f1; frame<=f2 && frame<spectseq->numframes; frame++)
|
|
{
|
|
if(spectseq->frames[frame]->selected) break;
|
|
}
|
|
if(frame > f2)
|
|
frame = int((-y+height/2)/(FRAME_HEIGHT*zoomy)); // keep centred frame
|
|
|
|
switch(command)
|
|
{
|
|
case T_ZOOMIN:
|
|
if(zoom < 5) zoom++;
|
|
break;
|
|
case T_ZOOMOUT:
|
|
if(zoom > 0) zoom--;
|
|
break;
|
|
}
|
|
|
|
zoomx = zoomy = zoomtab[zoom];
|
|
SetExtent();
|
|
ScrollToFrame(frame,1);
|
|
Refresh();
|
|
} // end of OnZoom
|
|
|
|
|
|
|
|
void SpectDisplay::Save(const wxString &path, int selection)
|
|
{//=========================================================
|
|
wxString filename;
|
|
wxFrame *parent;
|
|
wxString msg;
|
|
wxString fname = _T("");
|
|
wxFileName f;
|
|
|
|
if(selection)
|
|
msg = _T("Save selected frames");
|
|
else
|
|
{
|
|
msg = _T("Save spectrum sequence");
|
|
fname = spectseq->name;
|
|
}
|
|
|
|
if(path.empty())
|
|
{
|
|
filename = wxFileSelector(msg,wxFileName(savepath).GetPath(),fname,_T(""),_T("*"),wxSAVE);
|
|
}
|
|
else
|
|
filename = path;
|
|
|
|
if(filename.IsEmpty())
|
|
return;
|
|
|
|
wxFileOutputStream stream(filename);
|
|
|
|
if(stream.Ok() == FALSE)
|
|
{
|
|
wxLogError(_T("Failed to write '%s'"),filename.c_str());
|
|
return;
|
|
}
|
|
spectseq->Save(stream,selection);
|
|
savepath = filename;
|
|
if((parent = (wxFrame *)GetParent()) != NULL)
|
|
{
|
|
f = wxFileName(filename);
|
|
parent->SetTitle(f.GetName());
|
|
spectseq->name = f.GetName();
|
|
}
|
|
Refresh(); // Shouldn't need this, but redraw problem
|
|
|
|
if(path.empty())
|
|
{
|
|
wxFileName p(filename);
|
|
}
|
|
} // end of Save
|
|
|
|
|
|
void SpectDisplay::SavePitchenv(PitchEnvelope &pitch)
|
|
{//==================================================
|
|
// save the pitch envelope
|
|
|
|
int ix;
|
|
FILE *f_env;
|
|
wxString filename;
|
|
char fname[200];
|
|
|
|
filename = wxFileSelector(_T("(Save pitch envelope"),path_pitches,_T(""),_T(""),_T("*"),wxSAVE);
|
|
if(filename.IsEmpty())
|
|
return;
|
|
|
|
strcpy(fname, filename.mb_str(wxConvLocal));
|
|
f_env = fopen(fname,"w");
|
|
if(f_env == NULL)
|
|
{
|
|
wxLogError(_T("Failed to write ")+filename);
|
|
return;
|
|
}
|
|
|
|
for(ix=0; ix<128; ix++)
|
|
{
|
|
fprintf(f_env," 0x%.2x,",pitch.env[ix]);
|
|
if((ix & 0xf) == 0xf)
|
|
fprintf(f_env,"\n");
|
|
}
|
|
fclose(f_env);
|
|
} // end of SpectDisplay::SavePitchenv
|
|
|
|
|
|
// WX_DECLARE_LIST(MyChild,ChildList);
|
|
// WX_DEFINE_LIST(ChildList);
|
|
|
|
|
|
void SpectDisplay::PlayChild(int number, PitchEnvelope pitchenv)
|
|
{//=========================================================
|
|
SpectSeq *seq;
|
|
|
|
|
|
if(number >= canvaslistix) return;
|
|
|
|
if((seq = canvaslist[number]->spectseq) == NULL)
|
|
return;
|
|
|
|
ReadDialogValues();
|
|
seq->MakeWave(0,seq->numframes-1,pitchenv);
|
|
} // end of PlayChild
|
|
|
|
|
|
void SpectDisplay::SetKeyframe(SpectFrame *sf, int yes)
|
|
{//====================================================
|
|
if(sf->keyframe == yes) return; // already done
|
|
|
|
sf->keyframe = yes;
|
|
pitchgraph->Refresh();
|
|
|
|
WriteDialogLength();
|
|
}
|
|
|
|
|
|
|
|
void SpectDisplay::OnMenu(wxCommandEvent& event)
|
|
{//=============================================
|
|
int id;
|
|
int code;
|
|
wxKeyEvent keyevent;
|
|
SpectFrame *sf;
|
|
static int key[] = {0x1044,0x3044,0x104e,0x1047,0x105a,0x1051,0x3051,WXK_F1,WXK_F2,0x1049,WXK_F10,0x104b};
|
|
|
|
id = event.GetId();
|
|
|
|
if(id >= 300)
|
|
{
|
|
sf = spectseq->frames[sframe];
|
|
sf->ToggleMarker(id-300);
|
|
Refresh();
|
|
return;
|
|
}
|
|
|
|
// simulate a KeyEvent that corresponds to this menu entry
|
|
code = key[id - 201];
|
|
keyevent.m_keyCode = code & 0xfff;
|
|
if(code & 0x1000)
|
|
keyevent.m_controlDown = TRUE;
|
|
else
|
|
keyevent.m_controlDown = FALSE;
|
|
if(code & 0x2000)
|
|
keyevent.m_shiftDown = TRUE;
|
|
else
|
|
keyevent.m_shiftDown = FALSE;
|
|
OnKey(keyevent);
|
|
}
|
|
|
|
|
|
|
|
void SpectDisplay::OnKey(wxKeyEvent& event)
|
|
{//====================================
|
|
int key;
|
|
int display=0; // 1=change one peak 2=one frame, 3=all
|
|
int direction=0;
|
|
int x_inc;
|
|
int y_inc;
|
|
int i;
|
|
int field=0xff;
|
|
int keyfr;
|
|
int control;
|
|
int number;
|
|
double value;
|
|
SpectFrame *sf;
|
|
peak_t *pk;
|
|
// static short pk_inc1[N_PEAKS] = {2,2,2,5,5,5,5,5,5};
|
|
static short pk_inc1[N_PEAKS] = {4,4,4,8,8,8,8,8,8};
|
|
static short pk_inc2[N_PEAKS] = {8,8,20,20,20,20,25,25,25};
|
|
|
|
sf = spectseq->frames[sframe];
|
|
pk = &sf->peaks[pk_num];
|
|
key = event.GetKeyCode();
|
|
control = event.ControlDown();
|
|
if(control && isalnum(key)) key |= 0x1000;
|
|
|
|
if(event.ShiftDown())
|
|
{
|
|
x_inc = pk_inc1[pk_num];
|
|
y_inc = 0x40;
|
|
}
|
|
else
|
|
{
|
|
x_inc = pk_inc2[pk_num];
|
|
y_inc = 0x100;
|
|
}
|
|
|
|
switch(key)
|
|
{
|
|
case WXK_NEXT:
|
|
if(sframe < spectseq->numframes-1)
|
|
{
|
|
formantdlg->GetValues(spectseq, sframe);
|
|
spectseq->SelectAll(0);
|
|
sframe++;
|
|
spectseq->frames[sframe]->selected = 1;
|
|
display = 3;
|
|
}
|
|
break;
|
|
|
|
case WXK_PRIOR:
|
|
if(sframe > 0)
|
|
{
|
|
formantdlg->GetValues(spectseq, sframe);
|
|
spectseq->SelectAll(0);
|
|
sframe--;
|
|
spectseq->frames[sframe]->selected = 1;
|
|
display = 3;
|
|
}
|
|
break;
|
|
|
|
|
|
case 'Z':
|
|
if(pk_num > 0)
|
|
{
|
|
pk_num--;
|
|
display = 2;
|
|
}
|
|
break;
|
|
|
|
case 'X':
|
|
if(pk_num < N_PEAKS-1)
|
|
{
|
|
pk_num++;
|
|
display = 2;
|
|
}
|
|
break;
|
|
|
|
case WXK_RIGHT:
|
|
pk->pkfreq = pk->pkfreq - (pk->pkfreq % x_inc) + x_inc;
|
|
if(pk->pkfreq >= MAX_DISPLAY_FREQ)
|
|
pk->pkfreq = MAX_DISPLAY_FREQ;
|
|
display = 1;
|
|
direction = 1;
|
|
field = 1;
|
|
break;
|
|
|
|
case WXK_LEFT:
|
|
pk->pkfreq = pk->pkfreq - (pk->pkfreq % x_inc) - x_inc;
|
|
if(pk->pkfreq < 50)
|
|
pk->pkfreq = 50;
|
|
display = 1;
|
|
direction = -1;
|
|
field = 1;
|
|
break;
|
|
|
|
case WXK_UP:
|
|
pk->pkheight = pk->pkheight - (pk->pkheight % y_inc) + y_inc;
|
|
if(pk->pkheight >= 0x7fff)
|
|
pk->pkheight = 0x7fff;
|
|
display = 1;
|
|
field = 2;
|
|
SetKeyframe(sf,1);
|
|
break;
|
|
|
|
case WXK_DOWN:
|
|
pk->pkheight = pk->pkheight - (pk->pkheight % y_inc) - y_inc;
|
|
if(pk->pkheight <= 0)
|
|
{
|
|
pk->pkheight = 0;
|
|
keyfr = 0; // but only if all the other peaks are zero
|
|
for(i=0; i<N_PEAKS; i++)
|
|
{
|
|
if(sf->peaks[i].pkheight > 0)
|
|
keyfr = 1;
|
|
}
|
|
SetKeyframe(sf,keyfr);
|
|
}
|
|
|
|
display = 1;
|
|
field = 2;
|
|
break;
|
|
|
|
case ',': // width--
|
|
if(event.ControlDown())
|
|
{
|
|
// CTRL, rotate, make right slope steeper
|
|
if(pk_num < 3)
|
|
{
|
|
pk->pkright-= 5;
|
|
pk->pkwidth += 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pk->pkright -= 10;
|
|
pk->pkwidth -= 10;
|
|
if(pk->pkright < 0)
|
|
pk->pkright = 0;
|
|
if(pk->pkwidth < 0)
|
|
pk->pkwidth = 0;
|
|
}
|
|
field = 4;
|
|
display = 1;
|
|
break;
|
|
|
|
case '.': // width++
|
|
if(event.ControlDown())
|
|
{
|
|
// CTRL: rotate, make left slope steeper
|
|
if(pk_num < 3)
|
|
{
|
|
pk->pkright += 5;
|
|
pk->pkwidth -= 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pk->pkright += 10;
|
|
pk->pkwidth += 10;
|
|
}
|
|
field = 4;
|
|
display = 1;
|
|
break;
|
|
|
|
case '<': // width--
|
|
pk->pkright -= 2;
|
|
pk->pkwidth -= 2;
|
|
if(pk->pkwidth < 0)
|
|
pk->pkwidth = 0;
|
|
display = 1;
|
|
field = 4;
|
|
break;
|
|
|
|
case '>': // width++
|
|
pk->pkright += 2;
|
|
pk->pkwidth += 2;
|
|
display = 1;
|
|
field = 4;
|
|
break;
|
|
|
|
case '[': // width--
|
|
pk->pkright -= 1;
|
|
if(pk->pkright < 0)
|
|
pk->pkright = 0;
|
|
display = 1;
|
|
field = 4;
|
|
break;
|
|
|
|
case ']': // width++
|
|
pk->pkright += 1;
|
|
display = 1;
|
|
field = 4;
|
|
break;
|
|
|
|
case '/': // make left=right
|
|
i = pk->pkwidth + pk->pkright;
|
|
pk->pkwidth = pk->pkright = i/2;
|
|
display = 1;
|
|
field = 4;
|
|
break;
|
|
|
|
case 0x1041: // CTRL-A
|
|
spectseq->SelectAll(1);
|
|
Refresh();
|
|
break;
|
|
|
|
case 0x1042: // CTRL-B
|
|
// toggle bass reduction
|
|
spectseq->bass_reduction ^= 1;
|
|
Refresh();
|
|
break;
|
|
|
|
case 0x1043: // CTRL-C
|
|
spectseq->ClipboardCopy();
|
|
break;
|
|
|
|
case 0x1044: // CTRL-D
|
|
// copy peaks down from previous/next keyframe
|
|
if(event.ShiftDown())
|
|
spectseq->CopyDown(sframe,1);
|
|
else
|
|
spectseq->CopyDown(sframe,-1);
|
|
SetKeyframe(sf,1);
|
|
display = 2;
|
|
break;
|
|
|
|
case 0x1047: // CTRL-G toggle grid
|
|
spectseq->grid ^= 1;
|
|
Refresh();
|
|
break;
|
|
|
|
case 0x1049: // CTRL-I interpolate between two frames
|
|
spectseq->InterpolateAdjacent();
|
|
display = 2;
|
|
break;
|
|
|
|
case 0x104b: // CTRL-K
|
|
// spectseq->SetKlattDefaults();
|
|
// display = 3;
|
|
break;
|
|
|
|
case 0x104d: // CTRL-M
|
|
sf->ToggleMarker(1);
|
|
display = 2;
|
|
break;
|
|
|
|
case 0x104e: // CTRL-N
|
|
number = wxGetNumberFromUser(_T("Toggle Marker"),_T("Marker"),_T(""),1,0,7);
|
|
sf->ToggleMarker(number);
|
|
display = 2;
|
|
break;
|
|
|
|
case 0x104f: // CTRL-O
|
|
spectseq->ConstructVowel();
|
|
break;
|
|
|
|
case 0x1051: // CTRL-Q
|
|
if(event.ShiftDown())
|
|
spectseq->InterpolatePeaks(0); // remove interpolation
|
|
else
|
|
spectseq->InterpolatePeaks(1); // show interpolation
|
|
display = 3;
|
|
break;
|
|
|
|
case 0x1052: // CTRL-R
|
|
value = sf->GetRms(spectseq->amplitude);
|
|
break;
|
|
|
|
case 0x1053: // CTRL-S
|
|
Save(savepath);
|
|
break;
|
|
|
|
case 0x1056: // CTRL-V
|
|
if(event.ShiftDown())
|
|
{
|
|
// insert frames from the clipboard
|
|
sframe = spectseq->ClipboardInsert(sframe);
|
|
SetExtent();
|
|
display = 3;
|
|
pitchgraph->Refresh();
|
|
break;
|
|
}
|
|
|
|
// overwrite just the peaks
|
|
if(clipboard_spect == NULL)
|
|
break;
|
|
i = 0;
|
|
while((i < clipboard_spect->numframes) && ((sframe+i) < spectseq->numframes))
|
|
{
|
|
spectseq->frames[sframe+i]->CopyPeaks(clipboard_spect->frames[i]);
|
|
i++;
|
|
}
|
|
display = 3;
|
|
break;
|
|
|
|
case 0x1058: // CTRL-X
|
|
spectseq->ClipboardCopy();
|
|
spectseq->DeleteSelected();
|
|
SetExtent();
|
|
sframe = 0;
|
|
display = 3;
|
|
pitchgraph->Refresh();
|
|
break;
|
|
|
|
case 0x105a: // CTRK-Z
|
|
sf->ZeroPeaks();
|
|
SetKeyframe(sf,0);
|
|
display = 2;
|
|
break;
|
|
|
|
case WXK_F10:
|
|
sf->ApplyVoiceMods();
|
|
display = 2;
|
|
break;
|
|
|
|
case WXK_F2:
|
|
// make and play sequence
|
|
ReadDialogValues();
|
|
spectseq->MakeWave(0,spectseq->numframes-1,voicedlg->pitchenv);
|
|
break;
|
|
|
|
case WXK_F1:
|
|
// make and play selected
|
|
ReadDialogValues();
|
|
sf->MakeWaveF(0,voicedlg->pitchenv,spectseq->amplitude,spectseq->duration);
|
|
break;
|
|
case WXK_F3:
|
|
// make and play selected
|
|
ReadDialogValues();
|
|
sf->MakeWaveF(1,voicedlg->pitchenv,spectseq->amplitude,spectseq->duration);
|
|
break;
|
|
|
|
default:
|
|
if(key>='0' && key<='9')
|
|
{
|
|
i = key-'0';
|
|
if(event.ControlDown())
|
|
{
|
|
if(i==0) i=10;
|
|
PlayChild(i-1,voicedlg->pitchenv);
|
|
}
|
|
else
|
|
{
|
|
// select peak number
|
|
if((pk_num = i) >= N_PEAKS) pk_num = N_PEAKS-1;
|
|
}
|
|
display=2;
|
|
}
|
|
event.Skip();
|
|
break;
|
|
}
|
|
|
|
if(display)
|
|
{
|
|
pk_select = pk_num;
|
|
sf = spectseq->frames[sframe];
|
|
pk = &sf->peaks[pk_num];
|
|
|
|
if(pk->pkwidth < 50) pk->pkwidth = 50; // min. width
|
|
if(pk->pkright < 50) pk->pkright = 50;
|
|
|
|
// ensure minimum separation between peaks & prevent crossover
|
|
if(direction > 0)
|
|
{
|
|
for(i=pk_num+1; i<N_PEAKS; i++)
|
|
{
|
|
if(sf->peaks[i].pkfreq < sf->peaks[i-1].pkfreq + 100)
|
|
sf->peaks[i].pkfreq = sf->peaks[i-1].pkfreq + 100;
|
|
}
|
|
}
|
|
else
|
|
if(direction < 0)
|
|
{
|
|
for(i=pk_num-1; i>=0; i--)
|
|
{
|
|
if(sf->peaks[i].pkfreq > sf->peaks[i+1].pkfreq - 100)
|
|
sf->peaks[i].pkfreq = sf->peaks[i+1].pkfreq - 100;
|
|
}
|
|
}
|
|
|
|
if(display==3)
|
|
{
|
|
formantdlg->ShowFrame(spectseq,sframe,pk_num,0xff);
|
|
Refresh();
|
|
}
|
|
else
|
|
{
|
|
// only one frame needs to be redrawn
|
|
formantdlg->ShowFrame(spectseq,sframe,pk_num,field);
|
|
RefreshFrame(sframe);
|
|
}
|
|
|
|
if(sframe >= 0)
|
|
{
|
|
if(ScrollToFrame(sframe,0))
|
|
Refresh(); // shouldn't need this, but we have redraw problems
|
|
}
|
|
|
|
}
|
|
} // end of SpectDisplay::OnKey
|
|
|
|
|
|
void SpectDisplay::OnMouse(wxMouseEvent& event)
|
|
{//========================================
|
|
int frame;
|
|
int ix;
|
|
|
|
if(event.RightDown())
|
|
{
|
|
PopupMenu(menu_spectdisplay);
|
|
return;
|
|
}
|
|
|
|
wxClientDC dc(this);
|
|
PrepareDC(dc);
|
|
|
|
wxPoint pt(event.GetLogicalPosition(dc));
|
|
|
|
if(spectseq->numframes==0) return;
|
|
|
|
frame = (int)(pt.y/(FRAME_HEIGHT*zoomy));
|
|
|
|
if(!event.ControlDown())
|
|
spectseq->SelectAll(0);
|
|
|
|
if(event.ShiftDown())
|
|
{
|
|
if(sframe >= 0)
|
|
{
|
|
if(frame < sframe)
|
|
for(ix=frame; ix<=sframe; ix++)
|
|
spectseq->frames[ix]->selected =1;
|
|
else
|
|
for(ix=sframe; ix<=frame && ix<spectseq->numframes; ix++)
|
|
spectseq->frames[ix]->selected =1;
|
|
Refresh();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(frame < spectseq->numframes)
|
|
spectseq->frames[frame]->selected ^= 1;
|
|
Refresh();
|
|
}
|
|
|
|
if(frame < spectseq->numframes)
|
|
{
|
|
formantdlg->GetValues(spectseq,sframe);
|
|
if(sframe != frame)
|
|
formantdlg->ShowFrame(spectseq,frame,pk_num,0xff);
|
|
|
|
sframe = frame;
|
|
}
|
|
} // end of SpectDisplay::OnMouse
|
|
|
|
|
|
void MyFrame::OnNewWindow(wxCommandEvent& event)
|
|
{//=============================================
|
|
SpectSeq *spectseq;
|
|
wxString leaf;
|
|
wxString pathload;
|
|
int width, height;
|
|
|
|
if(event.GetId() == MENU_SPECTRUM)
|
|
pathload = path_spectload;
|
|
else
|
|
pathload = path_spectload2;
|
|
|
|
wxString filename = wxFileSelector(_T("Read spectrum or praat data"),pathload,
|
|
_T(""),_T(""),_T("*"),wxOPEN);
|
|
if(filename.IsEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// create SpectSeq and import data
|
|
spectseq = new SpectSeq;
|
|
if(spectseq == NULL)
|
|
{
|
|
wxLogError(_T("Failed to create SpectSeq"));
|
|
return;
|
|
}
|
|
|
|
wxFileInputStream stream(filename);
|
|
if(stream.Ok() == FALSE)
|
|
{
|
|
wxLogError(_T("Failed to open '%s'"),filename.c_str());
|
|
return;
|
|
}
|
|
wxFileName path = wxFileName(filename);
|
|
leaf = path.GetName();
|
|
|
|
setlocale(LC_NUMERIC,"C"); // read numbers in the form 1.23456
|
|
spectseq->Load(stream);
|
|
spectseq->name = leaf;
|
|
spectseq->MakePitchenv(spectseq->pitchenv,0,spectseq->numframes-1);
|
|
|
|
if(event.GetId() == MENU_SPECTRUM)
|
|
path_spectload = path.GetPath();
|
|
else
|
|
path_spectload2 = path.GetPath();
|
|
|
|
// Make another frame, containing a canvas
|
|
GetClientSize(&width, &height);
|
|
MyChild *subframe = new MyChild(myframe, _T("Spectrum"),
|
|
wxPoint(10, 0), wxSize(500, height),
|
|
wxDEFAULT_FRAME_STYLE |
|
|
wxNO_FULL_REPAINT_ON_RESIZE);
|
|
|
|
subframe->SetTitle(leaf);
|
|
|
|
// Give it a status line
|
|
subframe->CreateStatusBar();
|
|
|
|
subframe->GetClientSize(&width, &height);
|
|
SpectDisplay *canvas = new SpectDisplay(subframe, wxPoint(0, 0), wxSize(width, height), spectseq);
|
|
canvas->savepath = filename;
|
|
currentcanvas = canvas;
|
|
|
|
// Associate the menu bar with the frame
|
|
subframe->SetMenuBar(MakeMenu(1,translator->dictionary_name));
|
|
subframe->canvas = canvas;
|
|
subframe->Show(TRUE);
|
|
|
|
}
|
|
|
|
void InitSpectrumDisplay()
|
|
{//=======================
|
|
wxMenu *menu_markers = new wxMenu;
|
|
menu_spectdisplay = new wxMenu;
|
|
|
|
menu_markers->Append(301,_T("1 Vowel break point"));
|
|
menu_markers->Append(302,_T("2 Reduce length changes"));
|
|
menu_markers->Append(303,_T("3 Break F0 to F2"));
|
|
menu_markers->Append(304,_T("4 Break. All formants"));
|
|
menu_markers->Append(305,_T("5 Allow greater rate of formant change"));
|
|
menu_markers->Append(306,_T("6 Trill"));
|
|
menu_markers->Append(307,_T("7 Defer wav mixing"));
|
|
|
|
menu_spectdisplay->Append(201,_T("Copy Peaks Down CTRL+D"));
|
|
menu_spectdisplay->Append(202,_T("Copy Peaks Up SHIFT+CTRL+D"));
|
|
menu_spectdisplay->Append(204,_T("Grid (toggle) CTRL+G"));
|
|
menu_spectdisplay->Append(210,_T("Interpolate (percentage) CTRL+I"));
|
|
menu_spectdisplay->Append(212,_T("Convert sequence to Klatt format CTRL+K"));
|
|
menu_spectdisplay->Append(203,_T("Marker (toggle) CTRL+N"));
|
|
menu_spectdisplay->Append(206,_T("Show Interpolation CTRL+Q"));
|
|
menu_spectdisplay->Append(207,_T("Hide Interpolation CTRL+SHIFT+Q"));
|
|
menu_spectdisplay->Append(205,_T("Zero Peaks CTRL+Z"));
|
|
menu_spectdisplay->Append(210,_T("Toggle Marker"),menu_markers);
|
|
menu_spectdisplay->Append(211,_T("Apply the formant adjustments from a voice file"));
|
|
menu_spectdisplay->AppendSeparator();
|
|
menu_spectdisplay->Append(208,_T("Play Selected Frame F1"));
|
|
menu_spectdisplay->Append(209,_T("Play All F2"));
|
|
|
|
}
|