mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-14 01:32:29 +00:00
[1.30.04] SSML <audio src=""> now works without using a UriCallback() function, and works with the command-line espeak.
Pitch changes for mbrola are now applied over the first 80% of the phoneme, not over the whole length of the phoneme. This seems to give better intonation for mbrola voices. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@118 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
+1
-15
@@ -73,6 +73,7 @@
|
||||
#define tINCLUDE 31
|
||||
|
||||
extern void Write4Bytes(FILE *f, int value);
|
||||
extern int Read4Bytes(FILE *f);
|
||||
extern void MakeVowelLists(void);
|
||||
extern void FindPhonemesUsed(void);
|
||||
extern void DrawEnvelopes();
|
||||
@@ -309,21 +310,6 @@ static unsigned int StringToWord(const char *string)
|
||||
}
|
||||
|
||||
|
||||
int Read4Bytes(FILE *f)
|
||||
{//====================
|
||||
// Read 4 bytes (least significant first) into a word
|
||||
int ix;
|
||||
unsigned char c;
|
||||
int acc=0;
|
||||
|
||||
for(ix=0; ix<4; ix++)
|
||||
{
|
||||
c = fgetc(f) & 0xff;
|
||||
acc += (c << (ix*8));
|
||||
}
|
||||
return(acc);
|
||||
}
|
||||
|
||||
|
||||
static FILE *fopen_log(FILE *f_log, const char *fname,const char *access)
|
||||
{//==================================================
|
||||
|
||||
+102
-10
@@ -511,6 +511,21 @@ const char *Translator::LookupCharName(int c)
|
||||
return(buf);
|
||||
}
|
||||
|
||||
int Read4Bytes(FILE *f)
|
||||
{//====================
|
||||
// Read 4 bytes (least significant first) into a word
|
||||
int ix;
|
||||
unsigned char c;
|
||||
int acc=0;
|
||||
|
||||
for(ix=0; ix<4; ix++)
|
||||
{
|
||||
c = fgetc(f) & 0xff;
|
||||
acc += (c << (ix*8));
|
||||
}
|
||||
return(acc);
|
||||
}
|
||||
|
||||
|
||||
static int LoadSoundFile(const char *fname, int index)
|
||||
{//===================================================
|
||||
@@ -520,7 +535,7 @@ static int LoadSoundFile(const char *fname, int index)
|
||||
int length;
|
||||
char fname_temp[100];
|
||||
char fname2[sizeof(path_home)+13+40];
|
||||
char command[sizeof(fname2)+sizeof(fname2)+30];
|
||||
char command[sizeof(fname2)+sizeof(fname2)+40];
|
||||
|
||||
if(fname == NULL)
|
||||
{
|
||||
@@ -542,16 +557,27 @@ static int LoadSoundFile(const char *fname, int index)
|
||||
#ifdef PLATFORM_POSIX
|
||||
if((f = fopen(fname,"rb")) != NULL)
|
||||
{
|
||||
int header[11];
|
||||
fread(header, 1, 44, f);
|
||||
int ix;
|
||||
const char *resample;
|
||||
int header[3];
|
||||
|
||||
if(header[6] != samplerate)
|
||||
fseek(f,20,SEEK_SET);
|
||||
for(ix=0; ix<3; ix++)
|
||||
header[ix] = Read4Bytes(f);
|
||||
|
||||
// if the sound file is not mono, 16 bit signed, at the correct sample rate, then convert it
|
||||
if((header[0] != 0x10001) || (header[1] != samplerate) || (header[2] != samplerate*2))
|
||||
{
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
||||
if(header[2] == samplerate)
|
||||
resample = "";
|
||||
else
|
||||
resample = "polyphase";
|
||||
|
||||
sprintf(fname_temp,"%s.wav",tmpnam(NULL));
|
||||
sprintf(command,"sox \"%s\" -r %d -w %s polyphase\n",fname,samplerate,fname_temp);
|
||||
sprintf(command,"sox \"%s\" -r %d -w -s -c1 %s %s\n", fname, samplerate, fname_temp, resample);
|
||||
if(system(command) == 0)
|
||||
{
|
||||
fname = fname_temp;
|
||||
@@ -572,14 +598,18 @@ static int LoadSoundFile(const char *fname, int index)
|
||||
|
||||
length = GetFileLength(fname);
|
||||
fseek(f,0,SEEK_SET);
|
||||
p = Alloc(length);
|
||||
if((p = (char *)realloc(soundicon_tab[index].data, length)) == NULL)
|
||||
{
|
||||
fclose(f);
|
||||
return(4);
|
||||
}
|
||||
fread(p,length,1,f);
|
||||
fclose(f);
|
||||
remove(fname_temp);
|
||||
|
||||
ip = (int *)(&p[40]);
|
||||
soundicon_tab[index].length = (*ip) / 2; // length in samples
|
||||
soundicon_tab[index].data = p+44; // skip WAV header
|
||||
soundicon_tab[index].data = p;
|
||||
return(0);
|
||||
} // end of LoadSoundFile
|
||||
|
||||
@@ -589,7 +619,7 @@ static int LookupSoundicon(int c)
|
||||
// Find the sound icon number for a punctuation chatacter
|
||||
int ix;
|
||||
|
||||
for(ix=0; ix<n_soundicon_tab; ix++)
|
||||
for(ix=N_SOUNDICON_SLOTS; ix<n_soundicon_tab; ix++)
|
||||
{
|
||||
if(soundicon_tab[ix].name == c)
|
||||
{
|
||||
@@ -605,6 +635,34 @@ static int LookupSoundicon(int c)
|
||||
}
|
||||
|
||||
|
||||
static int LoadSoundFile2(const char *fname)
|
||||
{//=========================================
|
||||
// Load a sound file into one of the reserved slots in the sound icon table
|
||||
// (if it'snot already loaded)
|
||||
|
||||
int ix;
|
||||
static int slot = -1;
|
||||
|
||||
for(ix=0; ix<n_soundicon_tab; ix++)
|
||||
{
|
||||
if(((soundicon_tab[ix].filename != NULL) && strcmp(fname, soundicon_tab[ix].filename) == 0))
|
||||
return(ix); // already loaded
|
||||
}
|
||||
|
||||
// load the file into the next slot
|
||||
slot++;
|
||||
if(slot >= N_SOUNDICON_SLOTS)
|
||||
slot = 0;
|
||||
|
||||
if(LoadSoundFile(fname, slot) != 0)
|
||||
return(-1);
|
||||
|
||||
soundicon_tab[slot].filename = (char *)realloc(soundicon_tab[ix].filename, strlen(fname)+1);
|
||||
strcpy(soundicon_tab[slot].filename, fname);
|
||||
return(slot);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Translator::AnnouncePunctuation(int c1, int c2, char *buf, int bufix)
|
||||
{//======================================================================
|
||||
@@ -1462,12 +1520,27 @@ static int ProcessSsmlTag(wchar_t *xml_buf, char *outbuf, int &outix, int n_outb
|
||||
|
||||
if((attr1 = GetSsmlAttribute(px,"src")) != NULL)
|
||||
{
|
||||
char fname[256];
|
||||
attrcopy_utf8(buf,attr1,sizeof(buf));
|
||||
|
||||
if(uri_callback == NULL)
|
||||
{
|
||||
// we could load the audio file as a sound icon (assuming it's a local WAV file)
|
||||
// But when to free() the data?
|
||||
if((xmlbase != NULL) && (buf[0] != '/'))
|
||||
{
|
||||
sprintf(fname,"%s/%s",xmlbase,buf);
|
||||
index = LoadSoundFile2(fname);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = LoadSoundFile2(buf);
|
||||
}
|
||||
if(index >= 0)
|
||||
{
|
||||
sprintf(buf,"%c%dI",CTRL_EMBEDDED,index);
|
||||
strcpy(&outbuf[outix],buf);
|
||||
outix += strlen(buf);
|
||||
sp->parameter[espeakSILENCE] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1853,6 +1926,25 @@ f_input = f_in; // for GetC etc
|
||||
|
||||
if(iswalnum(c1))
|
||||
any_alnum = 1;
|
||||
else
|
||||
if(iswspace(c1))
|
||||
{
|
||||
if(translator_name == 0x6a626f)
|
||||
{
|
||||
// language jbo : lojban
|
||||
// treat "i" or ".i" as end-of-sentence
|
||||
if(buf[ix-1] == 'i')
|
||||
{
|
||||
if(iswspace(buf[ix-2]) || ((buf[ix-2] == '.') && iswspace(buf[ix-3])))
|
||||
{
|
||||
UngetC(c2);
|
||||
buf[ix] = ' ';
|
||||
buf[ix+1] = 0;
|
||||
return(CLAUSE_PERIOD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(iswupper(c1))
|
||||
{
|
||||
|
||||
+1
-3
@@ -305,9 +305,7 @@ static int initialise(void)
|
||||
else
|
||||
fprintf(stderr,"Wrong version of espeak-data 0x%x (expects 0x%x)\n",result,version_phdata);
|
||||
}
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
LoadConfig(); // causes problem on Windows, don't know why
|
||||
#endif
|
||||
LoadConfig();
|
||||
SetVoiceStack(NULL);
|
||||
SynthesizeInit();
|
||||
|
||||
|
||||
@@ -335,9 +335,7 @@ static int initialise(void)
|
||||
int param;
|
||||
int result;
|
||||
|
||||
#ifndef __WIN32__
|
||||
LoadConfig();
|
||||
#endif
|
||||
WavegenInit(22050,0); // 22050
|
||||
if((result = LoadPhData()) != 1)
|
||||
{
|
||||
|
||||
+39
-15
@@ -252,8 +252,9 @@ int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev, PHONE
|
||||
}
|
||||
|
||||
|
||||
static char *WritePitch(int env, int pitch1, int pitch2, int split)
|
||||
{//================================================================
|
||||
static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)
|
||||
{//===========================================================================
|
||||
// final=1: only give the final pitch value.
|
||||
int x;
|
||||
int ix;
|
||||
int pitch_base;
|
||||
@@ -264,11 +265,12 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split)
|
||||
int min = 999;
|
||||
int y_max=0;
|
||||
int y_min=0;
|
||||
int env100 = 80; // apply the pitch change only over this proportion of the mbrola phoneme(s)
|
||||
int y2;
|
||||
int y[4];
|
||||
int env_split;
|
||||
char buf[40];
|
||||
static char output[40];
|
||||
char buf[50];
|
||||
static char output[50];
|
||||
|
||||
output[0] = 0;
|
||||
pitch_env = envelope_data[env];
|
||||
@@ -335,18 +337,18 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split)
|
||||
|
||||
if(split > 0)
|
||||
{
|
||||
y2 = (y[ix] * 100)/env_split;
|
||||
y2 = (y[ix] * env100)/env_split;
|
||||
}
|
||||
else
|
||||
if(split < 0)
|
||||
{
|
||||
y2 = ((y[ix]-env_split) * 100)/env_split;
|
||||
y2 = ((y[ix]-env_split) * env100)/env_split;
|
||||
}
|
||||
else
|
||||
{
|
||||
y2 = (y[ix] * 100)/128;
|
||||
y2 = (y[ix] * env100)/128;
|
||||
}
|
||||
if((y2 > 0) && (y2 <= 100))
|
||||
if((y2 > 0) && (y2 <= env100))
|
||||
{
|
||||
sprintf(buf," %d %d",y2,p2/4096);
|
||||
strcat(output,buf);
|
||||
@@ -354,14 +356,23 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split)
|
||||
}
|
||||
}
|
||||
|
||||
p_end = p_end/4096;
|
||||
if(split <= 0)
|
||||
{
|
||||
sprintf(buf," 100 %d",p_end/4096);
|
||||
sprintf(buf," %d %d",env100,p_end);
|
||||
strcat(output,buf);
|
||||
}
|
||||
if(env100 < 100)
|
||||
{
|
||||
sprintf(buf," %d %d",100,p_end);
|
||||
strcat(output,buf);
|
||||
}
|
||||
strcat(output,"\n");
|
||||
|
||||
if(final)
|
||||
sprintf(output,"\t100 %d\n",p_end);
|
||||
return(output);
|
||||
} // end of SetPitch
|
||||
} // end of WritePitch
|
||||
|
||||
|
||||
#ifdef USE_MBROLA_LIB
|
||||
@@ -506,6 +517,7 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
|
||||
int control;
|
||||
int done;
|
||||
int len_percent;
|
||||
const char *final_pitch;
|
||||
char buf[80];
|
||||
char mbr_buf[120];
|
||||
|
||||
@@ -562,7 +574,7 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
|
||||
len = 1;
|
||||
}
|
||||
else
|
||||
len = (70 * speed_factor2)/256;
|
||||
len = (80 * speed_factor2)/256;
|
||||
|
||||
sprintf(buf,"%s\t",WordToString(name));
|
||||
strcat(mbr_buf,buf);
|
||||
@@ -575,6 +587,7 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
|
||||
}
|
||||
|
||||
done = 0;
|
||||
final_pitch = "";
|
||||
|
||||
switch(ph->type)
|
||||
{
|
||||
@@ -589,16 +602,16 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
|
||||
|
||||
if(name2 == 0)
|
||||
{
|
||||
sprintf(buf,"%d\t%s", len, WritePitch(p->env,p->pitch1,p->pitch2,0));
|
||||
sprintf(buf,"%d\t%s", len, WritePitch(p->env,p->pitch1,p->pitch2,0,0));
|
||||
strcat(mbr_buf,buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
len1 = (len * len_percent)/100;
|
||||
sprintf(buf,"%d\t%s", len1, WritePitch(p->env,p->pitch1,p->pitch2,len_percent));
|
||||
sprintf(buf,"%d\t%s", len1, WritePitch(p->env,p->pitch1,p->pitch2,len_percent,0));
|
||||
strcat(mbr_buf,buf);
|
||||
|
||||
sprintf(buf,"%s\t%d\t%s", WordToString(name2), len-len1, WritePitch(p->env,p->pitch1,p->pitch2,-len_percent));
|
||||
sprintf(buf,"%s\t%d\t%s", WordToString(name2), len-len1, WritePitch(p->env,p->pitch1,p->pitch2,-len_percent,0));
|
||||
strcat(mbr_buf,buf);
|
||||
}
|
||||
done = 1;
|
||||
@@ -635,6 +648,17 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
|
||||
{
|
||||
len = DoSpect(p->ph,prev->ph,phoneme_tab[phonPAUSE],2,p,-1);
|
||||
len = (len * 1000)/samplerate;
|
||||
if(next->type == phPAUSE)
|
||||
len += 50;
|
||||
final_pitch = WritePitch(p->env,p->pitch1,p->pitch2,0,1);
|
||||
}
|
||||
break;
|
||||
|
||||
case phLIQUID:
|
||||
if(next->type == phPAUSE)
|
||||
{
|
||||
len += 50;
|
||||
final_pitch = WritePitch(p->env,p->pitch1,p->pitch2,0,1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -648,7 +672,7 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
|
||||
strcat(mbr_buf,buf);
|
||||
len -= len1;
|
||||
}
|
||||
sprintf(buf,"%d\n",len);
|
||||
sprintf(buf,"%d%s\n",len,final_pitch);
|
||||
strcat(mbr_buf,buf);
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -35,7 +35,7 @@
|
||||
#include "translate.h"
|
||||
#include "wave.h"
|
||||
|
||||
const char *version_string = "1.30.03 04.Jan.08";
|
||||
const char *version_string = "1.30.04 07.Jan.08";
|
||||
const int version_phdata = 0x013000;
|
||||
|
||||
int option_device_number = -1;
|
||||
@@ -622,6 +622,12 @@ void LoadConfig(void)
|
||||
char *p;
|
||||
char string[200];
|
||||
|
||||
for(ix=0; ix<N_SOUNDICON_SLOTS; ix++)
|
||||
{
|
||||
soundicon_tab[ix].filename = NULL;
|
||||
soundicon_tab[ix].data = NULL;
|
||||
}
|
||||
|
||||
sprintf(buf,"%s%c%s",path_home,PATHSEP,"config");
|
||||
if((f = fopen(buf,"r"))==NULL)
|
||||
{
|
||||
|
||||
+4
-4
@@ -62,7 +62,7 @@ static int syllable_centre;
|
||||
|
||||
static voice_t *new_voice=NULL;
|
||||
|
||||
int n_soundicon_tab=0;
|
||||
int n_soundicon_tab=N_SOUNDICON_SLOTS;
|
||||
SOUND_ICON soundicon_tab[N_SOUNDICON_TAB];
|
||||
|
||||
#define RMS_GLOTTAL1 35 // vowel before glottal stop
|
||||
@@ -1041,13 +1041,13 @@ static void DoEmbedded(int &embix, int sourceix)
|
||||
case EMBED_I: // play dynamically loaded wav data (sound icon)
|
||||
if((int)value < n_soundicon_tab)
|
||||
{
|
||||
if((wcmdq[wcmdq_tail][1] = soundicon_tab[value].length) != 0)
|
||||
if(soundicon_tab[value].length != 0)
|
||||
{
|
||||
DoPause(10); // ensure a break in the speech
|
||||
wcmdq[wcmdq_tail][0] = WCMD_WAVE;
|
||||
wcmdq[wcmdq_tail][1] = soundicon_tab[value].length;
|
||||
wcmdq[wcmdq_tail][2] = (long)soundicon_tab[value].data;
|
||||
wcmdq[wcmdq_tail][3] = 0x1f00; // 16 bit data, amp=32
|
||||
wcmdq[wcmdq_tail][2] = (long)soundicon_tab[value].data + 44; // skip WAV header
|
||||
wcmdq[wcmdq_tail][3] = 0x1500; // 16 bit data, amp=21
|
||||
WcmdqInc();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -262,7 +262,8 @@ extern int option_log_frames;
|
||||
extern const char *version_string;
|
||||
extern const int version_phdata;
|
||||
|
||||
#define N_SOUNDICON_TAB 100
|
||||
#define N_SOUNDICON_TAB 80 // total entries in soundicon_tab
|
||||
#define N_SOUNDICON_SLOTS 4 // number of slots reserved for dynamic loading of autio files
|
||||
extern int n_soundicon_tab;
|
||||
extern SOUND_ICON soundicon_tab[N_SOUNDICON_TAB];
|
||||
|
||||
|
||||
+1
-1
@@ -1724,7 +1724,7 @@ void *Translator::TranslateClause(FILE *f_text, const void *vp_input, int *tone_
|
||||
WORD_TAB words[N_CLAUSE_WORDS];
|
||||
int word_count=0; // index into words
|
||||
|
||||
char sbuf[512];
|
||||
char sbuf[N_TR_SOURCE];
|
||||
|
||||
int terminator;
|
||||
int tone;
|
||||
|
||||
Reference in New Issue
Block a user