This is a stripped down win32 version of eSpeak.
(I added *.wav recording. source code are included)
Some of the supported language styles by eSpeak:
afrikaans, catalan, welsh-test, german, default
english, english_rp, english-us, esperanto, spanish-latin-american
finnish, french (Belgium), hindi, hungarian, armenian-west
icelandic-test, lojban, kannada, latin, macedonian-test
nahuatl - classical, norwegian, polish, portugal, russian_test
albanian, swedish, tamil, vietnam, cantonese
More infos about eSpeak can be found at: http://espeak.sourceforge.net
Download: eSpeakSynth.zip
speak text: (string and wstring both are supported)
Code: Select all
#include once "eSpeakSynth.bi"
eSpeak.Speak("I like free basic")
? "wait ...":sleep
Code: Select all
#include once "eSpeakSynth.bi"
eSpeak.Speak("You can play the voice back from wave file later, if you like.","Test.wav")
? "wait ...":sleep
Code: Select all
#include once "eSpeakSynth.bi"
var nVoices=eSpeak.VoiceCount
? "list of all " & nVoices & " language styles."
? string(40,"=")
for i as integer = 0 to nVoices step 2
? eSpeak.GetVoiceName(i),eSpeak.GetVoiceName(i+1)
next
sleep
Code: Select all
#include once "eSpeakSynth.bi"
eSpeak.Speak("Be or not to be. This is the question.")
eSpeak.CurrentVoice = "german"
eSpeak.Speak("Sein oder nicht sein. Das ist die Frage.")
? "wait...":sleep
You can get back the default values WordsPerMinuteDefault,WordGapDefault,VolumeDefault,PitchDefault ...
take a look at "eSpeakSynth.bi"
Code: Select all
#include once "eSpeakSynth.bi"
for i as integer=0 to 100 step 10
eSpeak.Pitch=i
eSpeak.Speak("pitch ")
next
eSpeak.Pitch=50
eSpeak.Speak("default pitch")
? "wait ...":sleep
Joshy
"eSpeakSnth.bi"
Code: Select all
#ifndef __EPEAK_SYNTH_BI__
#define __EPEAK_SYNTH_BI__
#include once "espeak.bi"
#include once "windows.bi"
#include once "win/mmsystem.bi"
#include once "crt/string.bi"
#include once "crt/stdlib.bi"
#ifndef WAVE_MAPPER
#define WAVE_MAPPER cuint(-1)
#endif
#define FCC(c) *(cptr(uinteger ptr,@##c))
type ESPEAKSYNTH
declare constructor(datapath as string="",DeviceIndex as uinteger=WAVE_MAPPER)
declare destructor
declare function VoiceCount as integer
declare function GetVoiceName(index as integer) as string
declare sub SetVoiceName(voicename as string)
declare property Volume(value as integer)
declare property Volume as integer
declare property VolumeDefault as integer
declare property Pitch(value as integer)
declare property Pitch as integer
declare property PitchDefault as integer
declare property Range(value as integer)
declare property Range as integer
declare property RangeDefault as integer
declare property WordsPerMinute(words as integer)
declare property WordsPerMinute as integer
declare property WordsPerMinuteDefault as integer
declare property WordGap(value as integer)
declare property WordGap as integer
declare property WordGapDefault as integer
declare property Synchron(onoff as integer)
declare property Synchron as integer
declare function Speak(txt as string,file as string="") as integer
declare function Speak(txt as wstring,file as string="") as integer
declare function SpeakKey(txt as string) as integer
private:
declare sub InRange(byref value as integer,min as integer,max as integer)
declare sub BeginRecording(file as string)
declare sub EndRecording
declare static sub AudioCallback( _
hDevice as HWAVEOUT, _
DriverMessage as uinteger, _
pESpeakSynth as ESPEAKSYNTH ptr, _
pWaveHeader as PWAVEHDR, _
Param2 as DWORD)
declare static function SynthCallback cdecl (_
pSamples as short ptr, _
nNewSamples as integer, _
pEvent as ESPEAK_EVENT ptr) as CallbackResult
as integer nVoices,nSamplesPerBuffer,nRate,hFile,nActiveBuffers
as integer IsAudioOpen,IsSynchron,nByesRecorded
as uinteger ptr pWAVEHeader
as VOICELIST Voices
as WAVEFORMATEX wfex
as WAVEOUTCAPS Caps
as HWAVEOUT hDevice
as MMRESULT LastResult
end type
' one global instance
dim shared as ESPEAKSYNTH eSpeak
' init datapath, synth and voices
constructor ESPEAKSYNTH(datapath as string,DeviceIndex as uinteger)
' ####################
' # init speak synth #
' ####################
nRate=22050:nSamplesPerBuffer=2205
if datapath="" then datapath=ExePath()
if (espeak_Initialize(2,nSamplesPerBuffer,datapath)<>nRate) then
open ERR for output as #99
print #99,"error: Initialize(" & datapath & ") !"
close #99
beep:sleep:end 1
end if
Voices = espeak_ListVoices(0)
while Voices[nVoices]<>0
nVoices+=1
wend
if (nVoices<1) then
open ERR for output as #99
print #99,"error: no voices !"
close #99
beep:sleep:end 1
end if
espeak_SetSynthCallback(@SynthCallback)
' ######################
' # setup audio device #
' ######################
LastResult=waveOutGetDevCaps(DeviceIndex, _
@Caps, _
sizeof(WAVEOUTCAPS))
if (LastResult<>MMSYSERR_NOERROR) then
open ERR for output as #99
print #99,"error: get audio caps !"
close #99
beep:sleep:end 1
end if
with wfex
.wFormatTag = WAVE_FORMAT_PCM
.nSamplesPerSec = nRate
.nChannels = 1
.wBitsPerSample = 16
.nBlockAlign = (.wBitsPerSample shr 3) * .nChannels
.nAvgBytesPerSec = .nBlockAlign * .nSamplesPerSec
.cbSize = 0 ' no extra bytes
end with
LastResult = waveOutOpen(@hDevice, _
DeviceIndex, _
cptr(LPCWAVEFORMATEX,@wfex), _
cast(uinteger,@AudioCallback), _
cast(uinteger,@this), _
CALLBACK_FUNCTION)
if (LastResult<>MMSYSERR_NOERROR) or (IsAudioOpen<>1) then
open ERR for output as #99
print #99,"error: open audio device !"
close #99
beep:sleep:end 1
end if
pWAVEHeader=calloc(11,sizeof(uinteger))
end constructor
' stop audiodevice, voicesynth and free all resources
destructor ESPEAKSYNTH
' ##############
' # stop synth #
' ##############
if espeak_IsPlaying() then
espeak_Cancel()
sleep 100,1
end if
' ########################
' # free synth resources #
' ########################
espeak_Terminate()
' ##############
' # stop audio #
' ##############
if IsAudioOpen then
waveOutReset(hDevice)
sleep 500,1
dim as integer count = 100
' ########################
' # free audio resources #
' ########################
LastResult=waveOutClose(hDevice)
while (LastResult=WAVERR_STILLPLAYING) andalso (count>0)
sleep 10,1:count-=1
LastResult=waveOutClose(hDevice)
wend
end if
if pWAVEHeader then
free(pWAVEHeader)
end if
end destructor
sub ESPEAKSYNTH.AudioCallBack(hDevice as HWAVEOUT, _
DriverMsg as uinteger, _
pSynth as ESPEAKSYNTH ptr, _
pBuffer as PWAVEHDR, _
Param2 as DWORD)
select case as const DriverMsg
case WOM_DONE
if (pBuffer<>NULL) then
' unprepare and free buffer
waveOutUnprepareHeader(pSynth->hDevice,pBuffer,sizeof(WAVEHDR))
free(pBuffer->lpData)
free(pBuffer)
pSynth->nActiveBuffers-=1
end if
case WOM_OPEN
pSynth->IsAudioOpen = 1
case WOM_CLOSE
pSynth->IsAudioOpen = 0
end select
end sub
function ESPEAKSYNTH.SynthCallback cdecl (pWave as short ptr, _
nNewSamples as integer, _
pEvent as ESPEAK_EVENT ptr) as CallbackResult
if (nNewSamples>0) then
nNewSamples shl=1 ' n samples to n bytes
dim as ESPEAKSYNTH ptr pSynth = pEvent->User_Data
if (pSynth<>NULL) then
if (pSynth->IsAudioOpen) then
dim as PWAVEHDR pBuffer = calloc(1,sizeof(WAVEHDR))
pBuffer->lpData=calloc(1,nNewSamples)
pBuffer->dwBufferLength=nNewSamples
memcpy(pBuffer->lpData,pWave,nNewSamples)
waveOutPrepareHeader(pSynth->hDevice,pBuffer,sizeof(WAVEHDR))
waveOutWrite(pSynth->hDevice,pBuffer,sizeof(WAVEHDR))
pSynth->nActiveBuffers+=1
end if
' in recording mode ?
if (pSynth->hFile<>0) then
dim as ubyte ptr p=cptr(ubyte ptr,pWave)
put #pSynth->hFile,,*p,nNewSamples
pSynth->nByesRecorded+=nNewSamples
end if
end if
end if
return OK
end function
sub ESPEAKSYNTH.InRange(byref value as integer,min as integer,max as integer)
if value<min then
value=min
elseif value>max then
value=max
end if
end sub
function ESPEAKSYNTH.VoiceCount as integer
return nVoices
end function
function ESPEAKSYNTH.GetVoiceName(index as integer) as string
InRange(index,0,nVoices-1)
return *Voices[index]->Name
end function
sub ESPEAKSYNTH.SetVoiceName(voicename as string)
espeak_SetVoiceByName(voicename)
end sub
property ESPEAKSYNTH.WordsPerMinute(value as integer)
InRange(value,80,450):espeak_SetParameter(PARAM_RATE,value)
end property
property ESPEAKSYNTH.WordsPerMinute as integer
return espeak_GetParameter(PARAM_RATE,1)
end property
property ESPEAKSYNTH.WordsPerMinuteDefault as integer
return espeak_GetParameter(PARAM_RATE,0)
end property
property ESPEAKSYNTH.WordGap(value as integer)
value\=10
InRange(value,0,100):espeak_SetParameter(PARAM_WORDGAP,value)
end property
property ESPEAKSYNTH.WordGap as integer
return espeak_GetParameter(PARAM_WORDGAP,1)*10
end property
property ESPEAKSYNTH.WordGapDefault as integer
return espeak_GetParameter(PARAM_WORDGAP,0)*10
end property
property ESPEAKSYNTH.Volume(value as integer)
InRange(value,0,200):espeak_SetParameter(PARAM_VOLUME,value)
end property
property ESPEAKSYNTH.Volume as integer
return espeak_GetParameter(PARAM_VOLUME,1)
end property
property ESPEAKSYNTH.VolumeDefault as integer
return espeak_GetParameter(PARAM_VOLUME,0)
end property
property ESPEAKSYNTH.Pitch(value as integer)
InRange(value,0,100):espeak_SetParameter(PARAM_PITCH,value)
end property
property ESPEAKSYNTH.Pitch as integer
return espeak_GetParameter(PARAM_PITCH,1)
end property
property ESPEAKSYNTH.PitchDefault as integer
return espeak_GetParameter(PARAM_PITCH,0)
end property
property ESPEAKSYNTH.Range(value as integer)
InRange(value,0,100):espeak_SetParameter(PARAM_RANGE,value)
end property
property ESPEAKSYNTH.Range as integer
return espeak_GetParameter(PARAM_RANGE,1)
end property
property ESPEAKSYNTH.RangeDefault as integer
return espeak_GetParameter(PARAM_RANGE,0)
end property
property ESPEAKSYNTH.Synchron(onoff as integer)
IsSynchron=(onoff<>0)
end property
property ESPEAKSYNTH.Synchron as integer
return IsSynchron
end property
sub ESPEAKSYNTH.BeginRecording(file as string)
' reset counter
nByesRecorded=0
hFile=FreeFile()
if open(file,for binary,access write,as #hFile) then
? "error: can't create '" & file & " !"
beep:hFile=0
else
' write placeholder RIFF WAVE header
put #hFile,,*pWAVEHeader,11
end if
end sub
sub ESPEAKSYNTH.EndRecording
' create and write the real WAVE header
pWAVEHeader[ 0]=FCC("RIFF") ' RIFF chunk
pWAVEHeader[ 1]=36 + nByesRecorded ' size of WAVE chunk + data size
pWAVEHeader[ 2]=FCC("WAVE") ' WAVE chunk
pWAVEHeader[ 3]=FCC("fmt ") ' fmt chunk
pWAVEHeader[ 4]=16 ' size of fmt chunk
pWAVEHeader[ 5]=(wfex.nChannels shl 16) or 1 ' nchannels + PCM_FORMAT flag
pWAVEHeader[ 6]=wfex.nSamplesPerSec ' playback rate
pWAVEHeader[ 7]=wfex.nAvgBytesPerSec ' bytes per sec.
pWAVEHeader[ 8]=(wfex.wBitsPerSample shl 16) or wfex.nBlockAlign ' bits per sample + blockalign
pWAVEHeader[ 9]=FCC("data") ' data chunk
pWAVEHeader[10]=nByesRecorded
seek #hFile,1
put #hFile,,*pWaveHeader,11
close #hFile
hFile=0
nByesRecorded=0
end sub
function ESPEAKSYNTH.Speak(txt as string,file as string) as integer
dim as integer n=len(txt)
if (n>0) then
dim as uinteger unicid
if len(file) then BeginRecording(file)
function = espeak_Synth(strptr(txt),n,0,POS_CHARACTER,0,espeakCHARS_8bit,@unicid,@this)
' in sync or recording mode wait on end
if (IsSynchron<>0) or (hFile<>0) then
espeak_Synchronize()
while (nActiveBuffers>0):sleep(10):wend
end if
if (hFile) then EndRecording()
end if
end function
function ESPEAKSYNTH.Speak(txt as wstring,file as string) as integer
dim as integer n=len(txt)
if (n>0) then
dim as uinteger unicid
if len(file) then BeginRecording(file)
function = espeak_Synth(strptr(txt),n,0,POS_CHARACTER,0,espeakCHARS_WCHAR,@unicid,@this)
' in sync or recording mode wait on end
if (IsSynchron<>0) or (hFile<>0) then
espeak_Synchronize()
while (nActiveBuffers>0):sleep(10):wend
end if
if (hFile) then EndRecording()
end if
end function
#endif ' __ESPEAK_SYNTH_BI__