blob: 4bc62080e310e9c17fb01453a49149eb79294808 [file] [log] [blame] [edit]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "log.h"
#include "parse.h"
typedef enum {
PARM_PATH,
PARM_PUNCTLIST,
PARM_VOICE,
PARM_MAXRATE
} DriverParameter;
#define SPKPARMS "path", "punctlist", "voice", "maxrate"
#include "spk_driver.h"
#include <espeak-ng/speak_lib.h>
static int maxrate = espeakRATE_MAXIMUM;
static void
spk_say(SpeechSynthesizer *spk, const unsigned char *buffer, size_t length, size_t count, const unsigned char *attributes)
{
int result;
/* add 1 to the length in order to pass along the trailing zero */
result = espeak_Synth(buffer, length+1, 0, POS_CHARACTER, 0,
espeakCHARS_UTF8, NULL, (void *)spk);
if (result != EE_OK)
logMessage(LOG_ERR, "eSpeak-NG: Synth() returned error %d", result);
}
static void
spk_mute(SpeechSynthesizer *spk)
{
espeak_Cancel();
}
static int SynthCallback(short *audio, int numsamples, espeak_EVENT *events)
{
SpeechSynthesizer *spk = events->user_data;
while (events->type != espeakEVENT_LIST_TERMINATED) {
if (events->type == espeakEVENT_WORD)
tellSpeechLocation(spk, events->text_position - 1);
if (events->type == espeakEVENT_MSG_TERMINATED)
tellSpeechFinished(spk);
events++;
}
return 0;
}
static void
spk_drain(SpeechSynthesizer *spk)
{
espeak_Synchronize();
}
static void
spk_setVolume(SpeechSynthesizer *spk, unsigned char setting)
{
int volume = getIntegerSpeechVolume(setting, 50);
espeak_SetParameter(espeakVOLUME, volume, 0);
}
static void
spk_setRate(SpeechSynthesizer *spk, unsigned char setting)
{
int h_range = (maxrate - espeakRATE_MINIMUM)/2;
int rate = getIntegerSpeechRate(setting, h_range) + espeakRATE_MINIMUM;
espeak_SetParameter(espeakRATE, rate, 0);
}
static void
spk_setPitch(SpeechSynthesizer *spk, unsigned char setting)
{
int pitch = getIntegerSpeechPitch(setting, 50);
espeak_SetParameter(espeakPITCH, pitch, 0);
}
static void
spk_setPunctuation(SpeechSynthesizer *spk, SpeechPunctuation setting)
{
espeak_PUNCT_TYPE punct;
if (setting <= SPK_PUNCTUATION_NONE)
punct = espeakPUNCT_NONE;
else if (setting >= SPK_PUNCTUATION_ALL)
punct = espeakPUNCT_ALL;
else
punct = espeakPUNCT_SOME;
espeak_SetParameter(espeakPUNCTUATION, punct, 0);
}
static int spk_construct(SpeechSynthesizer *spk, char **parameters)
{
const char *data_path, *voicename, *punctlist;
int result;
spk->setVolume = spk_setVolume;
spk->setRate = spk_setRate;
spk->setPitch = spk_setPitch;
spk->setPunctuation = spk_setPunctuation;
spk->drain = spk_drain;
logMessage(LOG_INFO, "eSpeak-NG version %s", espeak_Info(NULL));
data_path = parameters[PARM_PATH];
if (data_path && !*data_path)
data_path = NULL;
result = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, 0);
if (result < 0) {
logMessage(LOG_ERR, "eSpeak-NG: initialization failed");
return 0;
}
voicename = parameters[PARM_VOICE];
if(!voicename || !*voicename)
voicename = "en";
result = espeak_SetVoiceByName(voicename);
if (result != EE_OK) {
espeak_VOICE voice_select;
memset(&voice_select, 0, sizeof(voice_select));
voice_select.languages = voicename;
result = espeak_SetVoiceByProperties(&voice_select);
}
if (result != EE_OK) {
logMessage(LOG_ERR, "eSpeak-NG: unable to load voice '%s'", voicename);
return 0;
}
punctlist = parameters[PARM_PUNCTLIST];
if (punctlist && *punctlist) {
wchar_t w_punctlist[strlen(punctlist) + 1];
int i = 0;
while ((w_punctlist[i] = punctlist[i]) != 0) i++;
espeak_SetPunctuationList(w_punctlist);
}
if (parameters[PARM_MAXRATE]) {
int val = atoi(parameters[PARM_MAXRATE]);
if (val > espeakRATE_MINIMUM) maxrate = val;
}
espeak_SetSynthCallback(SynthCallback);
return 1;
}
static void spk_destruct(SpeechSynthesizer *spk)
{
espeak_Cancel();
espeak_Terminate();
}