blob: b18eae295178c8cc67cb9d3bf8f74b835f5880eb [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>.
*/
/* FestivalLite/speech.c - Speech library
* For the Festival Lite text to speech package
* Maintained by Mario Lang <mlang@delysid.org>
*/
#include "prologue.h"
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include "log.h"
#include "parse.h"
typedef enum {
PARM_pitch
} DriverParameter;
#define SPKPARMS "pitch"
#include "spk_driver.h"
#include <flite.h>
#include <flite_version.h>
extern cst_voice * REGISTER_VOX (const char *voxdir);
extern void UNREGISTER_VOX (cst_voice *voice);
static cst_voice *voice = NULL;
static const char *outtype = "play";
static pid_t child = -1;
static int fds[2];
static int *const readfd = &fds[0];
static int *const writefd = &fds[1];
static void
spk_setRate (SpeechSynthesizer *spk, unsigned char setting)
{
feat_set_float(voice->features, "duration_stretch", 1.0/getFloatSpeechRate(setting));
}
static int
spk_construct (SpeechSynthesizer *spk, char **parameters)
{
spk->setRate = spk_setRate;
child = -1;
flite_init();
voice = REGISTER_VOX(NULL);
{
int pitch = 100, minpitch = 50, maxpitch = 200;
if (*parameters[PARM_pitch])
if (!validateInteger(&pitch, parameters[PARM_pitch], &minpitch, &maxpitch))
logMessage(LOG_WARNING, "%s: %s", "invalid pitch specification", parameters[PARM_pitch]);
feat_set_int(voice->features, "int_f0_target_mean", pitch);
}
logMessage(LOG_INFO, "Festival Lite Engine: version %s-%s, %s",
FLITE_PROJECT_VERSION, FLITE_PROJECT_STATE,
FLITE_PROJECT_DATE);
return 1;
}
static void
spk_destruct (SpeechSynthesizer *spk)
{
spk_mute(spk);
UNREGISTER_VOX(voice);
voice = NULL;
}
static int
doChild (void) {
FILE *stream = fdopen(*readfd, "r");
if (stream) {
char buffer[0X400];
char *line;
while ((line = fgets(buffer, sizeof(buffer), stream))) {
flite_text_to_speech(line, voice, outtype);
}
fclose(stream);
}
return 0;
}
static void
spk_say (SpeechSynthesizer *spk, const unsigned char *buffer, size_t length, size_t count, const unsigned char *attributes)
{
if (child != -1) goto ready;
if (pipe(fds) != -1) {
if ((child = fork()) == -1) {
logSystemError("fork");
} else if (child == 0) {
_exit(doChild());
} else
ready: {
unsigned char text[length + 1];
memcpy(text, buffer, length);
text[length] = '\n';
write(*writefd, text, sizeof(text));
return;
}
close(*readfd);
close(*writefd);
} else {
logSystemError("pipe");
}
}
static void
spk_mute (SpeechSynthesizer *spk)
{
if (child != -1) {
close(*readfd);
close(*writefd);
kill(child, SIGKILL);
waitpid(child, NULL, 0);
child = -1;
}
}