rhubarb-lip-sync/lib/flite-1.4/wince/flowm_main.c

684 lines
22 KiB
C

/*************************************************************************/
/* */
/* Language Technologies Institute */
/* Carnegie Mellon University */
/* Copyright (c) 2008-2009 */
/* All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to use and distribute */
/* this software and its documentation without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of this work, and to */
/* permit persons to whom this work is furnished to do so, subject to */
/* the following conditions: */
/* 1. The code must retain the above copyright notice, this list of */
/* conditions and the following disclaimer. */
/* 2. Any modifications must be clearly marked as such. */
/* 3. Original authors' names are not deleted. */
/* 4. The authors' names are not used to endorse or promote products */
/* derived from this software without specific prior written */
/* permission. */
/* */
/* CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK */
/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
/* SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE */
/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
/* THIS SOFTWARE. */
/* */
/*************************************************************************/
/* Author: Alan W Black (awb@cs.cmu.edu) */
/* Date: January 2009 */
/*************************************************************************/
/* */
/* Flowm: Flite on Windows Mobile (pronounced flume) */
/* 0.5 */
/* */
/* A simple file reader */
/* */
/* Thanks to Programming Microsoft Windows CE by Douglas Boling which */
/* taught me a lot about how to program in WinCE */
/* */
/*************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <aygshell.h>
/* Apparently from pwingdi.h -- but I don't have that .h file */
/* For DisplayOff */
#define SETPOWERMANAGEMENT 6147
#define VideoPowerOff 4
typedef struct _VIDEO_POWER_MANAGEMENT {
ULONG Length;
ULONG DPMSVersion;
ULONG PowerState;
} VIDEO_POWER_MANAGEMENT;
#include "flowm.h"
#define AppName L"Flown"
HINSTANCE hInst;
int flowm_play_status = FLOWM_STOP;
TCHAR fl_filename[257];
int flowm_file_pos = 0;
int flowm_file_size = 0;
/* To hold position of previous utterances for backskipping */
int flowm_utt_pos_pos=0;
int flowm_prev_utt_pos[FLOWM_NUM_UTT_POS];
int flowm_selected_voice = 0;
int flowm_selected_relation = 0;
float flowm_duration = 0.0;
#define FL_BENCH_TEXT L"A whole joy was reaping, but they've gone south, you should fetch azure mike."
HWND hmbar = 0;
HWND TTSWindow = 0;
TCHAR fl_tts_msg[FL_MAX_MSG_CHARS];
TCHAR fl_fp_msg[FL_MAX_MSG_CHARS];
SHACTIVATEINFO sai;
HANDLE tts_thread = INVALID_HANDLE_VALUE;
const MsgDispatch MainDispatchers[] =
{
{ WM_CREATE, DoCreateMain },
{ WM_SIZE, DoSizeMain },
{ WM_COMMAND, DoCommandMain },
{ WM_NOTIFY, DoNotifyMain },
{ WM_SETTINGCHANGE, DoSettingChangeMain },
{ WM_HIBERNATE, DoHibernateMain },
{ WM_ACTIVATE, DoActivateMain },
{ WM_DESTROY, DoDestroyMain },
{ 0, NULL }
};
const CMDDispatch MainCommandItems[] = {
{ FL_EXIT, DoMainCommandExit },
{ FL_PLAY, DoMainCommandPlay },
{ FL_FILE, DoMainCommandFile },
{ FL_ABOUT, DoMainCommandAbout },
{ 0, NULL }
};
/*********************************************************************/
/*********************************************************************/
LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
int i;
for (i=0; MainDispatchers[i].Code != 0; i++)
{
if (msg == MainDispatchers[i].Code)
return (MainDispatchers[i].Fxn)(hwnd,msg,wParam,lParam);
}
return DefWindowProc(hwnd,msg,wParam,lParam);
}
LRESULT DoCreateMain(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
SHMENUBARINFO mbi;
ZeroMemory(&mbi,sizeof(mbi));
mbi.cbSize = sizeof(SHMENUBARINFO);
mbi.hwndParent = hwnd;
mbi.nToolBarId = FL_TOOLBAR1;
mbi.hInstRes = hInst;
SHCreateMenuBar(&mbi);
hmbar=mbi.hwndMB;
if (!hmbar)
{
MessageBox(hwnd, L"Couldn't create toolbar",AppName, MB_OK);
DestroyWindow(hwnd);
return 0;
}
fl_filename[0] = '\0';
return 0;
}
LRESULT DoSizeMain(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return 0;
}
LRESULT DoCommandMain(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
WORD idItem, wNotifyCode;
HWND hwndCtl;
int i;
idItem = (WORD)LOWORD(wParam);
wNotifyCode = (WORD)HIWORD(wParam);
hwndCtl = (HWND)lParam;
for (i=0; MainCommandItems[i].Code; i++)
{
if (idItem == MainCommandItems[i].Code)
return MainCommandItems[i].Fxn(hwnd,idItem,hwndCtl,wNotifyCode);
}
return 0;
}
LRESULT DoNotifyMain (HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return 0;
}
LRESULT DoSettingChangeMain(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
SHHandleWMSettingChange(hwnd, wParam, lParam, &sai);
return 0;
}
LRESULT DoHibernateMain(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return 0;
}
LRESULT DoActivateMain(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
SHHandleWMActivate(hwnd, wParam, lParam, &sai, 0);
return 0;
}
LRESULT DoDestroyMain(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
PostQuitMessage(0);
return 0;
}
/* Command handler routines */
LPARAM DoMainCommandExit(HWND hwnd, WORD idItem, HWND hwndCtl, WORD wNotifyCode)
{
SendMessage(hwnd, WM_CLOSE, 0, 0);
return 0;
}
LPARAM DoMainCommandAbout(HWND hwnd, WORD idItem,
HWND hwndCtl, WORD wNotifyCode)
{
DialogBox(hInst, L"aboutbox", hwnd, AboutDlgProc);
return 0;
}
BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
SHINITDLGINFO idi;
switch (msg)
{
case WM_INITDIALOG:
idi.dwMask = SHIDIM_FLAGS;
idi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLGFULLSCREEN |
SHIDIF_SIPDOWN;
idi.hDlg = hwnd;
SHInitDialog (&idi);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hwnd,0);
return TRUE;
}
break;
}
return FALSE;
}
LPARAM DoMainCommandPlay(HWND hwnd, WORD idItem,
HWND hwndCtl, WORD wNotifyCode)
{
DialogBox(hInst, L"playbox", hwnd, PlayDlgProc);
return 0;
}
BOOL CALLBACK PlayDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
OPENFILENAME sf;
const LPTSTR pszSaveFilter = L"Waveforms (*.wav)\0*.wav\0\0";
SHINITDLGINFO idi;
TCHAR text[FL_MAX_TEXTLEN];
TCHAR szFilePos[FL_MAX_TEXTLEN];
TCHAR *x;
int i, looptimes;
SYSTEMTIME StartTime, EndTime;
float elapsedtime;
switch (msg)
{
case WM_INITDIALOG:
idi.dwMask = SHIDIM_FLAGS;
idi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLGFULLSCREEN;
idi.hDlg = hwnd;
SHInitDialog (&idi);
for (i=0; flowm_voice_name(i); i++)
{ /* Add regestered voices to the voice dropdown */
SendDlgItemMessage(hwnd, FL_VOXLIST, CB_ADDSTRING,
0, (LPARAM)flowm_voice_name(i));
}
/* Position cursor at start, selecting first voice */
SendDlgItemMessage(hwnd, FL_VOXLIST, CB_SETCURSEL, 0, 0);
/* Add Relation types to the selection box */
SendDlgItemMessage(hwnd,FL_RELLIST,CB_ADDSTRING,0,(LPARAM)L"Token");
SendDlgItemMessage(hwnd,FL_RELLIST,CB_ADDSTRING,0,(LPARAM)L"Word");
SendDlgItemMessage(hwnd,FL_RELLIST,CB_ADDSTRING,0,(LPARAM)L"Segment");
SendDlgItemMessage(hwnd,FL_RELLIST,CB_SETCURSEL,0,0);
TTSWindow = 0; /* just in case there is a race condition */
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case FL_PUSHPLAY:
/* Synthesis the text with selection voice */
/* Output items in selected relation at end */
GetDlgItemText(hwnd, FL_TEXT, text, FL_MAX_TEXTLEN);
flowm_selected_voice =
ComboBox_GetCurSel(GetDlgItem(hwnd,FL_VOXLIST));
flowm_selected_relation =
ComboBox_GetCurSel(GetDlgItem(hwnd,FL_RELLIST));
flowm_play_status = FLOWM_PLAY;
flowm_say_text(text);
flowm_play_status = FLOWM_STOP;
if (flowm_selected_relation > 0)
SetDlgItemText(hwnd, FL_OUTPUT, fl_tts_msg);
return TRUE;
case FL_PUSHSAVE:
/* Save the last synthesized waveform */
ZeroMemory(&sf,sizeof(sf));
sf.lStructSize = sizeof(sf);
sf.lpstrFile = fl_filename;
sf.nMaxFile = 256;
sf.lpstrFilter = pszSaveFilter;
sf.Flags = 0;
sf.lpstrTitle = L"Flowm Save";
if (GetSaveFileName(&sf) != 0)
{
if (flowm_save_wave(fl_filename) == -1)
wsprintf(fl_tts_msg,L"Wave NOT saved in %s",fl_filename);
else
wsprintf(fl_tts_msg,L"Wave saved in %s",fl_filename);
MessageBox(hwnd, fl_tts_msg, AppName, MB_OK);
}
fl_filename[0] = '\0';
return TRUE;
case FL_BENCH:
/* Bench marking, find out the speed of synthesis on device */
if (flowm_play_status == FLOWM_BENCH)
{
flowm_play_status = FLOWM_STOP;
return TRUE;
}
flowm_play_status = FLOWM_BENCH;
/* Find out what voice we want */
flowm_selected_voice =
ComboBox_GetCurSel(GetDlgItem(hwnd,FL_VOXLIST));
flowm_selected_relation = 0;
flowm_duration = 0.0;
GetSystemTime(&StartTime);
GetDlgItemText(hwnd, FL_TEXT, szFilePos, FL_MAX_TEXTLEN);
looptimes = wcstod(szFilePos,&x);
if (looptimes < 5)
looptimes = 5;
wsprintf(fl_tts_msg,L"Bench marking: loop = %d ...",looptimes);
SetDlgItemText(hwnd, FL_OUTPUT, fl_tts_msg);
SetDlgItemText(hwnd, FL_TEXT,FL_BENCH_TEXT);
for (i=0; i<looptimes; i++)
flowm_say_text(FL_BENCH_TEXT);
GetSystemTime(&EndTime);
/* This will fail over noon (?) and midnight */
elapsedtime =
(EndTime.wHour*60.0*60.0+EndTime.wMinute*60.0+
EndTime.wSecond+EndTime.wMilliseconds/1000.0) -
(StartTime.wHour*60.0*60.0+StartTime.wMinute*60.0+
StartTime.wSecond+ StartTime.wMilliseconds/1000.0);
wsprintf(fl_tts_msg,L"%2.1f speech; %2.1f seconds; %2.2f rate;",
flowm_duration,
elapsedtime,
flowm_duration/elapsedtime);
SetDlgItemText(hwnd, FL_OUTPUT, fl_tts_msg);
flowm_play_status = FLOWM_STOP;
return TRUE;
case IDOK:
case IDCANCEL:
flowm_play_status = FLOWM_STOP;
EndDialog(hwnd,0);
return TRUE;
}
break;
}
return FALSE;
}
LPARAM DoMainCommandFile(HWND hwnd, WORD idItem,
HWND hwndCtl, WORD wNotifyCode)
{
DialogBox(hInst, L"filebox", hwnd, FileDlgProc);
return 0;
}
DWORD WINAPI tts_thread_function(PVOID pArg)
{
while (flowm_play_status != FLOWM_STOP)
{
flowm_say_file(fl_filename);
if (flowm_play_status == FLOWM_BACKSKIP)
flowm_play_status = FLOWM_PLAY; /* restart at new place */
else if (flowm_play_status != FLOWM_STOP)
{
/* If we finish the file without an explicit stop, reset */
/* the file position to the start of the file */
flowm_file_pos = 0;
if (TTSWindow) SetDlgItemText(TTSWindow, FL_FILEPOS, L"0");
flowm_play_status = FLOWM_STOP;
}
}
return 0x15;
}
static int flowm_find_filesize(TCHAR *filename)
{
HANDLE fp;
int fs = 0;
fp = CreateFile(filename, GENERIC_READ,
FILE_SHARE_READ, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (!fp)
return -1;
fs = GetFileSize(fp,NULL);
CloseHandle(fp);
return fs;
}
void DisplayOff()
{ /* Switch the screen off now */
HDC hdc;
VIDEO_POWER_MANAGEMENT vpm;
hdc = GetDC(NULL);
vpm.PowerState = VideoPowerOff;
vpm.Length = sizeof(VIDEO_POWER_MANAGEMENT);
ExtEscape(hdc,
SETPOWERMANAGEMENT,
sizeof(VIDEO_POWER_MANAGEMENT),
(LPCSTR)&vpm,
0,
NULL);
return;
}
BOOL CALLBACK FileDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
SHINITDLGINFO idi;
OPENFILENAME of;
const LPTSTR pszOpenFilter = L"Text Documents (*.txt)\0*.txt\0\0";
int nParameter = 5;
DWORD dwThreadID = 0;
TCHAR szFilePos[FL_MAX_TEXTLEN];
TCHAR *x;
int i;
float nfilepos;
HWND hwndvox;
switch (msg)
{
case WM_INITDIALOG:
idi.dwMask = SHIDIM_FLAGS;
idi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLGFULLSCREEN;
idi.hDlg = hwnd;
SHInitDialog (&idi);
if (fl_filename[0] != '\0')
{
SetDlgItemText(hwnd, FL_FILENAME, fl_filename);
flowm_file_pos = 0;
SetDlgItemText(hwnd, FL_FILEPOS, L"0");
}
for (i=0; flowm_voice_name(i); i++)
{ /* Add regestered voices to the voice dropdown */
SendDlgItemMessage(hwnd, FL_VOXLIST, CB_ADDSTRING,
0, (LPARAM)flowm_voice_name(i));
}
/* Position cursor at start, selecting first voice */
SendDlgItemMessage(hwnd, FL_VOXLIST, CB_SETCURSEL, 0, 0);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case FL_PUSHSELECT:
/* Find a file to synthesize */
fl_filename[0] = '\0';
ZeroMemory(&of,sizeof(of));
of.lStructSize = sizeof(of);
of.lpstrFile = fl_filename;
of.nMaxFile = 256;
of.lpstrFilter = pszOpenFilter;
of.Flags = 0;
of.lpstrTitle = L"Flowm Open";
if (GetOpenFileName(&of) != 0)
{
flowm_play_status = FLOWM_STOP;
SetDlgItemText(hwnd, FL_FILENAME, fl_filename);
flowm_file_pos = 0;
flowm_file_size = flowm_find_filesize(fl_filename);
flowm_utt_pos_pos = 0;
flowm_prev_utt_pos[flowm_utt_pos_pos] = 0;
SetDlgItemText(hwnd, FL_FILEPOS, L"0");
SetDlgItemText(hwnd, FL_SYNTHTEXT, L"");
if (flowm_file_size == -1)
{
wsprintf(fl_fp_msg,L"File not found: %s",fl_filename);
MessageBox(hwnd, fl_fp_msg,AppName, MB_OK);
fl_filename[0] = '\0';
}
}
return TRUE;
case FL_PUSHTTS:
/* Synthesize the selected file from the specified position */
/* with the selected voice */
if ((flowm_play_status != FLOWM_PLAY) &&
(fl_filename[0] != '\0'))
{
flowm_play_status = FLOWM_PLAY;
TTSWindow = hwnd;
/* Find out what voice we want */
hwndvox = GetDlgItem(hwnd,FL_VOXLIST);
flowm_selected_voice = ComboBox_GetCurSel(hwndvox);
/* Update file position, in case user changed it */
GetDlgItemText(hwnd, FL_FILEPOS, szFilePos, FL_MAX_TEXTLEN);
nfilepos = wcstod(szFilePos,&x);
/* Be a little careful we don't reset file position */
/* when we have an accuracy problem: filepos is an int */
/* but the display field is the % */
if (nfilepos > 100) nfilepos = 100.0;
if (nfilepos < 0) nfilepos = 0.0;
if (((nfilepos - flowm_find_file_percentage()) > 0.001) ||
((nfilepos - flowm_find_file_percentage()) < -0.001))
flowm_file_pos = (int)((nfilepos*flowm_file_size)/100.0);
/* Do the synthesis in a new thread, so we can still process */
/* button pushes */
tts_thread = CreateThread(NULL, 0, tts_thread_function,
(PVOID)nParameter, 0, &dwThreadID);
CloseHandle(tts_thread);
}
return TRUE;
case FL_PUSHBACK:
/* Move back to previous utterance */
if (flowm_utt_pos_pos > 0)
{ /* Jump back to beginning of previous utt (we know about) */
flowm_utt_pos_pos--;
flowm_file_pos = flowm_prev_utt_pos[flowm_utt_pos_pos];
}
else if (flowm_file_pos > 1)
/* Not got any previous -- we never payed that bit get */
/* so just jump back 100 chars */
flowm_file_pos -= 100;
else /* At start of file already */
flowm_file_pos = 0;
wsprintf(fl_fp_msg,L"%2.3f",flowm_find_file_percentage());
SetDlgItemText(TTSWindow, FL_FILEPOS, fl_fp_msg);
flowm_play_status = FLOWM_BACKSKIP;
return TRUE;
case FL_PUSHFORWARD:
/* Skip forward to next utterances now */
if ((flowm_play_status == FLOWM_PLAY) ||
(flowm_play_status == FLOWM_SKIP))
flowm_play_status = FLOWM_SKIP; /* already playing/skipping */
else
{ /* No playing so just jump forward 100 chars */
flowm_file_pos += 100;
wsprintf(fl_fp_msg,L"%2.3f",flowm_find_file_percentage());
SetDlgItemText(TTSWindow, FL_FILEPOS, fl_fp_msg);
}
return TRUE;
case FL_PUSHSTOP:
flowm_play_status = FLOWM_STOP;
return TRUE;
case FL_SCREENOFF:
/* turn off the screen */
DisplayOff();
return TRUE;
case IDOK:
if (flowm_play_status == FLOWM_STOP)
{ /* Only end if we are in stop mode */
TTSWindow = 0; /* just in case there is a race condition */
EndDialog(hwnd,0);
}
return TRUE; /* you need to press end to end */
case FL_PUSHEND:
case IDCANCEL:
flowm_play_status = FLOWM_STOP;
TTSWindow = 0; /* just in case there is a race condition */
EndDialog(hwnd,0);
return TRUE;
}
break;
}
return FALSE;
}
int WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HWND hwndMain=0;
int rc;
rc = InitApp(hInstance);
if (rc) return rc;
hwndMain=InitInstance(hInstance,lpCmdLine, nCmdShow);
if (hwndMain == 0) return 0x10;
flowm_init(); /* Initialize the TTS system */
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
flowm_terminate(); /* Close the TTS systems */
return msg.wParam;
}
int InitApp(HINSTANCE hInstance)
{
WNDCLASS wc;
HWND hWnd;
/* If already running, return */
hWnd = FindWindow(AppName,NULL);
if (hWnd)
{
SetForegroundWindow((HWND)(((DWORD)hWnd) | 0x01));
return -1;
}
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = MainWndProc; /* main callback function */
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Default cursor */
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL; /* Menu name */
wc.lpszClassName = AppName; /* Window class name */
if (RegisterClass(&wc) == 0)
return 1;
else
return 0;
}
HWND InitInstance(HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
hInst = hInstance;
hwnd = CreateWindow(AppName,
AppName,
WS_VISIBLE,
CW_USEDEFAULT, /* x position */
CW_USEDEFAULT, /* y position */
CW_USEDEFAULT, /* Initial width */
CW_USEDEFAULT, /* Initial height */
NULL, /* Parent */
NULL, /* Menu */
hInstance,
NULL); /* extra params */
if (!IsWindow(hwnd))
return 0; /* failed to create a window */
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return hwnd;
}