diff options
Diffstat (limited to 'navit/support/espeak/wavegen.c')
| -rw-r--r--[-rwxr-xr-x] | navit/support/espeak/wavegen.c | 434 |
1 files changed, 286 insertions, 148 deletions
diff --git a/navit/support/espeak/wavegen.c b/navit/support/espeak/wavegen.c index a5467ca1e..057178b70 100755..100644 --- a/navit/support/espeak/wavegen.c +++ b/navit/support/espeak/wavegen.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005 to 2007 by Jonathan Duddington * + * Copyright (C) 2005 to 2013 by Jonathan Duddington * * email: jonsd@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * @@ -28,13 +28,17 @@ #include <math.h> + #include "speak_lib.h" #include "speech.h" #include "phoneme.h" #include "synthesize.h" #include "voice.h" -//#undef INCLUDE_KLATT +#include "wavegen.h" +#ifdef INCLUDE_SONIC +#include "sonic.h" +#endif #ifdef USE_PORTAUDIO #include "portaudio.h" @@ -78,12 +82,11 @@ static wavegen_peaks_t peaks[N_PEAKS]; static int peak_harmonic[N_PEAKS]; static int peak_height[N_PEAKS]; -#define N_ECHO_BUF 5500 // max of 250mS at 22050 Hz -static int echo_head; -static int echo_tail; +int echo_head; +int echo_tail; +int echo_amp = 0; +short echo_buf[N_ECHO_BUF]; static int echo_length = 0; // period (in sample\) to ensure completion of echo at the end of speech, set in WavegenSetEcho() -static int echo_amp = 0; -static short echo_buf[N_ECHO_BUF]; static int voicing; static RESONATOR rbreath[N_PEAKS]; @@ -129,55 +132,31 @@ unsigned char *out_end; int outbuf_size = 0; // the queue of operations passed to wavegen from sythesize -long wcmdq[N_WCMDQ][4]; +long64 wcmdq[N_WCMDQ][4]; int wcmdq_head=0; int wcmdq_tail=0; // pitch,speed, -int embedded_default[N_EMBEDDED_VALUES] = {0,50,170,100,50, 0,0, 0,170,0,0,0,0,0}; -static int embedded_max[N_EMBEDDED_VALUES] = {0,0x7fff,600,300,99,99,99, 0,600,0,0,0,0,4}; +int embedded_default[N_EMBEDDED_VALUES] = {0, 50,175,100,50, 0, 0, 0,175,0,0,0,0,0,0}; +static int embedded_max[N_EMBEDDED_VALUES] = {0,0x7fff,750,300,99,99,99, 0,750,0,0,0,0,4,0}; #define N_CALLBACK_IX N_WAV_BUF-2 // adjust this delay to match display with the currently spoken word int current_source_index=0; extern FILE *f_wave; - +#ifdef USE_PORTAUDIO #if (USE_PORTAUDIO == 18) static PortAudioStream *pa_stream=NULL; #endif #if (USE_PORTAUDIO == 19) static PaStream *pa_stream=NULL; #endif +#endif -/* default pitch envelope, a steady fall */ -#define ENV_LEN 128 - -#define int(x) (int)(x) -/* -unsigned char Pitch_env0[ENV_LEN] = { - 255,253,251,249,247,245,243,241,239,237,235,233,231,229,227,225, - 223,221,219,217,215,213,211,209,207,205,203,201,199,197,195,193, - 191,189,187,185,183,181,179,177,175,173,171,169,167,165,163,161, - 159,157,155,153,151,149,147,145,143,141,139,137,135,133,131,129, - 127,125,123,121,119,117,115,113,111,109,107,105,103,101, 99, 97, - 95, 93, 91, 89, 87, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67, 65, - 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, - 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1 -}; -*/ - -/* -unsigned char Pitch_long[ENV_LEN] = { - 254,249,250,251,252,253,254,254, 255,255,255,255,254,254,253,252, - 251,250,249,247,244,242,238,234, 230,225,221,217,213,209,206,203, - 199,195,191,187,183,179,175,172, 168,165,162,159,156,153,150,148, - 145,143,140,138,136,134,132,130, 128,126,123,120,117,114,111,107, - 104,100,96,91, 86,82,77,73, 70,66,63,60, 58,55,53,51, - 49,47,46,45, 43,42,40,38, 36,34,31,28, 26,24,22,20, - 18,16,14,12, 11,10,9,8, 8,8,8,8, 9,8,8,8, - 8,8,7,7, 6,6,6,5, 4,4,3,3, 2,1,1,0 -}; -*/ +#ifdef INCLUDE_SONIC +static sonicStream sonicSpeedupStream = NULL; +double sonicSpeed = 1.0; +#endif // 1st index=roughness // 2nd index=modulation_type @@ -267,7 +246,7 @@ static unsigned char wavemult[N_WAVEMULT] = { 105, 98, 90, 83, 76, 69, 62, 55, 49, 43, 37, 32, 27, 22, 18, 14, 11, 8, 5, 3, 2, 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 }; - + // set from y = pow(2,x) * 128, x=-1 to 1 unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1] = { @@ -285,12 +264,13 @@ unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1] = { 217,220,223,226,229,232,236,239, 242,246,249,252, 254,255 }; -int WavegenFill(int fill_zeros); - #ifdef LOG_FRAMES -static void LogMarker(int type, int value) -{//======================================= +static void LogMarker(int type, int value, int value2) +{//=================================================== + char buf[20]; + int *p; + if(option_log_frames == 0) return; @@ -300,7 +280,13 @@ static void LogMarker(int type, int value) if(f_log) { if(type == espeakEVENT_PHONEME) - fprintf(f_log,"Phoneme [%s]\n",WordToString(value)); + { + p = (int *)buf; + p[0] = value; + p[1] = value2; + buf[8] = 0; + fprintf(f_log,"Phoneme [%s]\n", buf); + } else fprintf(f_log,"\n"); fclose(f_log); @@ -310,17 +296,28 @@ static void LogMarker(int type, int value) } #endif -void WcmdqStop() +void WcmdqStop(void) {//============= wcmdq_head = 0; wcmdq_tail = 0; + +#ifdef INCLUDE_SONIC + if(sonicSpeedupStream != NULL) + { + sonicDestroyStream(sonicSpeedupStream); + sonicSpeedupStream = NULL; + } +#endif + #ifdef USE_PORTAUDIO Pa_AbortStream(pa_stream); #endif + if(mbrola_name[0] != 0) + MbrolaReset(); } -int WcmdqFree() +int WcmdqFree(void) {//============ int i; i = wcmdq_head - wcmdq_tail; @@ -328,19 +325,19 @@ int WcmdqFree() return(i); } -int WcmdqUsed() +int WcmdqUsed(void) {//============ return(N_WCMDQ - WcmdqFree()); } -void WcmdqInc() +void WcmdqInc(void) {//============ wcmdq_tail++; if(wcmdq_tail >= N_WCMDQ) wcmdq_tail=0; } -static void WcmdqIncHead() +static void WcmdqIncHead(void) {//======================= wcmdq_head++; if(wcmdq_head >= N_WCMDQ) wcmdq_head=0; @@ -350,12 +347,14 @@ static void WcmdqIncHead() // data points from which to make the presets for pk_shape1 and pk_shape2 #define PEAKSHAPEW 256 +#ifdef deleted static const float pk_shape_x[2][8] = { {0,-0.6f, 0.0f, 0.6f, 1.4f, 2.5f, 4.5f, 5.5f}, {0,-0.6f, 0.0f, 0.6f, 1.4f, 2.0f, 4.5f, 5.5f }}; static const float pk_shape_y[2][8] = { {0, 67, 81, 67, 31, 14, 0, -6} , {0, 77, 81, 77, 31, 7, 0, -6 }}; +#endif unsigned char pk_shape1[PEAKSHAPEW+1] = { 255,254,254,254,254,254,253,253,252,251,251,250,249,248,247,246, @@ -440,6 +439,10 @@ static int userdata[4]; static PaError pa_init_err=0; static int out_channels=1; +unsigned char *outbuffer = NULL; +int outbuffer_size = 0; + + #if USE_PORTAUDIO == 18 static int WaveCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) @@ -452,9 +455,30 @@ static int WaveCallback(const void *inputBuffer, void *outputBuffer, int ix; int result; unsigned char *p; + unsigned char *out_buf; + unsigned char *out_end2; + int pa_size; - out_ptr = out_start = (unsigned char *)outputBuffer; - out_end = out_ptr + framesPerBuffer*2; + pa_size = framesPerBuffer*2; + + // make a buffer 3x size of the portaudio output + ix = pa_size*3; + if(ix > outbuffer_size) + { + outbuffer = (unsigned char *)realloc(outbuffer, ix); + if(outbuffer == NULL) + { + fprintf(stderr, "espeak: out of memory\n"); + } + outbuffer_size = ix; + out_ptr = NULL; + } + if(out_ptr == NULL) + { + out_ptr = out_start = outbuffer; + out_end = out_start + outbuffer_size; + } + out_end2 = &outbuffer[pa_size]; // top of data needed for the portaudio buffer #ifdef LIBRARY event_list_ix = 0; @@ -462,6 +486,24 @@ static int WaveCallback(const void *inputBuffer, void *outputBuffer, result = WavegenFill(1); + // copy from the outbut buffer into the portaudio buffer + if(result && (out_ptr > out_end2)) + { + result = 0; // don't end yet, there is more data in the buffer than can fit in portaudio + } + + while(out_ptr < out_end2) + *out_ptr++ = 0; // fill with zeros up to the size of the portaudio buffer + + memcpy(outputBuffer, outbuffer, pa_size); + + // move the remaining contents of the start of the output buffer + for(p = out_end2; p < out_end; p++) + { + p[-pa_size] = p[0]; + } + out_ptr -= pa_size; + #ifdef LIBRARY count_samples += framesPerBuffer; if(synth_callback) @@ -482,14 +524,15 @@ static int WaveCallback(const void *inputBuffer, void *outputBuffer, { // swap the order of bytes in each sound sample in the portaudio buffer int c; - out_ptr = (unsigned char *)outputBuffer; - out_end = out_ptr + framesPerBuffer*2; - while(out_ptr < out_end) + unsigned char *buf_end; + out_buf = (unsigned char *)outputBuffer; + buf_end = out_buf + framesPerBuffer*2; + while(out_buf < buf_end) { - c = out_ptr[0]; - out_ptr[0] = out_ptr[1]; - out_ptr[1] = c; - out_ptr += 2; + c = out_buf[0]; + out_buf[0] = out_buf[1]; + out_buf[1] = c; + out_buf += 2; } } #endif @@ -498,12 +541,12 @@ static int WaveCallback(const void *inputBuffer, void *outputBuffer, { // sound output can only do stereo, not mono. Duplicate each sound sample to // produce 2 channels. - out_ptr = (unsigned char *)outputBuffer; + out_buf = (unsigned char *)outputBuffer; for(ix=framesPerBuffer-1; ix>=0; ix--) { - p = &out_ptr[ix*4]; - p[3] = p[1] = out_ptr[ix*2 + 1]; - p[2] = p[0] = out_ptr[ix*2]; + p = &out_buf[ix*4]; + p[3] = p[1] = out_buf[ix*2 + 1]; + p[2] = p[0] = out_buf[ix*2]; } } @@ -553,7 +596,7 @@ static PaError Pa_OpenDefaultStream2( PaStream** stream, hostApiOutputParameters.device = Pa_GetDefaultOutputDevice(); if( hostApiOutputParameters.device == paNoDevice ) - return paDeviceUnavailable; + return paDeviceUnavailable; hostApiOutputParameters.channelCount = outputChannelCount; hostApiOutputParameters.sampleFormat = sampleFormat; @@ -574,7 +617,7 @@ static PaError Pa_OpenDefaultStream2( PaStream** stream, #endif -int WavegenOpenSound() +int WavegenOpenSound(void) {//=================== PaError err, err2; PaError active; @@ -639,7 +682,7 @@ int WavegenOpenSound() -int WavegenCloseSound() +int WavegenCloseSound(void) {//==================== PaError active; @@ -669,7 +712,7 @@ int WavegenCloseSound() } -int WavegenInitSound() +int WavegenInitSound(void) {//=================== PaError err; @@ -687,15 +730,15 @@ int WavegenInitSound() return(0); } #else -int WavegenOpenSound() +int WavegenOpenSound(void) {//=================== return(0); } -int WavegenCloseSound() +int WavegenCloseSound(void) {//==================== return(0); } -int WavegenInitSound() +int WavegenInitSound(void) {//=================== return(0); } @@ -720,7 +763,7 @@ void WavegenInit(int rate, int wavemult_fact) max_hval = 0; wdata.amplitude = 32; - wdata.prev_was_synth = 0; + wdata.amplitude_fmt = 100; for(ix=0; ix<N_EMBEDDED_VALUES; ix++) embedded_value[ix] = embedded_default[ix]; @@ -754,6 +797,7 @@ void WavegenInit(int rate, int wavemult_fact) #ifdef LOG_FRAMES remove("log-espeakedit"); +remove("log-klatt"); #endif } // end of WavegenInit @@ -794,12 +838,6 @@ static void WavegenSetEcho(void) amp = embedded_value[EMBED_H]; delay = 130; } - if(embedded_value[EMBED_T] > 0) - { - // announcing punctuation - amp = embedded_value[EMBED_T] * 8; - delay = 60; - } if(delay == 0) amp = 0; @@ -811,7 +849,7 @@ static void WavegenSetEcho(void) if(amp > 20) echo_length = echo_head * 2; // perhaps allow 2 echo periods if the echo is loud. - // echo_amp units are 1/256ths of the amplitude of the original sound. + // echo_amp units are 1/256ths of the amplitude of the original sound. echo_amp = amp; // compensate (partially) for increase in amplitude due to echo general_amplitude = GetAmplitude(); @@ -820,7 +858,7 @@ static void WavegenSetEcho(void) -int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control) +static int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control) {//============================================================================ // Calculate the amplitude of each harmonics from the formants // Only for formants 0 to 5 @@ -951,7 +989,7 @@ int h2; -static void AdvanceParameters() +static void AdvanceParameters(void) {//============================ // Called every 64 samples to increment the formant freq, height, and widths @@ -982,16 +1020,16 @@ static void AdvanceParameters() for(ix=0; ix <= wvoice->n_harmonic_peaks; ix++) { peaks[ix].freq1 += peaks[ix].freq_inc; - peaks[ix].freq = (int)(peaks[ix].freq1); + peaks[ix].freq = (int)peaks[ix].freq1; peaks[ix].height1 += peaks[ix].height_inc; - if((peaks[ix].height = (int)(peaks[ix].height1)) < 0) + if((peaks[ix].height = (int)peaks[ix].height1) < 0) peaks[ix].height = 0; peaks[ix].left1 += peaks[ix].left_inc; - peaks[ix].left = (int)(peaks[ix].left1); + peaks[ix].left = (int)peaks[ix].left1; if(ix < 3) { peaks[ix].right1 += peaks[ix].right_inc; - peaks[ix].right = (int)(peaks[ix].right1); + peaks[ix].right = (int)peaks[ix].right1; } else { @@ -1004,10 +1042,10 @@ static void AdvanceParameters() if(ix < 7) { peaks[ix].freq1 += peaks[ix].freq_inc; - peaks[ix].freq = (int)(peaks[ix].freq1); + peaks[ix].freq = (int)peaks[ix].freq1; } peaks[ix].height1 += peaks[ix].height_inc; - if((peaks[ix].height = (int)(peaks[ix].height1)) < 0) + if((peaks[ix].height = (int)peaks[ix].height1) < 0) peaks[ix].height = 0; } @@ -1086,7 +1124,7 @@ void InitBreath(void) -static void SetBreath() +static void SetBreath(void) {//==================== #ifndef PLATFORM_RISCOS int pk; @@ -1123,7 +1161,7 @@ static int ApplyBreath(void) if((amp = wvoice->breath[ix]) != 0) { amp *= (peaks[ix].height >> 14); - value += (int)(resonator(&rbreath[ix],noise) * amp); + value += (int)resonator(&rbreath[ix],noise) * amp; } } #endif @@ -1132,7 +1170,7 @@ static int ApplyBreath(void) -int Wavegen() +static int Wavegen(void) {//========== unsigned short waveph; unsigned short theta; @@ -1171,7 +1209,8 @@ int Wavegen() maxh2 = PeaksToHarmspect(peaks, wdata.pitch<<4, hspect[0], 0); // adjust amplitude to compensate for fewer harmonics at higher pitch - amplitude2 = (wdata.amplitude * wdata.pitch)/(100 << 11); +// amplitude2 = (wdata.amplitude * wdata.pitch)/(100 << 11); + amplitude2 = (wdata.amplitude * (wdata.pitch >> 8) * wdata.amplitude_fmt)/(10000 << 3); // switch sign of harmonics above about 900Hz, to reduce max peak amplitude h_switch_sign = 890 / (wdata.pitch >> 12); @@ -1220,11 +1259,12 @@ int Wavegen() for(pk=wvoice->n_harmonic_peaks+1; pk<N_PEAKS; pk++) { // find the nearest harmonic for HF peaks where we don't use shape - peak_harmonic[pk] = peaks[pk].freq / (wdata.pitch*16); + peak_harmonic[pk] = ((peaks[pk].freq / (wdata.pitch*8)) + 1) / 2; } // adjust amplitude to compensate for fewer harmonics at higher pitch - amplitude2 = (wdata.amplitude * wdata.pitch)/(100 << 11); +// amplitude2 = (wdata.amplitude * wdata.pitch)/(100 << 11); + amplitude2 = (wdata.amplitude * (wdata.pitch >> 8) * wdata.amplitude_fmt)/(10000 << 3); if(glottal_flag > 0) { @@ -1321,12 +1361,12 @@ int Wavegen() for(h=1; h<=h_switch_sign; h++) { - total += ((int)(sin_tab[theta >> 5]) * harmspect[h]); + total += ((int)sin_tab[theta >> 5] * harmspect[h]); theta += waveph; } while(h<=maxh) { - total -= ((int)(sin_tab[theta >> 5]) * harmspect[h]); + total -= ((int)sin_tab[theta >> 5] * harmspect[h]); theta += waveph; h++; } @@ -1351,17 +1391,20 @@ int Wavegen() if(wdata.mix_wave_scale == 0) { // a 16 bit sample - c = wdata.mix_wavefile[wdata.mix_wavefile_ix+1]; - sample = wdata.mix_wavefile[wdata.mix_wavefile_ix] + (c * 256); + c = wdata.mix_wavefile[wdata.mix_wavefile_ix+wdata.mix_wavefile_offset+1]; + sample = wdata.mix_wavefile[wdata.mix_wavefile_ix+wdata.mix_wavefile_offset] + (c * 256); wdata.mix_wavefile_ix += 2; } else { // a 8 bit sample, scaled - sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_ix++] * wdata.mix_wave_scale; + sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_offset+wdata.mix_wavefile_ix++] * wdata.mix_wave_scale; } z2 = (sample * wdata.amplitude_v) >> 10; z2 = (z2 * wdata.mix_wave_amp)/32; + + if((wdata.mix_wavefile_ix + wdata.mix_wavefile_offset) >= wdata.mix_wavefile_max) // reached the end of available WAV data + wdata.mix_wavefile_offset -= (wdata.mix_wavefile_max*3)/4; } z1 = z2 + (((total>>8) * amplitude2) >> 13); @@ -1406,11 +1449,12 @@ static int PlaySilence(int length, int resume) static int n_samples; int value=0; - if(length == 0) - return(0); - nsamples = 0; samplecount = 0; + wavephase = 0x7fffffff; + + if(length == 0) + return(0); if(resume==0) n_samples = length; @@ -1507,14 +1551,38 @@ static int SetWithRange0(int value, int max) } +static void SetPitchFormants(void) +{//=========================== + int ix; + int factor = 256; + int pitch_value; + + // adjust formants to give better results for a different voice pitch + if((pitch_value = embedded_value[EMBED_P]) > MAX_PITCH_VALUE) + pitch_value = MAX_PITCH_VALUE; + + if(pitch_value > 50) + { + // only adjust if the pitch is higher than normal + factor = 256 + (25 * (pitch_value - 50))/50; + } + + for(ix=0; ix<=5; ix++) + { + wvoice->freq[ix] = (wvoice->freq2[ix] * factor)/256; + } + + factor = embedded_value[EMBED_T]*3; + wvoice->height[0] = (wvoice->height2[0] * (256 - factor*2))/256; + wvoice->height[1] = (wvoice->height2[1] * (256 - factor))/256; +} + + void SetEmbedded(int control, int value) {//===================================== // there was an embedded command in the text at this point int sign=0; int command; - int ix; - int factor; - int pitch_value; command = control & 0x1f; if((control & 0x60) == 0x60) @@ -1537,25 +1605,14 @@ void SetEmbedded(int control, int value) case EMBED_T: WavegenSetEcho(); // and drop through to case P case EMBED_P: - // adjust formants to give better results for a different voice pitch - if((pitch_value = embedded_value[EMBED_P]) > MAX_PITCH_VALUE) - pitch_value = MAX_PITCH_VALUE; - - factor = 256 + (25 * (pitch_value - 50))/50; - for(ix=0; ix<=5; ix++) - { - wvoice->freq[ix] = (wvoice->freq2[ix] * factor)/256; - } - factor = embedded_value[EMBED_T]*3; - wvoice->height[0] = (wvoice->height2[0] * (256 - factor*2))/256; - wvoice->height[1] = (wvoice->height2[1] * (256 - factor))/256; + SetPitchFormants(); break; case EMBED_A: // amplitude general_amplitude = GetAmplitude(); break; - case EMBED_F: // emphasiis + case EMBED_F: // emphasis general_amplitude = GetAmplitude(); break; @@ -1585,6 +1642,9 @@ void WavegenSetVoice(voice_t *v) option_harmonic1 = 6; } WavegenSetEcho(); + SetPitchFormants(); + MarkerEvent(espeakEVENT_SAMPLERATE, 0, wvoice->samplerate, 0, out_ptr); +// WVoiceChanged(wvoice); } @@ -1629,12 +1689,12 @@ void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pit // compensate for change in pitch when the range is narrowed or widened base -= (range - voice->pitch_range)*18; - *pitch_base = base + (pitch1 * range); - *pitch_range = base + (pitch2 * range) - *pitch_base; + *pitch_base = base + (pitch1 * range)/2; + *pitch_range = base + (pitch2 * range)/2 - *pitch_base; } -void SetPitch(int length, unsigned char *env, int pitch1, int pitch2) +static void SetPitch(int length, unsigned char *env, int pitch1, int pitch2) {//================================================================== // length in samples @@ -1671,7 +1731,7 @@ if(option_log_frames) -void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v) +static void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v) {//======================================================================== int ix; DOUBLEX next; @@ -1692,7 +1752,7 @@ if(option_log_frames) fprintf(f_log,"%3dmS %3d %3d %4d %4d (%3d %3d %3d %3d) to %3d %3d %4d %4d (%3d %3d %3d %3d)\n",length*1000/samplerate, fr1->ffreq[0],fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3], fr1->fheight[0],fr1->fheight[1],fr1->fheight[2],fr1->fheight[3], fr2->ffreq[0],fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3], fr2->fheight[0],fr2->fheight[1],fr2->fheight[2],fr2->fheight[3] ); - + fclose(f_log); f_log=NULL; } @@ -1751,27 +1811,27 @@ if(option_log_frames) if(ix < 7) { peaks[ix].freq1 = (fr1->ffreq[ix] * v->freq[ix] + v->freqadd[ix]*256) << 8; - peaks[ix].freq = (int)(peaks[ix].freq1); + peaks[ix].freq = (int)peaks[ix].freq1; next = (fr2->ffreq[ix] * v->freq[ix] + v->freqadd[ix]*256) << 8; peaks[ix].freq_inc = ((next - peaks[ix].freq1) * (STEPSIZE/4)) / length4; // lower headroom for fixed point math } peaks[ix].height1 = (fr1->fheight[ix] * v->height[ix]) << 6; - peaks[ix].height = (int)(peaks[ix].height1); + peaks[ix].height = (int)peaks[ix].height1; next = (fr2->fheight[ix] * v->height[ix]) << 6; peaks[ix].height_inc = ((next - peaks[ix].height1) * STEPSIZE) / length2; - if(ix <= wvoice->n_harmonic_peaks) + if((ix <= 5) && (ix <= wvoice->n_harmonic_peaks)) { peaks[ix].left1 = (fr1->fwidth[ix] * v->width[ix]) << 10; - peaks[ix].left = int(peaks[ix].left1); + peaks[ix].left = (int)peaks[ix].left1; next = (fr2->fwidth[ix] * v->width[ix]) << 10; peaks[ix].left_inc = ((next - peaks[ix].left1) * STEPSIZE) / length2; if(ix < 3) { peaks[ix].right1 = (fr1->fright[ix] * v->width[ix]) << 10; - peaks[ix].right = int(peaks[ix].right1); + peaks[ix].right = (int)peaks[ix].right1; next = (fr2->fright[ix] * v->width[ix]) << 10; peaks[ix].right_inc = ((next - peaks[ix].right1) * STEPSIZE) / length2; } @@ -1806,24 +1866,19 @@ void Write4Bytes(FILE *f, int value) - -int WavegenFill(int fill_zeros) +static int WavegenFill2(int fill_zeros) {//============================ // Pick up next wavegen commands from the queue // return: 0 output buffer has been filled // return: 1 input command queue is now empty - long *q; + long64 *q; int length; int result; + int marker_type; static int resume=0; static int echo_complete=0; -#ifdef TEST_MBROLA - if(mbrola_name[0] != 0) - return(MbrolaFill(fill_zeros)); -#endif - while(out_ptr < out_end) { if(WcmdqUsed() <= 0) @@ -1848,7 +1903,7 @@ int WavegenFill(int fill_zeros) q = wcmdq[wcmdq_head]; length = q[1]; - switch(q[0]) + switch(q[0] & 0xff) { case WCMD_PITCH: SetPitch(length,(unsigned char *)q[2],q[3] >> 16,q[3] & 0xffff); @@ -1860,14 +1915,19 @@ int WavegenFill(int fill_zeros) echo_complete -= length; } wdata.n_mix_wavefile = 0; - wdata.prev_was_synth = 0; + wdata.amplitude_fmt = 100; +#ifdef INCLUDE_KLATT + KlattReset(1); +#endif result = PlaySilence(length,resume); break; case WCMD_WAVE: echo_complete = echo_length; wdata.n_mix_wavefile = 0; - wdata.prev_was_synth = 0; +#ifdef INCLUDE_KLATT + KlattReset(1); +#endif result = PlayWave(length,resume,(unsigned char*)q[2], q[3] & 0xff, q[3] >> 8); break; @@ -1875,11 +1935,15 @@ int WavegenFill(int fill_zeros) // wave file to be played at the same time as synthesis wdata.mix_wave_amp = q[3] >> 8; wdata.mix_wave_scale = q[3] & 0xff; + wdata.n_mix_wavefile = (length & 0xffff); + wdata.mix_wavefile_max = (length >> 16) & 0xffff; if(wdata.mix_wave_scale == 0) - wdata.n_mix_wavefile = length*2; - else - wdata.n_mix_wavefile = length; + { + wdata.n_mix_wavefile *= 2; + wdata.mix_wavefile_max *= 2; + } wdata.mix_wavefile_ix = 0; + wdata.mix_wavefile_offset = 0; wdata.mix_wavefile = (unsigned char *)q[2]; break; @@ -1900,13 +1964,14 @@ int WavegenFill(int fill_zeros) #endif case WCMD_MARKER: - MarkerEvent(q[1],q[2],q[3],out_ptr); + marker_type = q[0] >> 8; + MarkerEvent(marker_type, q[1],q[2],q[3],out_ptr); #ifdef LOG_FRAMES - LogMarker(q[1],q[3]); + LogMarker(marker_type, q[2], q[3]); #endif - if(q[1] == 1) + if(marker_type == 1) // word marker { - current_source_index = q[2] & 0xffffff; + current_source_index = q[1] & 0xffffff; } break; @@ -1915,13 +1980,28 @@ int WavegenFill(int fill_zeros) break; case WCMD_VOICE: - WavegenSetVoice((voice_t *)q[1]); - free((voice_t *)q[1]); + WavegenSetVoice((voice_t *)q[2]); + free((voice_t *)q[2]); break; case WCMD_EMBEDDED: SetEmbedded(q[1],q[2]); break; + + case WCMD_MBROLA_DATA: + result = MbrolaFill(length, resume, (general_amplitude * wvoice->voicing)/64); + break; + + case WCMD_FMT_AMPLITUDE: + if((wdata.amplitude_fmt = q[1]) == 0) + wdata.amplitude_fmt = 100; // percentage, but value=0 means 100% + break; + +#ifdef INCLUDE_SONIC + case WCMD_SONIC_SPEED: + sonicSpeed = (double)q[1] / 1024; + break; +#endif } if(result==0) @@ -1936,6 +2016,64 @@ int WavegenFill(int fill_zeros) } return(0); -} // end of WavegenFill +} // end of WavegenFill2 +#ifdef INCLUDE_SONIC +/* Speed up the audio samples with libsonic. */ +static int SpeedUp(short *outbuf, int length_in, int length_out, int end_of_text) +{//============================================================================== + if(length_in >0) + { + if(sonicSpeedupStream == NULL) + { + sonicSpeedupStream = sonicCreateStream(22050, 1); + } + if(sonicGetSpeed(sonicSpeedupStream) != sonicSpeed) + { + sonicSetSpeed(sonicSpeedupStream, sonicSpeed); + } + + sonicWriteShortToStream(sonicSpeedupStream, outbuf, length_in); + } + + if(sonicSpeedupStream == NULL) + return(0); + + if(end_of_text) + { + sonicFlushStream(sonicSpeedupStream); + } + return sonicReadShortFromStream(sonicSpeedupStream, outbuf, length_out); +} // end of SpeedUp +#endif + + +/* Call WavegenFill2, and then speed up the output samples. */ +int WavegenFill(int fill_zeros) +{//============================ + int finished; + unsigned char *p_start; + + p_start = out_ptr; + + // fill_zeros is ignored. It is now done in the portaudio callback + finished = WavegenFill2(0); + +#ifdef INCLUDE_SONIC + if(sonicSpeed > 1.0) + { + int length; + int max_length; + + max_length = (out_end - p_start); + length = 2*SpeedUp((short *)p_start, (out_ptr-p_start)/2, max_length/2, finished); + out_ptr = p_start + length; + + if(length >= max_length) + finished = 0; // there may be more data to flush + } +#endif + return finished; +} // end of WavegenFill + |
