mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-02 22:07:12 +00:00
[1.47.13]
Program changes to enable audio output from Windows DLL. Language changes: an, de, en, nl, ta. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@365 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
@@ -990,6 +990,10 @@ static wxString CompileAllDictionaries()
|
||||
|
||||
sprintf(fname_log,"%s%s",path_dsource,"dict_log");
|
||||
log = fopen(fname_log,"w");
|
||||
if(log != 0)
|
||||
{
|
||||
fprintf(log, "%s", utf8_bom);
|
||||
}
|
||||
sprintf(fname_log,"%s%s",path_dsource,"dict_phonemes");
|
||||
f_phused = fopen(fname_log,"w");
|
||||
|
||||
@@ -2407,6 +2411,9 @@ int CompileIf(int elif)
|
||||
else
|
||||
{
|
||||
error("Unexpected keyword '%s'",item_string);
|
||||
|
||||
if((strcmp(item_string, "phoneme") == 0) || (strcmp(item_string, "endphoneme") == 0))
|
||||
return(-1);
|
||||
}
|
||||
|
||||
// output the word
|
||||
|
||||
+12
-8
@@ -425,7 +425,8 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
|
||||
char *mnemptr;
|
||||
unsigned char flag_codes[100];
|
||||
char encoded_ph[200];
|
||||
unsigned char bad_phoneme[4];
|
||||
char bad_phoneme_str[4];
|
||||
int bad_phoneme;
|
||||
static char nullstring[] = {0};
|
||||
|
||||
text_not_phonemes = 0;
|
||||
@@ -660,17 +661,18 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
|
||||
}
|
||||
else
|
||||
{
|
||||
EncodePhonemes(phonetic,encoded_ph,bad_phoneme);
|
||||
EncodePhonemes(phonetic,encoded_ph,&bad_phoneme);
|
||||
if(strchr(encoded_ph,phonSWITCH) != 0)
|
||||
{
|
||||
flag_codes[n_flag_codes++] = BITNUM_FLAG_ONLY_S; // don't match on suffixes (except 's') when switching languages
|
||||
}
|
||||
|
||||
// check for errors in the phonemes codes
|
||||
if(bad_phoneme[0] != 0)
|
||||
if(bad_phoneme != 0)
|
||||
{
|
||||
// unrecognised phoneme, report error
|
||||
fprintf(f_log,"%5d: Bad phoneme [%c] (0x%x) in: %s %s\n",linenum,bad_phoneme[0],bad_phoneme[0],word,phonetic);
|
||||
bad_phoneme_str[utf8_out(bad_phoneme, bad_phoneme_str)] = 0;
|
||||
fprintf(f_log,"%5d: Bad phoneme [%s] (U+%x) in: %s %s\n",linenum,bad_phoneme_str,bad_phoneme,word,phonetic);
|
||||
error_count++;
|
||||
}
|
||||
}
|
||||
@@ -1194,7 +1196,8 @@ static char *compile_rule(char *input)
|
||||
int finish=0;
|
||||
char buf[80];
|
||||
char output[150];
|
||||
unsigned char bad_phoneme[4];
|
||||
int bad_phoneme;
|
||||
char bad_phoneme_str[4];
|
||||
|
||||
buf[0]=0;
|
||||
rule_cond[0]=0;
|
||||
@@ -1272,10 +1275,11 @@ static char *compile_rule(char *input)
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
EncodePhonemes(rule_phonemes,buf,bad_phoneme);
|
||||
if(bad_phoneme[0] != 0)
|
||||
EncodePhonemes(rule_phonemes,buf,&bad_phoneme);
|
||||
if(bad_phoneme != 0)
|
||||
{
|
||||
fprintf(f_log,"%5d: Bad phoneme [%c] in %s\n",linenum,bad_phoneme[0],input);
|
||||
bad_phoneme_str[utf8_out(bad_phoneme, bad_phoneme_str)] = 0;
|
||||
fprintf(f_log,"%5d: Bad phoneme [%s] (U+%x) in: %s\n",linenum,bad_phoneme_str,bad_phoneme,input);
|
||||
error_count++;
|
||||
}
|
||||
strcpy(output,buf);
|
||||
|
||||
+4
-5
@@ -347,8 +347,8 @@ int HashDictionary(const char *string)
|
||||
|
||||
|
||||
|
||||
const char *EncodePhonemes(const char *p, char *outptr, unsigned char *bad_phoneme)
|
||||
/***************************************************************************/
|
||||
const char *EncodePhonemes(const char *p, char *outptr, int *bad_phoneme)
|
||||
/******************************************************************/
|
||||
/* Translate a phoneme string from ascii mnemonics to internal phoneme numbers,
|
||||
from 'p' up to next blank .
|
||||
Returns advanced 'p'
|
||||
@@ -365,7 +365,7 @@ const char *EncodePhonemes(const char *p, char *outptr, unsigned char *bad_phone
|
||||
unsigned int mnemonic_word;
|
||||
|
||||
if(bad_phoneme != NULL)
|
||||
bad_phoneme[0] = 0;
|
||||
*bad_phoneme = 0;
|
||||
|
||||
// skip initial blanks
|
||||
while(isspace(*p))
|
||||
@@ -427,8 +427,7 @@ const char *EncodePhonemes(const char *p, char *outptr, unsigned char *bad_phone
|
||||
// not recognised, report and ignore
|
||||
if(bad_phoneme != NULL)
|
||||
{
|
||||
bad_phoneme[0] = *p;
|
||||
bad_phoneme[1] = 0;
|
||||
utf8_in(bad_phoneme, p);
|
||||
}
|
||||
*outptr++ = 0;
|
||||
return(p+1);
|
||||
|
||||
@@ -726,6 +726,7 @@ void MyFrame::OnTools(wxCommandEvent& event)
|
||||
int debug_flag=0;
|
||||
char fname_log[sizeof(path_dsource)+12];
|
||||
char err_fname[sizeof(path_home)+15];
|
||||
static const char utf8_bom[] = {0xef,0xbb,0xbf,0};
|
||||
|
||||
switch(event.GetId())
|
||||
{
|
||||
@@ -776,6 +777,10 @@ void MyFrame::OnTools(wxCommandEvent& event)
|
||||
case MENU_COMPILE_DICT:
|
||||
sprintf(fname_log,"%s%s",path_dsource,"dict_log");
|
||||
log = fopen(fname_log,"w");
|
||||
if(log != NULL)
|
||||
{
|
||||
fprintf(log, "%s", utf8_bom);
|
||||
}
|
||||
|
||||
LoadDictionary(translator, translator->dictionary_name, 0);
|
||||
if((err = CompileDictionary(path_dsource,translator->dictionary_name,log,err_fname,debug_flag)) < 0)
|
||||
|
||||
+18
-11
@@ -24,7 +24,9 @@
|
||||
|
||||
|
||||
//<includes
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -48,6 +50,7 @@ static sem_t my_sem_stop_is_required;
|
||||
static sem_t my_sem_stop_is_acknowledged;
|
||||
// my_thread: polls the audio duration and compares it to the duration of the first event.
|
||||
static pthread_t my_thread;
|
||||
static bool thread_inited;
|
||||
|
||||
static t_espeak_callback* my_callback = NULL;
|
||||
static int my_event_is_running=0;
|
||||
@@ -95,16 +98,16 @@ void event_init(void)
|
||||
assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));
|
||||
|
||||
pthread_attr_t a_attrib;
|
||||
if (pthread_attr_init (& a_attrib)
|
||||
|| pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE)
|
||||
|| pthread_create( &my_thread,
|
||||
& a_attrib,
|
||||
polling_thread,
|
||||
(void*)NULL))
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (pthread_attr_init (&a_attrib) == 0
|
||||
&& pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE) == 0)
|
||||
{
|
||||
thread_inited = (0 == pthread_create(&my_thread,
|
||||
&a_attrib,
|
||||
polling_thread,
|
||||
(void*)NULL));
|
||||
}
|
||||
assert(thread_inited);
|
||||
pthread_attr_destroy(&a_attrib);
|
||||
}
|
||||
//>
|
||||
@@ -127,7 +130,10 @@ ENTER("event_display");
|
||||
"MARK",
|
||||
"PLAY",
|
||||
"END",
|
||||
"MSG_TERMINATED"
|
||||
"MSG_TERMINATED",
|
||||
"PHONEME",
|
||||
"SAMPLERATE",
|
||||
"??"
|
||||
};
|
||||
|
||||
SHOW("event_display > event=0x%x\n",event);
|
||||
@@ -712,7 +718,7 @@ void event_terminate()
|
||||
{
|
||||
ENTER("event_terminate");
|
||||
|
||||
if (my_thread)
|
||||
if (thread_inited)
|
||||
{
|
||||
pthread_cancel(my_thread);
|
||||
pthread_join(my_thread,NULL);
|
||||
@@ -721,6 +727,7 @@ ENTER("event_terminate");
|
||||
sem_destroy(&my_sem_stop_is_required);
|
||||
sem_destroy(&my_sem_stop_is_acknowledged);
|
||||
init(); // purge event
|
||||
thread_inited = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
//<includes
|
||||
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
+8
-2
@@ -1506,7 +1506,10 @@ static int LookupNum2(Translator *tr, int value, const int control, char *ph_out
|
||||
else
|
||||
{
|
||||
// followed by hundreds or thousands etc
|
||||
sprintf(string,"_%da",value);
|
||||
if(tr->langopts.numbers2 & NUM2_ORDINAL_AND_THOUSANDS)
|
||||
sprintf(string, "_%do", value);
|
||||
else
|
||||
sprintf(string, "_%da", value);
|
||||
found = Lookup(tr, string, ph_digits);
|
||||
}
|
||||
|
||||
@@ -1612,7 +1615,10 @@ static int LookupNum2(Translator *tr, int value, const int control, char *ph_out
|
||||
else if(((control & 2) == 0) || ((tr->langopts.numbers & NUM_SWAP_TENS) != 0))
|
||||
{
|
||||
// followed by hundreds or thousands (or tens)
|
||||
sprintf(string,"_%da",units);
|
||||
if(tr->langopts.numbers2 & NUM2_ORDINAL_AND_THOUSANDS)
|
||||
sprintf(string, "_%do", units);
|
||||
else
|
||||
sprintf(string, "_%da", units);
|
||||
found = Lookup(tr, string, ph_digits);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -49,7 +49,7 @@
|
||||
#define phSINGLE_INSTN 0x1000 // this phoneme has a single instruction program, with an implicit Return
|
||||
#define phBRKAFTER 0x4000 // [*] add a post-pause
|
||||
|
||||
#define phNONSYLLABIC 0x100000 // don't count this vowel as a syllable when finding the stress position
|
||||
#define phNONSYLLABIC 0x100000 // don't count this vowel as a syllable when finding the stress position
|
||||
#define phLONG 0x200000
|
||||
#define phLENGTHENSTOP 0x400000 // make the pre-pause slightly longer
|
||||
#define phRHOTIC 0x800000 // bit 23
|
||||
@@ -113,7 +113,7 @@ typedef struct {
|
||||
unsigned char end_type;
|
||||
unsigned char std_length; // for vowels, in mS/2; for phSTRESS phonemes, this is the stress/tone type
|
||||
unsigned char length_mod; // a length_mod group number, used to access length_mod_tab
|
||||
|
||||
|
||||
} PHONEME_TAB;
|
||||
|
||||
|
||||
@@ -155,13 +155,13 @@ typedef struct {
|
||||
|
||||
|
||||
|
||||
#define PH(c1,c2) (c2<<8)+c1 // combine two characters into an integer for phoneme name
|
||||
#define PH(c1,c2) (c2<<8)+c1 // combine two characters into an integer for phoneme name
|
||||
#define PH3(c1,c2,c3) (c3<<16)+(c2<<8)+c1
|
||||
#define PhonemeCode2(c1,c2) PhonemeCode((c2<<8)+c1)
|
||||
int LookupPhonemeString(const char *string);
|
||||
int PhonemeCode(unsigned int mnem);
|
||||
|
||||
const char *EncodePhonemes(const char *p, char *outptr, unsigned char *bad_phoneme);
|
||||
const char *EncodePhonemes(const char *p, char *outptr, int *bad_phoneme);
|
||||
void DecodePhonemes(const char *inptr, char *outptr);
|
||||
|
||||
extern const char *WordToString(unsigned int word);
|
||||
|
||||
+11
-2
@@ -31,7 +31,12 @@
|
||||
#include "speech.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#include <winreg.h>
|
||||
#else /* PLATFORM_POSIX */
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
@@ -551,7 +556,11 @@ static const char* label[] = {
|
||||
"SENTENCE",
|
||||
"MARK",
|
||||
"PLAY",
|
||||
"END"};
|
||||
"END",
|
||||
"MSG_TERMINATED",
|
||||
"PHONEME",
|
||||
"SAMPLERATE",
|
||||
"??" };
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
#include "translate.h"
|
||||
#include "wave.h"
|
||||
|
||||
const char *version_string = "1.47.12 23.Sep.13";
|
||||
const char *version_string = "1.47.13 22.Oct.13";
|
||||
const int version_phdata = 0x014709;
|
||||
|
||||
int option_device_number = -1;
|
||||
|
||||
@@ -1482,6 +1482,7 @@ SetLengthMods(tr,3); // all equal
|
||||
SetupTranslator(tr,stress_lengths_ta, NULL);
|
||||
tr->letter_bits_offset = OFFSET_TAMIL;
|
||||
tr->langopts.numbers = NUM_OMIT_1_THOUSAND ;
|
||||
tr->langopts.numbers2 = NUM2_ORDINAL_AND_THOUSANDS;
|
||||
tr->langopts.param[LOPT_WORD_MERGE] = 1; // don't break vowels betwen words
|
||||
}
|
||||
else
|
||||
@@ -1578,6 +1579,7 @@ SetLengthMods(tr,3); // all equal
|
||||
break;
|
||||
|
||||
case L('u','r'): // Urdu
|
||||
case L('s','d'): // Sindhi
|
||||
{
|
||||
tr->letter_bits_offset = OFFSET_ARABIC;
|
||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words
|
||||
|
||||
+3
-3
@@ -1310,7 +1310,7 @@ if(end_type & SUFX_UNPRON)
|
||||
prefix_flags = 1;
|
||||
if(found == 0)
|
||||
{
|
||||
end_type = TranslateRules(tr, wordx, phonemes, N_WORD_PHONEMES, end_phonemes, 0, dictionary_flags);
|
||||
end_type = TranslateRules(tr, wordx, phonemes, N_WORD_PHONEMES, end_phonemes, wflags & FLAG_HYPHEN_AFTER, dictionary_flags);
|
||||
|
||||
if(phonemes[0] == phonSWITCH)
|
||||
{
|
||||
@@ -1768,7 +1768,7 @@ static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pa
|
||||
int ix;
|
||||
int sylimit; // max. number of syllables in a word to be combined with a preceding preposition
|
||||
const char *new_language;
|
||||
unsigned char bad_phoneme[4];
|
||||
int bad_phoneme;
|
||||
int word_flags;
|
||||
int word_copy_len;
|
||||
char word_copy[N_WORD_BYTES+1];
|
||||
@@ -1874,7 +1874,7 @@ static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pa
|
||||
}
|
||||
else
|
||||
{
|
||||
EncodePhonemes(word,word_phonemes,bad_phoneme);
|
||||
EncodePhonemes(word,word_phonemes,&bad_phoneme);
|
||||
}
|
||||
flags = FLAG_FOUND;
|
||||
}
|
||||
|
||||
@@ -511,6 +511,7 @@ typedef struct {
|
||||
#define NUM2_ENGLISH_NUMERALS 0x8000
|
||||
#define NUM2_PERCENT_BEFORE 0x10000
|
||||
#define NUM2_OMIT_1_HUNDRED_ONLY 0x20000
|
||||
#define NUM2_ORDINAL_AND_THOUSANDS 0x40000
|
||||
// bits 1-4 use variant form of numbers before thousands,millions,etc.
|
||||
// bits 6-8 use different forms of thousand, million, etc (M MA MB)
|
||||
// bit9=(LANG=rw) say "thousand" and "million" before its number, not after
|
||||
@@ -521,6 +522,7 @@ typedef struct {
|
||||
// bit15=(LANG=ne) speak (non-replaced) English numerals in English
|
||||
// bit16=(LANG=si) say "%" before the number
|
||||
// bit17=(LANG=ml) omit "one" before hundred only if there are no previous digits
|
||||
// bit18=(LANG=ta) same variant for ordinals and thousands (#o = #a)
|
||||
int numbers2;
|
||||
|
||||
#define BREAK_THOUSANDS 0x49249248
|
||||
|
||||
+74
-63
@@ -32,7 +32,9 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "portaudio.h"
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "wave.h"
|
||||
@@ -40,6 +42,15 @@
|
||||
|
||||
//<Definitions
|
||||
|
||||
#ifdef NEED_STRUCT_TIMESPEC
|
||||
#define HAVE_STRUCT_TIMESPEC 1
|
||||
struct timespec {
|
||||
long tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
#endif /* HAVE_STRUCT_TIMESPEC */
|
||||
|
||||
|
||||
enum {ONE_BILLION=1000000000};
|
||||
|
||||
#ifdef USE_PORTAUDIO
|
||||
@@ -53,8 +64,8 @@ enum {ONE_BILLION=1000000000};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef USE_PULSEAUDIO
|
||||
// create some wrappers for runtime detection
|
||||
|
||||
@@ -203,8 +214,8 @@ static t_wave_callback* my_callback_is_output_enabled=NULL;
|
||||
#define BUFFER_LENGTH (MAX_SAMPLE_RATE*2*sizeof(uint16_t))
|
||||
//#define THRESHOLD (BUFFER_LENGTH/5)
|
||||
static char myBuffer[BUFFER_LENGTH];
|
||||
static char* myRead=NULL;
|
||||
static char* myWrite=NULL;
|
||||
static char* myRead=NULL;
|
||||
static char* myWrite=NULL;
|
||||
static int out_channels=1;
|
||||
static int my_stream_could_start=0;
|
||||
static int wave_samplerate;
|
||||
@@ -223,7 +234,7 @@ static PaError pa_init_err=0;
|
||||
|
||||
// time measurement
|
||||
// The read and write position audio stream in the audio stream are measured in ms.
|
||||
//
|
||||
//
|
||||
// * When the stream is opened, myReadPosition and myWritePosition are cleared.
|
||||
// * myWritePosition is updated in wave_write.
|
||||
// * myReadPosition is updated in pa_callback (+ sample delay).
|
||||
@@ -275,12 +286,12 @@ static void start_stream()
|
||||
PaError err;
|
||||
SHOW_TIME("start_stream");
|
||||
|
||||
my_stream_could_start=0;
|
||||
my_stream_could_start=0;
|
||||
mInCallbackFinishedState = false;
|
||||
|
||||
err = Pa_StartStream(pa_stream);
|
||||
SHOW("start_stream > Pa_StartStream=%d (%s)\n", err, Pa_GetErrorText(err));
|
||||
|
||||
|
||||
#if USE_PORTAUDIO == 19
|
||||
if(err == paStreamIsNotStopped)
|
||||
{
|
||||
@@ -337,7 +348,7 @@ static int pa_callback(void *inputBuffer, void *outputBuffer,
|
||||
memcpy(outputBuffer, myRead, aUsedMem);
|
||||
}
|
||||
char* p = (char*)outputBuffer + aUsedMem;
|
||||
memset(p, 0, n - aUsedMem);
|
||||
memset(p, 0, n - aUsedMem);
|
||||
// myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t));
|
||||
myRead = aWrite;
|
||||
}
|
||||
@@ -367,7 +378,7 @@ static int pa_callback(void *inputBuffer, void *outputBuffer,
|
||||
myRead = myBuffer + aRest;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
SHOW_TIME("pa_callback > underflow");
|
||||
aResult=1; // paComplete;
|
||||
|
||||
@@ -387,7 +398,7 @@ static int pa_callback(void *inputBuffer, void *outputBuffer,
|
||||
|
||||
size_t aUsedMem = aTopMem + aRest;
|
||||
char* p = (char*)outputBuffer + aUsedMem;
|
||||
memset(p, 0, n - aUsedMem);
|
||||
memset(p, 0, n - aUsedMem);
|
||||
// myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t));
|
||||
myRead = aWrite;
|
||||
}
|
||||
@@ -498,8 +509,8 @@ static int wave_open_sound()
|
||||
//paClipOff | paDitherOff,
|
||||
paNoFlag,
|
||||
pa_callback, (void *)userdata);
|
||||
|
||||
SHOW("wave_open_sound > Pa_OpenDefaultStream(1): err=%d (%s)\n",err, Pa_GetErrorText(err));
|
||||
|
||||
SHOW("wave_open_sound > Pa_OpenDefaultStream(1): err=%d (%s)\n",err, Pa_GetErrorText(err));
|
||||
|
||||
if(err == paInvalidChannelCount)
|
||||
{
|
||||
@@ -544,7 +555,7 @@ static int wave_open_sound()
|
||||
// paClipOff | paDitherOff,
|
||||
pa_callback,
|
||||
(void *)userdata);
|
||||
if ((err!=paNoError)
|
||||
if ((err!=paNoError)
|
||||
&& (err!=paInvalidChannelCount)) //err==paUnanticipatedHostError
|
||||
{
|
||||
fprintf(stderr, "wave_open_sound > Pa_OpenStream : err=%d (%s)\n",err,Pa_GetErrorText(err));
|
||||
@@ -600,7 +611,7 @@ static void update_output_parameters(int selectedDevice, const PaDeviceInfo *dev
|
||||
myOutputParameters.channelCount = 1;
|
||||
myOutputParameters.sampleFormat = paInt16;
|
||||
|
||||
// Latency greater than 100ms for avoiding glitches
|
||||
// Latency greater than 100ms for avoiding glitches
|
||||
// (e.g. when moving a window in a graphical desktop)
|
||||
// deviceInfo = Pa_GetDeviceInfo(selectedDevice);
|
||||
if (deviceInfo)
|
||||
@@ -654,15 +665,15 @@ static void select_device(const char* the_api)
|
||||
for( i=0; i<numDevices; i++ )
|
||||
{
|
||||
deviceInfo = Pa_GetDeviceInfo( i );
|
||||
|
||||
|
||||
if (deviceInfo == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
|
||||
|
||||
|
||||
if (hostInfo && hostInfo->type == paALSA)
|
||||
{
|
||||
{
|
||||
// Check (once) the default output device
|
||||
if (defaultAlsaIndex == numDevices)
|
||||
{
|
||||
@@ -671,23 +682,23 @@ static void select_device(const char* the_api)
|
||||
update_output_parameters(defaultAlsaIndex, deviceInfo);
|
||||
if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0)
|
||||
{
|
||||
SHOW( "select_device > ALSA (default), name=%s (#%d)\n", deviceInfo->name, defaultAlsaIndex);
|
||||
SHOW( "select_device > ALSA (default), name=%s (#%d)\n", deviceInfo->name, defaultAlsaIndex);
|
||||
selectedIndex = defaultAlsaIndex;
|
||||
selectedDeviceInfo = deviceInfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if the default output device does not match,
|
||||
// look for the device with the highest number of output channels
|
||||
|
||||
// if the default output device does not match,
|
||||
// look for the device with the highest number of output channels
|
||||
SHOW( "select_device > ALSA, i=%d (numDevices=%d)\n", i, numDevices);
|
||||
|
||||
|
||||
update_output_parameters(i, deviceInfo);
|
||||
|
||||
|
||||
if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0)
|
||||
{
|
||||
SHOW( "select_device > ALSA, name=%s (#%d)\n", deviceInfo->name, i);
|
||||
|
||||
|
||||
if (!selectedDeviceInfo
|
||||
|| (selectedDeviceInfo->maxOutputChannels < deviceInfo->maxOutputChannels))
|
||||
{
|
||||
@@ -703,14 +714,14 @@ static void select_device(const char* the_api)
|
||||
{
|
||||
update_output_parameters(selectedIndex, selectedDeviceInfo);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
i = Pa_GetDefaultOutputDevice();
|
||||
deviceInfo = Pa_GetDeviceInfo( i );
|
||||
update_output_parameters(i, deviceInfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
//>
|
||||
@@ -798,18 +809,18 @@ void* wave_open(const char* the_api)
|
||||
//<copyBuffer
|
||||
|
||||
|
||||
static size_t copyBuffer(char* dest, char* src, const size_t theSizeInBytes)
|
||||
{
|
||||
static size_t copyBuffer(char* dest, char* src, const size_t theSizeInBytes)
|
||||
{
|
||||
size_t bytes_written = 0;
|
||||
unsigned int i = 0;
|
||||
uint16_t* a_dest = NULL;
|
||||
uint16_t* a_src = NULL;
|
||||
|
||||
|
||||
if ((src != NULL) && dest != NULL)
|
||||
{
|
||||
{
|
||||
// copy for one channel (mono)?
|
||||
if(out_channels==1)
|
||||
{
|
||||
{
|
||||
SHOW("copyBuffer > 1 channel > memcpy %x (%d bytes)\n", (int)myWrite, theSizeInBytes);
|
||||
memcpy(dest, src, theSizeInBytes);
|
||||
bytes_written = theSizeInBytes;
|
||||
@@ -820,7 +831,7 @@ static size_t copyBuffer(char* dest, char* src, const size_t theSizeInBytes)
|
||||
i = 0;
|
||||
a_dest = (uint16_t* )dest;
|
||||
a_src = (uint16_t* )src;
|
||||
|
||||
|
||||
for(i=0; i<theSizeInBytes/2; i++)
|
||||
{
|
||||
a_dest[2*i] = a_src[i];
|
||||
@@ -829,8 +840,8 @@ static size_t copyBuffer(char* dest, char* src, const size_t theSizeInBytes)
|
||||
bytes_written = 2*theSizeInBytes;
|
||||
} // end if(out_channels==1)
|
||||
} // end if ((src != NULL) && dest != NULL)
|
||||
|
||||
return bytes_written;
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
//>
|
||||
@@ -843,7 +854,7 @@ size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSiz
|
||||
// space in ringbuffer for the sample needed: 1x mono channel but 2x for 1 stereo channel
|
||||
size_t bytes_to_write = (out_channels==1) ? theSize : theSize*2;
|
||||
my_stream_could_start = 0;
|
||||
|
||||
|
||||
if(pa_stream == NULL)
|
||||
{
|
||||
SHOW_TIME("wave_write > wave_open_sound\n");
|
||||
@@ -859,16 +870,16 @@ size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSiz
|
||||
my_stream_could_start = 1;
|
||||
}
|
||||
assert(BUFFER_LENGTH >= bytes_to_write);
|
||||
|
||||
|
||||
if (myWrite >= myBuffer + BUFFER_LENGTH)
|
||||
{
|
||||
myWrite = myBuffer;
|
||||
} // end if (myWrite >= myBuffer + BUFFER_LENGTH)
|
||||
|
||||
|
||||
size_t aTotalFreeMem=0;
|
||||
char* aRead = myRead;
|
||||
SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled()))
|
||||
@@ -876,9 +887,9 @@ size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSiz
|
||||
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
aRead = myRead;
|
||||
|
||||
|
||||
// write pointer is before read pointer?
|
||||
if (myWrite >= aRead)
|
||||
{
|
||||
@@ -888,27 +899,27 @@ size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSiz
|
||||
{
|
||||
aTotalFreeMem = aRead - myWrite;
|
||||
} // end if (myWrite >= aRead)
|
||||
|
||||
|
||||
if (aTotalFreeMem>1)
|
||||
{
|
||||
// -1 because myWrite must be different of aRead
|
||||
// otherwise buffer would be considered as empty
|
||||
aTotalFreeMem -= 1;
|
||||
} // end if (aTotalFreeMem>1)
|
||||
|
||||
|
||||
if (aTotalFreeMem >= bytes_to_write)
|
||||
{
|
||||
break;
|
||||
} // end if (aTotalFreeMem >= bytes_to_write)
|
||||
|
||||
|
||||
//SHOW_TIME("wave_write > wait");
|
||||
SHOW("wave_write > wait: aTotalFreeMem=%d\n", aTotalFreeMem);
|
||||
SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);
|
||||
usleep(10000);
|
||||
} // end while (1)
|
||||
|
||||
|
||||
aRead = myRead;
|
||||
|
||||
|
||||
// write pointer is ahead the read pointer?
|
||||
if (myWrite >= aRead)
|
||||
{
|
||||
@@ -945,17 +956,17 @@ size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSiz
|
||||
SHOW_TIME("wave_write > myWrite <= aRead");
|
||||
myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize);
|
||||
} // end if (myWrite >= aRead)
|
||||
|
||||
|
||||
bytes_written = bytes_to_write;
|
||||
myWritePosition += theSize/sizeof(uint16_t); // add number of samples
|
||||
|
||||
|
||||
if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER))
|
||||
{
|
||||
start_stream();
|
||||
} // end if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER))
|
||||
|
||||
|
||||
SHOW_TIME("wave_write > LEAVE");
|
||||
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
@@ -974,7 +985,7 @@ int wave_close(void* theHandler)
|
||||
SHOW_TIME("wave_close > LEAVE (NULL stream)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if( Pa_IsStreamStopped( pa_stream ) )
|
||||
{
|
||||
SHOW_TIME("wave_close > LEAVE (stopped)");
|
||||
@@ -986,7 +997,7 @@ int wave_close(void* theHandler)
|
||||
SHOW_TIME("wave_close > LEAVE (NULL stream)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if( Pa_StreamActive( pa_stream ) == false && mInCallbackFinishedState == false )
|
||||
{
|
||||
SHOW_TIME("wave_close > LEAVE (not active)");
|
||||
@@ -1002,20 +1013,20 @@ int wave_close(void* theHandler)
|
||||
SHOW_TIME("wave_close > LEAVE (stopStreamCount)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Comment from Audacity-1.2.4b adapted to the eSpeak context.
|
||||
|
||||
// Comment from Audacity-1.2.4b adapted to the eSpeak context.
|
||||
//
|
||||
// We got here in one of two ways:
|
||||
//
|
||||
// 1. The calling program calls the espeak_Cancel function and we
|
||||
// therefore want to stop as quickly as possible.
|
||||
// 1. The calling program calls the espeak_Cancel function and we
|
||||
// therefore want to stop as quickly as possible.
|
||||
// So we use AbortStream(). If this is
|
||||
// the case the portaudio stream is still in the Running state
|
||||
// (see PortAudio state machine docs).
|
||||
//
|
||||
// 2. The callback told PortAudio to stop the stream since it had
|
||||
// reached the end of the selection.
|
||||
// The event polling thread discovered this by noticing that
|
||||
// reached the end of the selection.
|
||||
// The event polling thread discovered this by noticing that
|
||||
// wave_is_busy() returned false.
|
||||
// wave_is_busy() (which calls Pa_GetStreamActive()) will not return
|
||||
// false until all buffers have finished playing, so we can call
|
||||
@@ -1030,7 +1041,7 @@ int wave_close(void* theHandler)
|
||||
// call StopStream if the callback brought us here, and AbortStream
|
||||
// if the user brought us here.
|
||||
//
|
||||
|
||||
|
||||
#if (USE_PORTAUDIO == 19)
|
||||
if (pa_stream)
|
||||
{
|
||||
@@ -1114,14 +1125,14 @@ int wave_is_busy(void* theHandler)
|
||||
if (pa_stream)
|
||||
{
|
||||
#if USE_PORTAUDIO == 18
|
||||
active = Pa_StreamActive(pa_stream)
|
||||
active = Pa_StreamActive(pa_stream)
|
||||
&& (mInCallbackFinishedState == false);
|
||||
#else
|
||||
active = Pa_IsStreamActive(pa_stream)
|
||||
&& (mInCallbackFinishedState == false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SHOW("wave_is_busy: %d\n",active);
|
||||
|
||||
|
||||
@@ -1160,7 +1171,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time)
|
||||
|
||||
if (!time || !pa_stream)
|
||||
{
|
||||
SHOW("event get_remaining_time> %s\n","audio device not available");
|
||||
SHOW("event get_remaining_time> %s\n","audio device not available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1246,7 +1257,7 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms)
|
||||
{
|
||||
SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
|
||||
ts->tv_sec += 1;
|
||||
t_ns -= ONE_BILLION;
|
||||
t_ns -= ONE_BILLION;
|
||||
}
|
||||
ts->tv_nsec = (long int)t_ns;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user