| /* |
| * 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; |
| } |
| } |