From 5e502661d64ceb5e96b8279eee52f8969b53eab8 Mon Sep 17 00:00:00 2001 From: datajake1999 Date: Sun, 6 Dec 2020 08:34:38 -0800 Subject: [PATCH] Add speechPlayer Klatt implementation as Klatt 6. --- Makefile.am | 22 +- configure.ac | 13 ++ docs/building.md | 5 +- espeak-ng-data/voices/!v/edward2 | 10 + espeak-ng-data/voices/!v/klatt6 | 4 + src/libespeak-ng/klatt.c | 16 ++ src/libespeak-ng/sPlayer.c | 143 ++++++++++++ src/libespeak-ng/sPlayer.h | 20 ++ src/speak-ng.cpp | 1 + src/speechPlayer/include/speechPlayer.h | 67 ++++++ src/speechPlayer/src/frame.cpp | 131 +++++++++++ src/speechPlayer/src/frame.h | 55 +++++ src/speechPlayer/src/sample.h | 24 ++ src/speechPlayer/src/speechPlayer.cpp | 55 +++++ src/speechPlayer/src/speechPlayer.h | 37 ++++ src/speechPlayer/src/speechWaveGenerator.cpp | 221 +++++++++++++++++++ src/speechPlayer/src/speechWaveGenerator.h | 27 +++ src/speechPlayer/src/utils.h | 37 ++++ src/speechPlayer/src/waveGenerator.h | 27 +++ src/windows/libespeak-ng.vcxproj | 21 +- tests/dummy.cpp | 3 + 21 files changed, 928 insertions(+), 11 deletions(-) create mode 100644 espeak-ng-data/voices/!v/edward2 create mode 100644 espeak-ng-data/voices/!v/klatt6 create mode 100644 src/libespeak-ng/sPlayer.c create mode 100644 src/libespeak-ng/sPlayer.h create mode 100644 src/speak-ng.cpp create mode 100644 src/speechPlayer/include/speechPlayer.h create mode 100644 src/speechPlayer/src/frame.cpp create mode 100644 src/speechPlayer/src/frame.h create mode 100644 src/speechPlayer/src/sample.h create mode 100644 src/speechPlayer/src/speechPlayer.cpp create mode 100644 src/speechPlayer/src/speechPlayer.h create mode 100644 src/speechPlayer/src/speechWaveGenerator.cpp create mode 100644 src/speechPlayer/src/speechWaveGenerator.h create mode 100644 src/speechPlayer/src/utils.h create mode 100644 src/speechPlayer/src/waveGenerator.h create mode 100644 tests/dummy.cpp diff --git a/Makefile.am b/Makefile.am index 48c02b3f..210680cb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ MKDIR=mkdir -p # -Wno-endif-labels : Needed to prevent warnings in ieee80.c. AM_CFLAGS = \ - -Isrc/include -Isrc/include/compat -I$(srcdir)/src/ucd-tools/src/include \ + -Isrc/include -Isrc/include/compat -I$(srcdir)/src/speechPlayer/include -I$(srcdir)/src/ucd-tools/src/include \ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L \ -Wno-endif-labels @@ -171,6 +171,7 @@ src_libespeak_ng_la_SOURCES = \ src/libespeak-ng/wavegen.c noinst_HEADERS = \ + src/speechPlayer/include/speechPlayer.h src/ucd-tools/src/include/ucd/ucd.h if OPT_KLATT @@ -178,6 +179,17 @@ src_libespeak_ng_la_CFLAGS += -DINCLUDE_KLATT src_libespeak_ng_la_SOURCES += src/libespeak-ng/klatt.c endif +if OPT_SPEECHPLAYER +src_libespeak_ng_la_CFLAGS += -DINCLUDE_SPEECHPLAYER +src_libespeak_ng_la_SOURCES += src/libespeak-ng/sPlayer.c +src_libespeak_ng_la_SOURCES += src/speechPlayer/src/frame.cpp +src_libespeak_ng_la_SOURCES += src/speechPlayer/src/speechPlayer.cpp +src_libespeak_ng_la_SOURCES += src/speechPlayer/src/speechWaveGenerator.cpp +src_speak_ng_SOURCES = src/speak-ng.cpp +else +src_speak_ng_SOURCES = src/speak-ng.c +endif + if OPT_MBROLA src_libespeak_ng_la_CFLAGS += -DINCLUDE_MBROLA src_libespeak_ng_la_SOURCES += src/libespeak-ng/mbrowrap.c @@ -200,7 +212,6 @@ endif src_speak_ng_LDADD = src/libespeak-ng.la src_speak_ng_LDFLAGS = -static -lm ${PCAUDIOLIB_LIBS} src_speak_ng_CFLAGS = -Isrc/libespeak-ng ${AM_CFLAGS} -src_speak_ng_SOURCES = src/speak-ng.c bin_PROGRAMS += src/espeak-ng @@ -276,6 +287,13 @@ tests_ssml_fuzzer_test_CFLAGS = ${AM_CFLAGS} tests_ssml_fuzzer_test_SOURCES = tests/ssml-fuzzer.c tests_ssml_fuzzer_test_LDADD = src/libespeak-ng.la +if OPT_SPEECHPLAYER +tests_api_test_SOURCES += tests/dummy.cpp +tests_encoding_test_SOURCES += tests/dummy.cpp +tests_readclause_test_SOURCES += tests/dummy.cpp +tests_ssml_fuzzer_test_SOURCES += tests/dummy.cpp +endif + if HAVE_LIBFUZZER tests_ssml_fuzzer_test_CFLAGS += -fsanitize=fuzzer tests_ssml_fuzzer_test_LDFLAGS = -fsanitize=fuzzer diff --git a/configure.ac b/configure.ac index a333ab93..a7e925d8 100644 --- a/configure.ac +++ b/configure.ac @@ -32,6 +32,10 @@ AC_ARG_WITH([klatt], [AS_HELP_STRING([--with-klatt], [enable the Klatt formant synthesizer @<:@default=yes@:>@])], []) +AC_ARG_WITH([speechplayer], + [AS_HELP_STRING([--with-speechplayer], [enable the speechPlayer Klatt implementation @<:@default=yes@:>@])], + []) + AC_ARG_WITH([mbrola], [AS_HELP_STRING([--with-mbrola], [enable the MBROLA speech synthesizer @<:@default=yes@:>@])], []) @@ -65,6 +69,7 @@ dnl Program checks. dnl ================================================================ AC_PROG_CC +AC_PROG_CXX AC_PROG_MAKE_SET AC_PROG_LIBTOOL AC_PROG_LN_S @@ -221,6 +226,12 @@ else have_klatt=yes fi +if test "$with_speechplayer" = "no" ; then + have_speechplayer=no +else + have_speechplayer=yes +fi + if test "$with_mbrola" = "no" ; then have_mbrola=no else @@ -246,6 +257,7 @@ else fi AM_CONDITIONAL(OPT_KLATT, [test x"$have_klatt" = xyes]) +AM_CONDITIONAL(OPT_SPEECHPLAYER, [test x"$have_speechplayer" = xyes]) AM_CONDITIONAL(OPT_MBROLA, [test x"$have_mbrola" = xyes]) AM_CONDITIONAL(OPT_ASYNC, [test x"$have_async" = xyes]) @@ -341,6 +353,7 @@ AC_MSG_NOTICE([ ndk-build (Android): ${NDKBUILD_CHECK} Klatt: ${have_klatt} + speechPlayer: ${have_speechplayer} MBROLA: ${have_mbrola} Async: ${have_async} diff --git a/docs/building.md b/docs/building.md index d5830536..858b14ef 100644 --- a/docs/building.md +++ b/docs/building.md @@ -66,12 +66,14 @@ In order to build eSpeak NG, you need: 1. a functional autotools system (`make`, `autoconf`, `automake`, `libtool` and `pkg-config`); -2. a functional c compiler that supports C99 (e.g. gcc or clang). +2. a functional c compiler that supports C99 (e.g. gcc or clang). Note: if building with speechPlayer, a C++ compiler is required. Optionally, you need: 1. the [pcaudiolib](https://github.com/espeak-ng/pcaudiolib) development library to enable audio output; +2. the speechPlayer development library to + enable the speechPlayer Klatt implementation; 3. the [sonic](https://github.com/espeak-ng/sonic) development library to enable sonic audio speed up support; 4. the `ronn` man-page markdown processor to build the man pages. @@ -186,6 +188,7 @@ The following `configure` options control which eSpeak NG features are enabled: | Option | Description | Default | |-----------------|----------------------------------------------|---------| | `--with-klatt` | Enable Klatt formant synthesis. | yes | +| `--with-speechplayer` | Enable the speechPlayer Klatt implementation. | yes | | `--with-mbrola` | Enable MBROLA voice support. | yes | | `--with-sonic` | Use the sonic library to support higher WPM. | yes | | `--with-async` | Enable asynchronous commands. | yes | diff --git a/espeak-ng-data/voices/!v/edward2 b/espeak-ng-data/voices/!v/edward2 new file mode 100644 index 00000000..abee6aaa --- /dev/null +++ b/espeak-ng-data/voices/!v/edward2 @@ -0,0 +1,10 @@ +language variant +name Edward2 +klatt 6 +voicing 100 +consonants 70 80 + +formant 1 92 100 130 +formant 2 103 100 80 +formant 3 103 100 70 +formant 4 114 100 60 diff --git a/espeak-ng-data/voices/!v/klatt6 b/espeak-ng-data/voices/!v/klatt6 new file mode 100644 index 00000000..7656ab35 --- /dev/null +++ b/espeak-ng-data/voices/!v/klatt6 @@ -0,0 +1,4 @@ +language variant +name klatt6 +klatt 6 + diff --git a/src/libespeak-ng/klatt.c b/src/libespeak-ng/klatt.c index 335b218f..35e5d0dd 100644 --- a/src/libespeak-ng/klatt.c +++ b/src/libespeak-ng/klatt.c @@ -37,6 +37,9 @@ #include "klatt.h" #include "synthesize.h" // for frame_t, WGEN_DATA, STEPSIZE, N_KLATTP, echo... #include "voice.h" // for voice_t, N_PEAKS +#ifdef INCLUDE_SPEECHPLAYER +#include "sPlayer.h" +#endif extern unsigned char *out_ptr; extern unsigned char *out_end; @@ -433,6 +436,10 @@ void KlattReset(int control) { int r_ix; +#ifdef INCLUDE_SPEECHPLAYER + KlattResetSP(); +#endif + if (control == 2) { // Full reset kt_globals.FLPhz = (950 * kt_globals.samrate) / 10000; @@ -848,6 +855,11 @@ static double klattp_inc[N_KLATTP]; int Wavegen_Klatt(int length, int resume, frame_t *fr1, frame_t *fr2, WGEN_DATA *wdata, voice_t *wvoice) { +#ifdef INCLUDE_SPEECHPLAYER + if(wvoice->klattv[0] == 6) + return Wavegen_KlattSP(wdata, wvoice, length, resume, fr1, fr2); +#endif + if (resume == 0) SetSynth_Klatt(length, fr1, fr2, wvoice, 1); @@ -1064,6 +1076,10 @@ void KlattInit() int ix; +#ifdef INCLUDE_SPEECHPLAYER + KlattInitSP(); +#endif + sample_count = 0; kt_globals.synthesis_model = CASCADE_PARALLEL; diff --git a/src/libespeak-ng/sPlayer.c b/src/libespeak-ng/sPlayer.c new file mode 100644 index 00000000..c7d8ca28 --- /dev/null +++ b/src/libespeak-ng/sPlayer.c @@ -0,0 +1,143 @@ +#include +#include +#include "sPlayer.h" + +extern unsigned char *out_ptr; +extern unsigned char *out_end; + +static speechPlayer_handle_t speechPlayerHandle=NULL; +static const unsigned int minFadeLength=110; + +static int MAX(int a, int b) { return((a) > (b) ? a : b); } +static int MIN(int a, int b) { return((a) < (b) ? a : b); } + +static bool needsMixWaveFile(WGEN_DATA *wdata) { + return (bool)wdata->n_mix_wavefile; +} + +// mixes the currently queued espeak consonant wave file into the existing content in the given sample buffer. +// This would be used for voiced consonants where the voiced part is generated by speechPlayer, but the consonant comes from a wave file in eSpeak. +// e.g. z, v. +// @param maxNumSamples the maximum number of samples that can be mixed into the sample buffer. +// @param sampleBuf the buffer of existing samples. +static void mixWaveFile(WGEN_DATA *wdata, unsigned int maxNumSamples, sample* sampleBuf) { + unsigned int i=0; + for(;wdata->mix_wavefile_ixn_mix_wavefile;++wdata->mix_wavefile_ix) { + if(i>=maxNumSamples) break; + int val; + if(wdata->mix_wave_scale==0) { + val=wdata->mix_wavefile[wdata->mix_wavefile_ix+wdata->mix_wavefile_offset]; + ++(wdata->mix_wavefile_ix); + signed char c=wdata->mix_wavefile[wdata->mix_wavefile_ix+wdata->mix_wavefile_offset]; + val+=(c*256); + } else { + val=(signed char)wdata->mix_wavefile[wdata->mix_wavefile_ix+wdata->mix_wavefile_offset]*wdata->mix_wave_scale; + } + val*=(wdata->amplitude_v/1024.0); + val=(val*wdata->mix_wave_amp)/40; + sampleBuf[i].value+=val; + if((wdata->mix_wavefile_ix+wdata->mix_wavefile_offset)>=wdata->mix_wavefile_max) { + wdata->mix_wavefile_offset-=(wdata->mix_wavefile_max*3)/4; + } + ++i; + } +} + +static bool isKlattFrameFollowing() { + // eSpeak implements its command queue with a circular buffer. + // Thus to walk it, we start from the head, walking to the tail, which may wrap around to the beginning of the buffer as it is circular. + for(int i=(wcmdq_head+1)%N_WCMDQ;i!=wcmdq_tail;i=(i+1)%N_WCMDQ) { + int cmd=wcmdq[i][0]; + if(cmd==WCMD_PAUSE||cmd==WCMD_WAVE) { + break; + } + if(cmd==WCMD_KLATT) { + return true; + } + } + return false; +} + +static void fillSpeechPlayerFrame(WGEN_DATA *wdata, voice_t *wvoice, frame_t * eFrame, speechPlayer_frame_t* spFrame) { + // eSpeak stores pitch in 4096ths of a hz. Specifically comments in voice.h mentions pitch<<12. + // SpeechPlayer deals with floating point values of hz. + spFrame->voicePitch=(wdata->pitch)/4096.0; + // eSpeak stores voicing amplitude with 64 representing 100% according to comments in voice.h. + // speechPlayer uses floating point value of 1 as 100%. + spFrame->voiceAmplitude=(wvoice->voicing)/64.0; + // All of eSpeak's relative formant frequency ratio values are stored with 256 representing 100% according to comments in voice.h. + spFrame->cf1=(eFrame->ffreq[1]*wvoice->freq[1]/256.0)+wvoice->freqadd[1]; + spFrame->cf2=(eFrame->ffreq[2]*wvoice->freq[2]/256.0)+wvoice->freqadd[2]; + spFrame->cf3=(eFrame->ffreq[3]*wvoice->freq[3]/256.0)+wvoice->freqadd[3]; + spFrame->cf4=(eFrame->ffreq[4]*wvoice->freq[4]/256.0)+wvoice->freqadd[4]; + spFrame->cf5=(eFrame->ffreq[5]*wvoice->freq[5]/256.0)+wvoice->freqadd[5]; + spFrame->cf6=(eFrame->ffreq[6]*wvoice->freq[6]/256.0)+wvoice->freqadd[6]; + spFrame->cfNP=200; + spFrame->cfN0=250; + if(eFrame->klattp[KLATT_FNZ]>0) { + spFrame->caNP=1; + spFrame->cfN0=eFrame->klattp[KLATT_FNZ]*2; + } else { + spFrame->caNP=0; + } + spFrame->cb1=eFrame->bw[1]*2*(wvoice->width[1]/256.0); + spFrame->cb2=eFrame->bw[2]*2*(wvoice->width[2]/256.0); + spFrame->cb3=eFrame->bw[3]*2*(wvoice->width[3]/256.0); + spFrame->cb4=eFrame->bw[4]*2*(wvoice->width[4]/256.0); + spFrame->cb5=1000; + spFrame->cb6=1000; + spFrame->cbNP=100; + spFrame->cbN0=100; + spFrame->preFormantGain=1; + spFrame->outputGain=3*(wdata->amplitude/100.0); + spFrame->endVoicePitch=spFrame->voicePitch; +} + +void KlattInitSP() { + speechPlayerHandle=speechPlayer_initialize(22050); +} + +void KlattResetSP() { + speechPlayer_terminate(speechPlayerHandle); + speechPlayerHandle=speechPlayer_initialize(22050); +} + +int Wavegen_KlattSP(WGEN_DATA *wdata, voice_t *wvoice, int length, int resume, frame_t *fr1, frame_t *fr2){ + if(!resume) { + speechPlayer_frame_t spFrame1={0}; + fillSpeechPlayerFrame(wdata, wvoice, fr1,&spFrame1); + speechPlayer_frame_t spFrame2={0}; + fillSpeechPlayerFrame(wdata, wvoice, fr2,&spFrame2); + wdata->pitch_ix+=(wdata->pitch_inc*(length/STEPSIZE)); + wdata->pitch=((wdata->pitch_env[MIN(wdata->pitch_ix>>8,127)]*wdata->pitch_range)>>8)+wdata->pitch_base; + spFrame2.endVoicePitch=wdata->pitch/4096; + bool willMixWaveFile=needsMixWaveFile(wdata); + if(willMixWaveFile) { + spFrame1.outputGain/=5; + spFrame2.outputGain/=5; + } + int mainLength=length; + speechPlayer_queueFrame(speechPlayerHandle,&spFrame1,minFadeLength,minFadeLength,-1,false); + mainLength-=minFadeLength; + bool fadeOut=!isKlattFrameFollowing(); + if(fadeOut) { + mainLength-=minFadeLength; + } + if(mainLength>=1) { + speechPlayer_queueFrame(speechPlayerHandle,&spFrame2,mainLength,mainLength,-1,false); + } + if(fadeOut) { + spFrame2.voicePitch=spFrame2.endVoicePitch; + spFrame2.preFormantGain=0; + speechPlayer_queueFrame(speechPlayerHandle,&spFrame2,minFadeLength/2,minFadeLength/2,-1,false); + spFrame2.outputGain=0; + speechPlayer_queueFrame(speechPlayerHandle,&spFrame2,minFadeLength/2,minFadeLength/2,-1,false); + } + } + unsigned int maxLength=(out_end-out_ptr)/sizeof(sample); + unsigned int outLength=speechPlayer_synthesize(speechPlayerHandle,maxLength,(sample*)out_ptr); + mixWaveFile(wdata, outLength,(sample*)out_ptr); + out_ptr=out_ptr+(sizeof(sample)*outLength); + if(out_ptr>=out_end) return 1; + return 0; +} diff --git a/src/libespeak-ng/sPlayer.h b/src/libespeak-ng/sPlayer.h new file mode 100644 index 00000000..5d64e04d --- /dev/null +++ b/src/libespeak-ng/sPlayer.h @@ -0,0 +1,20 @@ +#ifndef ESPEAK_NG_SPLAYER_H +#define ESPEAK_NG_SPLAYER_H + +#include "synthesize.h" +#include "voice.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + + void KlattInitSP(); + void KlattResetSP(); + int Wavegen_KlattSP(WGEN_DATA *wdata, voice_t *wvoice, int length, int resume, frame_t *fr1, frame_t *fr2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/speak-ng.cpp b/src/speak-ng.cpp new file mode 100644 index 00000000..2034c186 --- /dev/null +++ b/src/speak-ng.cpp @@ -0,0 +1 @@ +#include "speak-ng.c" \ No newline at end of file diff --git a/src/speechPlayer/include/speechPlayer.h b/src/speechPlayer/include/speechPlayer.h new file mode 100644 index 00000000..2f66a857 --- /dev/null +++ b/src/speechPlayer/include/speechPlayer.h @@ -0,0 +1,67 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#ifndef SPEECHPLAYER_H +#define SPEECHPLAYER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef double speechPlayer_frameParam_t; + +typedef struct { + // voicing and cascaide + speechPlayer_frameParam_t voicePitch; // fundermental frequency of voice (phonation) in hz + speechPlayer_frameParam_t vibratoPitchOffset; // pitch is offset up or down in fraction of a semitone + speechPlayer_frameParam_t vibratoSpeed; // Speed of vibrato in hz + speechPlayer_frameParam_t voiceTurbulenceAmplitude; // amplitude of voice breathiness from 0 to 1 + speechPlayer_frameParam_t glottalOpenQuotient; // fraction between 0 and 1 of a voice cycle that the glottis is open (allows voice turbulance, alters f1...) + speechPlayer_frameParam_t voiceAmplitude; // amplitude of voice (phonation) source between 0 and 1. + speechPlayer_frameParam_t aspirationAmplitude; // amplitude of aspiration (voiceless h, whisper) source between 0 and 1. + speechPlayer_frameParam_t cf1, cf2, cf3, cf4, cf5, cf6, cfN0, cfNP; // frequencies of standard cascaide formants, nasal (anti) 0 and nasal pole in hz + speechPlayer_frameParam_t cb1, cb2, cb3, cb4, cb5, cb6, cbN0, cbNP; // bandwidths of standard cascaide formants, nasal (anti) 0 and nasal pole in hz + speechPlayer_frameParam_t caNP; // amplitude from 0 to 1 of cascade nasal pole formant + // fricatives and parallel + speechPlayer_frameParam_t fricationAmplitude; // amplitude of frication noise from 0 to 1. + speechPlayer_frameParam_t pf1, pf2, pf3, pf4, pf5, pf6; // parallel formants in hz + speechPlayer_frameParam_t pb1, pb2, pb3, pb4, pb5, pb6; // parallel formant bandwidths in hz + speechPlayer_frameParam_t pa1, pa2, pa3, pa4, pa5, pa6; // amplitude of parallel formants between 0 and 1 + speechPlayer_frameParam_t parallelBypass; // amount of signal which should bypass parallel resonators from 0 to 1 + speechPlayer_frameParam_t preFormantGain; // amplitude from 0 to 1 of all vocal tract sound (voicing, frication) before entering formant resonators. Useful for stopping/starting speech + speechPlayer_frameParam_t outputGain; // amplitude from 0 to 1 of final output (master volume) + speechPlayer_frameParam_t endVoicePitch; // pitch of voice at the end of the frame length +} speechPlayer_frame_t; + +typedef short sampleVal; + +typedef struct { + sampleVal value; +} sample; + +typedef void* speechPlayer_handle_t; + +speechPlayer_handle_t speechPlayer_initialize(int sampleRate); +void speechPlayer_queueFrame(speechPlayer_handle_t playerHandle, speechPlayer_frame_t* framePtr, unsigned int minFrameDuration, unsigned int fadeDuration, int userIndex, bool purgeQueue); +int speechPlayer_synthesize(speechPlayer_handle_t playerHandle, unsigned int sampleCount, sample* sampleBuf); +int speechPlayer_getLastIndex(speechPlayer_handle_t playerHandle); +void speechPlayer_terminate(speechPlayer_handle_t playerHandle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/speechPlayer/src/frame.cpp b/src/speechPlayer/src/frame.cpp new file mode 100644 index 00000000..f841fad8 --- /dev/null +++ b/src/speechPlayer/src/frame.cpp @@ -0,0 +1,131 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#include +#include +#include "utils.h" +#include "frame.h" + +using namespace std; + +struct frameRequest_t { + unsigned int minNumSamples; + unsigned int numFadeSamples; + bool NULLFrame; + speechPlayer_frame_t frame; + double voicePitchInc; + int userIndex; +}; + +class FrameManagerImpl: public FrameManager { + private: + queue frameRequestQueue; + frameRequest_t* oldFrameRequest; + frameRequest_t* newFrameRequest; + speechPlayer_frame_t curFrame; + bool curFrameIsNULL; + unsigned int sampleCounter; + int lastUserIndex; + + void updateCurrentFrame() { + sampleCounter++; + if(newFrameRequest) { + if(sampleCounter>(newFrameRequest->numFadeSamples)) { + delete oldFrameRequest; + oldFrameRequest=newFrameRequest; + newFrameRequest=NULL; + } else { + double curFadeRatio=(double)sampleCounter/(newFrameRequest->numFadeSamples); + for(int i=0;iframe))[i],((speechPlayer_frameParam_t*)&(newFrameRequest->frame))[i],curFadeRatio); + } + } + } else if(sampleCounter>(oldFrameRequest->minNumSamples)) { + if(!frameRequestQueue.empty()) { + curFrameIsNULL=false; + newFrameRequest=frameRequestQueue.front(); + frameRequestQueue.pop(); + if(newFrameRequest->NULLFrame) { + memcpy(&(newFrameRequest->frame),&(oldFrameRequest->frame),sizeof(speechPlayer_frame_t)); + newFrameRequest->frame.preFormantGain=0; + newFrameRequest->frame.voicePitch=curFrame.voicePitch; + newFrameRequest->voicePitchInc=0; + } else if(oldFrameRequest->NULLFrame) { + memcpy(&(oldFrameRequest->frame),&(newFrameRequest->frame),sizeof(speechPlayer_frame_t)); + oldFrameRequest->frame.preFormantGain=0; + } + if(newFrameRequest) { + if(newFrameRequest->userIndex!=-1) lastUserIndex=newFrameRequest->userIndex; + sampleCounter=0; + newFrameRequest->frame.voicePitch+=(newFrameRequest->voicePitchInc*newFrameRequest->numFadeSamples); + } + } else { + curFrameIsNULL=true; + } + } else { + curFrame.voicePitch+=oldFrameRequest->voicePitchInc; + oldFrameRequest->frame.voicePitch=curFrame.voicePitch; + } + } + + + public: + + FrameManagerImpl(): curFrame(), curFrameIsNULL(true), sampleCounter(0), newFrameRequest(NULL), lastUserIndex(-1) { + oldFrameRequest=new frameRequest_t(); + oldFrameRequest->NULLFrame=true; + } + + void queueFrame(speechPlayer_frame_t* frame, unsigned int minNumSamples, unsigned int numFadeSamples, int userIndex, bool purgeQueue) { + frameRequest_t* frameRequest=new frameRequest_t; + frameRequest->minNumSamples=minNumSamples; //max(minNumSamples,1); + frameRequest->numFadeSamples=numFadeSamples; //max(numFadeSamples,1); + if(frame) { + frameRequest->NULLFrame=false; + memcpy(&(frameRequest->frame),frame,sizeof(speechPlayer_frame_t)); + frameRequest->voicePitchInc=(frame->endVoicePitch-frame->voicePitch)/frameRequest->minNumSamples; + } else { + frameRequest->NULLFrame=true; + } + frameRequest->userIndex=userIndex; + if(purgeQueue) { + for(;!frameRequestQueue.empty();frameRequestQueue.pop()) delete frameRequestQueue.front(); + sampleCounter=oldFrameRequest->minNumSamples; + if(newFrameRequest) { + oldFrameRequest->NULLFrame=newFrameRequest->NULLFrame; + memcpy(&(oldFrameRequest->frame),&curFrame,sizeof(speechPlayer_frame_t)); + delete newFrameRequest; + newFrameRequest=NULL; + } + } + frameRequestQueue.push(frameRequest); + } + + const int getLastIndex() { + return lastUserIndex; + } + + const speechPlayer_frame_t* const getCurrentFrame() { + updateCurrentFrame(); + return curFrameIsNULL?NULL:&curFrame; + } + + ~FrameManagerImpl() { + if(oldFrameRequest) delete oldFrameRequest; + if(newFrameRequest) delete newFrameRequest; + } + +}; + +FrameManager* FrameManager::create() { return new FrameManagerImpl(); } diff --git a/src/speechPlayer/src/frame.h b/src/speechPlayer/src/frame.h new file mode 100644 index 00000000..aa319d38 --- /dev/null +++ b/src/speechPlayer/src/frame.h @@ -0,0 +1,55 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#ifndef SPEECHPLAYER_FRAME_H +#define SPEECHPLAYER_FRAME_H + +#include "utils.h" + +typedef double speechPlayer_frameParam_t; + +typedef struct { + // voicing and cascaide + speechPlayer_frameParam_t voicePitch; // fundermental frequency of voice (phonation) in hz + speechPlayer_frameParam_t vibratoPitchOffset; // pitch is offset up or down in fraction of a semitone + speechPlayer_frameParam_t vibratoSpeed; // Speed of vibrato in hz + speechPlayer_frameParam_t voiceTurbulenceAmplitude; // amplitude of voice breathiness from 0 to 1 + speechPlayer_frameParam_t glottalOpenQuotient; // fraction between 0 and 1 of a voice cycle that the glottis is open (allows voice turbulance, alters f1...) + speechPlayer_frameParam_t voiceAmplitude; // amplitude of voice (phonation) source between 0 and 1. + speechPlayer_frameParam_t aspirationAmplitude; // amplitude of aspiration (voiceless h, whisper) source between 0 and 1. + speechPlayer_frameParam_t cf1, cf2, cf3, cf4, cf5, cf6, cfN0, cfNP; // frequencies of standard cascaide formants, nasal (anti) 0 and nasal pole in hz + speechPlayer_frameParam_t cb1, cb2, cb3, cb4, cb5, cb6, cbN0, cbNP; // bandwidths of standard cascaide formants, nasal (anti) 0 and nasal pole in hz + speechPlayer_frameParam_t caNP; // amplitude from 0 to 1 of cascade nasal pole formant + // fricatives and parallel + speechPlayer_frameParam_t fricationAmplitude; // amplitude of frication noise from 0 to 1. + speechPlayer_frameParam_t pf1, pf2, pf3, pf4, pf5, pf6; // parallel formants in hz + speechPlayer_frameParam_t pb1, pb2, pb3, pb4, pb5, pb6; // parallel formant bandwidths in hz + speechPlayer_frameParam_t pa1, pa2, pa3, pa4, pa5, pa6; // amplitude of parallel formants between 0 and 1 + speechPlayer_frameParam_t parallelBypass; // amount of signal which should bypass parallel resonators from 0 to 1 + speechPlayer_frameParam_t preFormantGain; // amplitude from 0 to 1 of all vocal tract sound (voicing, frication) before entering formant resonators. Useful for stopping/starting speech + speechPlayer_frameParam_t outputGain; // amplitude from 0 to 1 of final output (master volume) + speechPlayer_frameParam_t endVoicePitch; // pitch of voice at the end of the frame length +} speechPlayer_frame_t; + +const int speechPlayer_frame_numParams=sizeof(speechPlayer_frame_t)/sizeof(speechPlayer_frameParam_t); + +class FrameManager { + public: + static FrameManager* create(); //factory function + virtual void queueFrame(speechPlayer_frame_t* frame, unsigned int minNumSamples, unsigned int numFadeSamples, int userIndex, bool purgeQueue)=0; + virtual const speechPlayer_frame_t* const getCurrentFrame()=0; + virtual const int getLastIndex()=0; +}; + +#endif diff --git a/src/speechPlayer/src/sample.h b/src/speechPlayer/src/sample.h new file mode 100644 index 00000000..6b84c4b2 --- /dev/null +++ b/src/speechPlayer/src/sample.h @@ -0,0 +1,24 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#ifndef SPEECHPLAYER_SAMPLE_H +#define SPEECHPLAYER_SAMPLE_H + +typedef short sampleVal; + +typedef struct { + sampleVal value; +} sample; + +#endif \ No newline at end of file diff --git a/src/speechPlayer/src/speechPlayer.cpp b/src/speechPlayer/src/speechPlayer.cpp new file mode 100644 index 00000000..574bee88 --- /dev/null +++ b/src/speechPlayer/src/speechPlayer.cpp @@ -0,0 +1,55 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#include "frame.h" +#include "speechWaveGenerator.h" +#include "speechPlayer.h" + +typedef struct { + int sampleRate; + FrameManager* frameManager; + SpeechWaveGenerator* waveGenerator; +} speechPlayer_handleInfo_t; + +speechPlayer_handle_t speechPlayer_initialize(int sampleRate) { + speechPlayer_handleInfo_t* playerHandleInfo=new speechPlayer_handleInfo_t; + playerHandleInfo->sampleRate=sampleRate; + playerHandleInfo->frameManager=FrameManager::create(); + playerHandleInfo->waveGenerator=SpeechWaveGenerator::create(sampleRate); + playerHandleInfo->waveGenerator->setFrameManager(playerHandleInfo->frameManager); + return (speechPlayer_handle_t)playerHandleInfo; +} + +void speechPlayer_queueFrame(speechPlayer_handle_t playerHandle, speechPlayer_frame_t* framePtr, unsigned int minFrameDuration, unsigned int fadeDuration, int userIndex, bool purgeQueue) { + speechPlayer_handleInfo_t* playerHandleInfo=(speechPlayer_handleInfo_t*)playerHandle; + if (fadeDuration < 1) fadeDuration = 1; + playerHandleInfo->frameManager->queueFrame(framePtr,minFrameDuration,fadeDuration,userIndex,purgeQueue); +} + +int speechPlayer_synthesize(speechPlayer_handle_t playerHandle, unsigned int sampleCount, sample* sampleBuf) { + return ((speechPlayer_handleInfo_t*)playerHandle)->waveGenerator->generate(sampleCount,sampleBuf); +} + +int speechPlayer_getLastIndex(speechPlayer_handle_t playerHandle) { + speechPlayer_handleInfo_t* playerHandleInfo=(speechPlayer_handleInfo_t*)playerHandle; + return playerHandleInfo->frameManager->getLastIndex(); +} + +void speechPlayer_terminate(speechPlayer_handle_t playerHandle) { + speechPlayer_handleInfo_t* playerHandleInfo=(speechPlayer_handleInfo_t*)playerHandle; + delete playerHandleInfo->waveGenerator; + delete playerHandleInfo->frameManager; + delete playerHandleInfo; +} + \ No newline at end of file diff --git a/src/speechPlayer/src/speechPlayer.h b/src/speechPlayer/src/speechPlayer.h new file mode 100644 index 00000000..60f4f72b --- /dev/null +++ b/src/speechPlayer/src/speechPlayer.h @@ -0,0 +1,37 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#ifndef SPEECHPLAYER_H +#define SPEECHPLAYER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "frame.h" +#include "sample.h" + +typedef void* speechPlayer_handle_t; + +speechPlayer_handle_t speechPlayer_initialize(int sampleRate); +void speechPlayer_queueFrame(speechPlayer_handle_t playerHandle, speechPlayer_frame_t* framePtr, unsigned int minFrameDuration, unsigned int fadeDuration, int userIndex, bool purgeQueue); +int speechPlayer_synthesize(speechPlayer_handle_t playerHandle, unsigned int sampleCount, sample* sampleBuf); +int speechPlayer_getLastIndex(speechPlayer_handle_t playerHandle); +void speechPlayer_terminate(speechPlayer_handle_t playerHandle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/speechPlayer/src/speechWaveGenerator.cpp b/src/speechPlayer/src/speechWaveGenerator.cpp new file mode 100644 index 00000000..750666a1 --- /dev/null +++ b/src/speechPlayer/src/speechWaveGenerator.cpp @@ -0,0 +1,221 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +/* +Based on klsyn-88, found at http://linguistics.berkeley.edu/phonlab/resources/ +*/ + +#define _USE_MATH_DEFINES + +#include +#include +#include +#include "utils.h" +#include "speechWaveGenerator.h" + +using namespace std; + +const double PITWO=M_PI*2; + +class NoiseGenerator { + private: + double lastValue; + + public: + NoiseGenerator(): lastValue(0.0) {}; + + double getNext() { + lastValue=((double)rand()/RAND_MAX)+0.75*lastValue; + return lastValue; + } + +}; + +class FrequencyGenerator { + private: + int sampleRate; + double lastCyclePos; + + public: + FrequencyGenerator(int sr): sampleRate(sr), lastCyclePos(0) {} + + double getNext(double frequency) { + double cyclePos=fmod((frequency/sampleRate)+lastCyclePos,1); + lastCyclePos=cyclePos; + return cyclePos; + } + +}; + +class VoiceGenerator { + private: + FrequencyGenerator pitchGen; + FrequencyGenerator vibratoGen; + NoiseGenerator aspirationGen; + + public: + bool glottisOpen; + VoiceGenerator(int sr): pitchGen(sr), vibratoGen(sr), aspirationGen(), glottisOpen(false) {}; + + double getNext(const speechPlayer_frame_t* frame) { + double vibrato=(sin(vibratoGen.getNext(frame->vibratoSpeed)*PITWO)*0.06*frame->vibratoPitchOffset)+1; + double voice=pitchGen.getNext(frame->voicePitch*vibrato); + double aspiration=aspirationGen.getNext()*0.2; + double turbulence=aspiration*frame->voiceTurbulenceAmplitude; + glottisOpen=voice>=frame->glottalOpenQuotient; + if(!glottisOpen) { + turbulence*=0.01; + } + voice=(voice*2)-1; + voice+=turbulence; + voice*=frame->voiceAmplitude; + aspiration*=frame->aspirationAmplitude; + return aspiration+voice; + } + +}; + +class Resonator { + private: + //raw parameters + int sampleRate; + double frequency; + double bandwidth; + bool anti; + //calculated parameters + bool setOnce; + double a, b, c; + //Memory + double p1, p2; + + public: + Resonator(int sampleRate, bool anti=false) { + this->sampleRate=sampleRate; + this->anti=anti; + this->setOnce=false; + this->p1=0; + this->p2=0; + } + + void setParams(double frequency, double bandwidth) { + if(!setOnce||(frequency!=this->frequency)||(bandwidth!=this->bandwidth)) { + this->frequency=frequency; + this->bandwidth=bandwidth; + double r=exp(-M_PI/sampleRate*bandwidth); + c=-(r*r); + b=r*cos(PITWO/sampleRate*-frequency)*2.0; + a=1.0-b-c; + if(anti&&frequency!=0) { + a=1.0/a; + c*=-a; + b*=-a; + } + } + this->setOnce=true; + } + + double resonate(double in, double frequency, double bandwidth) { + setParams(frequency,bandwidth); + double out=a*in+b*p1+c*p2; + p2=p1; + p1=anti?in:out; + return out; + } + +}; + +class CascadeFormantGenerator { + private: + int sampleRate; + Resonator r1, r2, r3, r4, r5, r6, rN0, rNP; + + public: + CascadeFormantGenerator(int sr): sampleRate(sr), r1(sr), r2(sr), r3(sr), r4(sr), r5(sr), r6(sr), rN0(sr,true), rNP(sr) {}; + + double getNext(const speechPlayer_frame_t* frame, bool glottisOpen, double input) { + input/=2.0; + double n0Output=rN0.resonate(input,frame->cfN0,frame->cbN0); + double output=calculateValueAtFadePosition(input,rNP.resonate(n0Output,frame->cfNP,frame->cbNP),frame->caNP); + output=r6.resonate(output,frame->cf6,frame->cb6); + output=r5.resonate(output,frame->cf5,frame->cb5); + output=r4.resonate(output,frame->cf4,frame->cb4); + output=r3.resonate(output,frame->cf3,frame->cb3); + output=r2.resonate(output,frame->cf2,frame->cb2); + output=r1.resonate(output,frame->cf1,frame->cb1); + return output; + } + +}; + +class ParallelFormantGenerator { + private: + int sampleRate; + Resonator r1, r2, r3, r4, r5, r6; + + public: + ParallelFormantGenerator(int sr): sampleRate(sr), r1(sr), r2(sr), r3(sr), r4(sr), r5(sr), r6(sr) {}; + + double getNext(const speechPlayer_frame_t* frame, double input) { + input/=2.0; + double output=0; + output+=(r1.resonate(input,frame->pf1,frame->pb1)-input)*frame->pa1; + output+=(r2.resonate(input,frame->pf2,frame->pb2)-input)*frame->pa2; + output+=(r3.resonate(input,frame->pf3,frame->pb3)-input)*frame->pa3; + output+=(r4.resonate(input,frame->pf4,frame->pb4)-input)*frame->pa4; + output+=(r5.resonate(input,frame->pf5,frame->pb5)-input)*frame->pa5; + output+=(r6.resonate(input,frame->pf6,frame->pb6)-input)*frame->pa6; + return calculateValueAtFadePosition(output,input,frame->parallelBypass); + } + +}; + +class SpeechWaveGeneratorImpl: public SpeechWaveGenerator { + private: + int sampleRate; + VoiceGenerator voiceGenerator; + NoiseGenerator fricGenerator; + CascadeFormantGenerator cascade; + ParallelFormantGenerator parallel; + FrameManager* frameManager; + + public: + SpeechWaveGeneratorImpl(int sr): sampleRate(sr), voiceGenerator(sr), fricGenerator(), cascade(sr), parallel(sr), frameManager(NULL) { + } + + unsigned int generate(const unsigned int sampleCount, sample* sampleBuf) { + if(!frameManager) return 0; + double val=0; + for(unsigned int i=0;igetCurrentFrame(); + if(frame) { + double voice=voiceGenerator.getNext(frame); + double cascadeOut=cascade.getNext(frame,voiceGenerator.glottisOpen,voice*frame->preFormantGain); + double fric=fricGenerator.getNext()*0.3*frame->fricationAmplitude; + double parallelOut=parallel.getNext(frame,fric*frame->preFormantGain); + double out=(cascadeOut+parallelOut)*frame->outputGain; + sampleBuf[i].value=(int)MAX(MIN(out*4000,32000),-32000); + } else { + return i; + } + } + return sampleCount; + } + + void setFrameManager(FrameManager* frameManager) { + this->frameManager=frameManager; + } + +}; + +SpeechWaveGenerator* SpeechWaveGenerator::create(int sampleRate) {return new SpeechWaveGeneratorImpl(sampleRate); } diff --git a/src/speechPlayer/src/speechWaveGenerator.h b/src/speechPlayer/src/speechWaveGenerator.h new file mode 100644 index 00000000..91876207 --- /dev/null +++ b/src/speechPlayer/src/speechWaveGenerator.h @@ -0,0 +1,27 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#ifndef SPEECHPLAYERSPEECHWAVEGENERATOR_H +#define SPEECHPLAYERSPEECHWAVEGENERATOR_H + +#include "frame.h" +#include "waveGenerator.h" + +class SpeechWaveGenerator: public WaveGenerator { + public: + static SpeechWaveGenerator* create(int sampleRate); + virtual void setFrameManager(FrameManager* frameManager)=0; +}; + +#endif diff --git a/src/speechPlayer/src/utils.h b/src/speechPlayer/src/utils.h new file mode 100644 index 00000000..bc09923b --- /dev/null +++ b/src/speechPlayer/src/utils.h @@ -0,0 +1,37 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#ifndef SPEECHPLAYER_UTILS_H +#define SPEECHPLAYER_UTILS_H + +#ifndef M_PI + #define M_PI 3.14159265358979323846 +#endif + +static inline int MAX(int a, int b) { return((a) > (b) ? a : b); } +static inline int MIN(int a, int b) { return((a) < (b) ? a : b); } + +static inline int ISNAN (double x) { + if (x != x) + return 1; + else + return 0; +} + +inline double calculateValueAtFadePosition(double oldVal, double newVal, double curFadeRatio) { + if(ISNAN(newVal)) return oldVal; + return oldVal+((newVal-oldVal)*curFadeRatio); +} + +#endif diff --git a/src/speechPlayer/src/waveGenerator.h b/src/speechPlayer/src/waveGenerator.h new file mode 100644 index 00000000..259a2c04 --- /dev/null +++ b/src/speechPlayer/src/waveGenerator.h @@ -0,0 +1,27 @@ +/* +This file is a part of the NV Speech Player project. +URL: https://bitbucket.org/nvaccess/speechplayer +Copyright 2014 NV Access Limited. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2.0, as published by +the Free Software Foundation. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This license can be found at: +http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +*/ + +#ifndef SPEECHPLAYERWAVEGENERATOR_H +#define SPEECHPLAYERWAVEGENERATOR_H + +#include +#include "sample.h" +#include "speechPlayer.h" + +class WaveGenerator { + public: + virtual unsigned int generate(const unsigned int bufSize, sample* buffer)=0; +}; + +#endif diff --git a/src/windows/libespeak-ng.vcxproj b/src/windows/libespeak-ng.vcxproj index dce2b27a..e242c98a 100644 --- a/src/windows/libespeak-ng.vcxproj +++ b/src/windows/libespeak-ng.vcxproj @@ -87,8 +87,8 @@ TurnOffAllWarnings Disabled - $(ProjectDir);$(ProjectDir)/../include;$(ProjectDir)/../pcaudiolib/src/include;$(ProjectDir)/../include/compat;$(ProjectDir)/../ucd-tools/src/include - LIBESPEAK_NG_EXPORT;INCLUDE_KLATT;INCLUDE_MBROLA;HAVE_PCAUDIOLIB_AUDIO_H;%(PreprocessorDefinitions) + $(ProjectDir);$(ProjectDir)/../include;$(ProjectDir)/../pcaudiolib/src/include;$(ProjectDir)/../speechPlayer/include;$(ProjectDir)/../include/compat;$(ProjectDir)/../ucd-tools/src/include + LIBESPEAK_NG_EXPORT;INCLUDE_KLATT;INCLUDE_SPEECHPLAYER;INCLUDE_MBROLA;HAVE_PCAUDIOLIB_AUDIO_H;%(PreprocessorDefinitions) $(IntDir)libespeak-ng.pdb @@ -104,9 +104,9 @@ TurnOffAllWarnings Disabled - LIBESPEAK_NG_EXPORT;INCLUDE_KLATT;INCLUDE_MBROLA;HAVE_PCAUDIOLIB_AUDIO_H;%(PreprocessorDefinitions) + LIBESPEAK_NG_EXPORT;INCLUDE_KLATT;INCLUDE_SPEECHPLAYER;INCLUDE_MBROLA;HAVE_PCAUDIOLIB_AUDIO_H;%(PreprocessorDefinitions) $(IntDir)libespeak-ng.pdb - $(ProjectDir);$(ProjectDir)/../include;$(ProjectDir)/../pcaudiolib/src/include;$(ProjectDir)/../include/compat;$(ProjectDir)/../ucd-tools/src/include + $(ProjectDir);$(ProjectDir)/../include;$(ProjectDir)/../pcaudiolib/src/include;$(ProjectDir)/../speechPlayer/include;$(ProjectDir)/../include/compat;$(ProjectDir)/../ucd-tools/src/include Windows @@ -123,8 +123,8 @@ MaxSpeed true true - $(ProjectDir);$(ProjectDir)/../include;$(ProjectDir)/../pcaudiolib/src/include;$(ProjectDir)/../include/compat;$(ProjectDir)/../ucd-tools/src/include - LIBESPEAK_NG_EXPORT;INCLUDE_KLATT;INCLUDE_MBROLA;HAVE_PCAUDIOLIB_AUDIO_H;%(PreprocessorDefinitions) + $(ProjectDir);$(ProjectDir)/../include;$(ProjectDir)/../pcaudiolib/src/include;$(ProjectDir)/../speechPlayer/include;$(ProjectDir)/../include/compat;$(ProjectDir)/../ucd-tools/src/include + LIBESPEAK_NG_EXPORT;INCLUDE_KLATT;INCLUDE_SPEECHPLAYER;INCLUDE_MBROLA;HAVE_PCAUDIOLIB_AUDIO_H;%(PreprocessorDefinitions) $(IntDir)libespeak-ng.pdb @@ -144,9 +144,9 @@ MaxSpeed true true - LIBESPEAK_NG_EXPORT;INCLUDE_KLATT;INCLUDE_MBROLA;HAVE_PCAUDIOLIB_AUDIO_H;%(PreprocessorDefinitions) + LIBESPEAK_NG_EXPORT;INCLUDE_KLATT;INCLUDE_SPEECHPLAYER;INCLUDE_MBROLA;HAVE_PCAUDIOLIB_AUDIO_H;%(PreprocessorDefinitions) $(IntDir)libespeak-ng.pdb - $(ProjectDir);$(ProjectDir)/../include;$(ProjectDir)/../pcaudiolib/src/include;$(ProjectDir)/../include/compat;$(ProjectDir)/../ucd-tools/src/include + $(ProjectDir);$(ProjectDir)/../include;$(ProjectDir)/../pcaudiolib/src/include;$(ProjectDir)/../speechPlayer/include;$(ProjectDir)/../include/compat;$(ProjectDir)/../ucd-tools/src/include Windows @@ -183,6 +183,7 @@ + @@ -194,6 +195,9 @@ + + + @@ -207,6 +211,7 @@ + diff --git a/tests/dummy.cpp b/tests/dummy.cpp new file mode 100644 index 00000000..2c9032e3 --- /dev/null +++ b/tests/dummy.cpp @@ -0,0 +1,3 @@ +void dummy() +{ +} \ No newline at end of file