mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-01 21:58:52 +00:00
[1.39.14]
Provide Viseme events on the Windows SAPI5 interface. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@199 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
@@ -23,13 +23,12 @@
|
||||
#include "src/speak_lib.h"
|
||||
#include "stdio.h"
|
||||
|
||||
|
||||
|
||||
#define CTRL_EMBEDDED 1
|
||||
|
||||
CTTSEngObj *m_EngObj;
|
||||
ISpTTSEngineSite* m_OutputSite;
|
||||
FILE *f_log2=NULL;
|
||||
ULONGLONG event_interest;
|
||||
|
||||
extern int AddNameData(const char *name, int wide);
|
||||
extern void InitNamedata(void);
|
||||
@@ -49,6 +48,10 @@ char *path_install = NULL;
|
||||
|
||||
unsigned long audio_offset = 0;
|
||||
unsigned long audio_latest = 0;
|
||||
int prev_phoneme = 0;
|
||||
int prev_phoneme_position = 0;
|
||||
unsigned long prev_phoneme_time = 0;
|
||||
|
||||
unsigned int gBufSize = 0;
|
||||
wchar_t *TextBuf=NULL;
|
||||
|
||||
@@ -65,6 +68,48 @@ int frag_count=0;
|
||||
FRAG_OFFSET *frag_offsets = NULL;
|
||||
|
||||
|
||||
int VisemeCode(unsigned int phoneme_name)
|
||||
{//======================================
|
||||
// Convert eSpeak phoneme name into a SAPI viseme code
|
||||
|
||||
int ix;
|
||||
unsigned int ph;
|
||||
unsigned int ph_name;
|
||||
|
||||
#define PH(c1,c2) (c2<<8)+c1 // combine two characters into an integer for phoneme name
|
||||
|
||||
const unsigned char initial_to_viseme[128] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 0, 0,19, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,
|
||||
4, 2,18,16,17, 4,18,20,12, 6,16,20,14,21,20, 3,
|
||||
21,20,13,16,17, 4, 1, 5,20, 7,16, 0, 0, 0, 0, 0,
|
||||
0, 1,21,16,19, 4,18,20,12, 6, 6,20,14,21,19, 8,
|
||||
21,20,13,15,19, 7,18, 7,20, 7,15, 0, 0, 0, 0, 0 };
|
||||
|
||||
const unsigned int viseme_exceptions[] = {
|
||||
PH('a','I'), 11,
|
||||
PH('a','U'), 9,
|
||||
PH('O','I'), 10,
|
||||
PH('t','S'), 16,
|
||||
PH('d','Z'), 16,
|
||||
PH('_','|'), 255,
|
||||
0
|
||||
};
|
||||
|
||||
ph_name = phoneme_name & 0xffff;
|
||||
for(ix=0; (ph = viseme_exceptions[ix]) != 0; ix+=2)
|
||||
{
|
||||
if(ph == ph_name)
|
||||
{
|
||||
return(viseme_exceptions[ix+1]);
|
||||
}
|
||||
}
|
||||
return(initial_to_viseme[phoneme_name & 0x7f]);
|
||||
}
|
||||
|
||||
|
||||
int SynthCallback(short *wav, int numsamples, espeak_EVENT *events);
|
||||
|
||||
int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
|
||||
@@ -73,6 +118,8 @@ int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
|
||||
wchar_t *tailptr;
|
||||
unsigned int text_offset;
|
||||
int length;
|
||||
int phoneme_duration;
|
||||
int this_viseme;
|
||||
|
||||
espeak_EVENT *event;
|
||||
#define N_EVENTS 100
|
||||
@@ -86,7 +133,7 @@ int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
|
||||
m_EngObj->CheckActions(m_OutputSite);
|
||||
|
||||
// return the events
|
||||
for(event=events; event->type != 0; event++)
|
||||
for(event=events; (event->type != 0) && (n_Events < N_EVENTS); event++)
|
||||
{
|
||||
audio_latest = event->audio_position + audio_offset;
|
||||
|
||||
@@ -121,6 +168,28 @@ int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
|
||||
Event->lParam = (long)event->id.name;
|
||||
Event->wParam = wcstol((wchar_t *)event->id.name,&tailptr,10);
|
||||
}
|
||||
if(event->type == espeakEVENT_PHONEME)
|
||||
{
|
||||
if(event_interest & SPEI_VISEME)
|
||||
{
|
||||
phoneme_duration = audio_latest - prev_phoneme_time;
|
||||
|
||||
// ignore some phonemes (which translate to viseme=255)
|
||||
if((this_viseme = VisemeCode(event->id.number)) != 255)
|
||||
{
|
||||
Event = &Events[n_Events++];
|
||||
Event->eEventId = SPEI_VISEME;
|
||||
Event->elParamType = SPET_LPARAM_IS_UNDEFINED;
|
||||
Event->ullAudioStreamOffset = ((prev_phoneme_position + audio_offset) * srate)/10; // ms -> bytes
|
||||
Event->lParam = phoneme_duration << 16 | this_viseme;
|
||||
Event->wParam = VisemeCode(prev_phoneme);
|
||||
|
||||
prev_phoneme = event->id.number;
|
||||
prev_phoneme_time = audio_latest;
|
||||
prev_phoneme_position = event->audio_position;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef deleted
|
||||
if(event->type == espeakEVENT_SENTENCE)
|
||||
{
|
||||
@@ -286,7 +355,7 @@ STDMETHODIMP CTTSEngObj::SetObjectToken(ISpObjectToken * pToken)
|
||||
gEmphasis = 0;
|
||||
gSayas = 0;
|
||||
|
||||
espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,100,path_install,0);
|
||||
espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,100,path_install,1);
|
||||
espeak_SetVoiceByName(voice);
|
||||
espeak_SetSynthCallback(SynthCallback);
|
||||
|
||||
@@ -654,7 +723,7 @@ STDMETHODIMP CTTSEngObj::Speak( DWORD dwSpeakFlags,
|
||||
m_ullAudioOff = 0;
|
||||
|
||||
m_OutputSite = pOutputSite;
|
||||
|
||||
pOutputSite->GetEventInterest(&event_interest);
|
||||
|
||||
xVolume = gVolume;
|
||||
xSpeed = gSpeed;
|
||||
@@ -694,6 +763,10 @@ STDMETHODIMP CTTSEngObj::Speak( DWORD dwSpeakFlags,
|
||||
}
|
||||
|
||||
audio_latest = 0;
|
||||
prev_phoneme = 0;
|
||||
prev_phoneme_time = 0;
|
||||
prev_phoneme_position = 0;
|
||||
|
||||
size = ProcessFragList(pTextFragList,TextBuf,pOutputSite,&n_text_frag);
|
||||
|
||||
if(size > 0)
|
||||
|
||||
Reference in New Issue
Block a user