blob: 191a8c9eb7abca95831c043238c5bf53a57810d7 [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 <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "log.h"
#include "parameters.h"
#include "program.h"
#include "file.h"
#include "parse.h"
#include "prefs.h"
#include "utf8.h"
#include "spk.h"
#include "spk_thread.h"
void
constructSpeechSynthesizer (SpeechSynthesizer *spk) {
spk->canAutospeak = 1;
spk->track.isActive = 0;
spk->track.screenNumber = SPK_SCR_NONE;
spk->track.firstLine = 0;
spk->track.speechLocation = SPK_LOC_NONE;
spk->setVolume = NULL;
spk->setRate = NULL;
spk->setPitch = NULL;
spk->setPunctuation = NULL;
spk->drain = NULL;
spk->setFinished = NULL;
spk->setLocation = NULL;
spk->driver.thread = NULL;
spk->driver.data = NULL;
}
void
destructSpeechSynthesizer (SpeechSynthesizer *spk) {
}
int
startSpeechDriverThread (SpeechSynthesizer *spk, char **parameters) {
return constructSpeechDriverThread(spk, parameters);
}
void
stopSpeechDriverThread (SpeechSynthesizer *spk) {
destroySpeechDriverThread(spk);
}
int
muteSpeech (SpeechSynthesizer *spk, const char *reason) {
int result;
logMessage(LOG_CATEGORY(SPEECH_EVENTS), "mute: %s", reason);
result = speechRequest_muteSpeech(spk->driver.thread);
if (spk->setFinished) spk->setFinished(spk);
return result;
}
int
sayUtf8Characters (
SpeechSynthesizer *spk,
const char *text, const unsigned char *attributes,
size_t length, size_t count,
SayOptions options
) {
if (count) {
logMessage(LOG_CATEGORY(SPEECH_EVENTS), "say: %s", text);
if (!speechRequest_sayText(spk->driver.thread, text, length, count, attributes, options)) return 0;
}
return 1;
}
int
sayWideCharacters (
SpeechSynthesizer *spk,
const wchar_t *characters, const unsigned char *attributes,
size_t count, SayOptions options
) {
int ok = 0;
size_t length;
void *text = getUtf8FromWchars(characters, count, &length);
if (text) {
if (sayUtf8Characters(spk, text, attributes, length, count, options)) ok = 1;
free(text);
} else {
logMallocError();
}
return ok;
}
int
sayString (
SpeechSynthesizer *spk,
const char *string, SayOptions options
) {
return sayUtf8Characters(spk, string, NULL, strlen(string), countUtf8Characters(string), options);
}
static int
sayStringSetting (
SpeechSynthesizer *spk,
const char *name, const char *string
) {
char statement[0X40];
snprintf(statement, sizeof(statement), "%s %s", name, string);
return sayString(spk, statement, SAY_OPT_MUTE_FIRST);
}
static int
sayIntegerSetting (
SpeechSynthesizer *spk,
const char *name, int integer
) {
char string[0X10];
snprintf(string, sizeof(string), "%d", integer);
return sayStringSetting(spk, name, string);
}
int
canDrainSpeech (SpeechSynthesizer *spk) {
return spk->drain != NULL;
}
int
drainSpeech (SpeechSynthesizer *spk) {
if (!canDrainSpeech(spk)) return 0;
logMessage(LOG_CATEGORY(SPEECH_EVENTS), "drain speech");
speechRequest_drainSpeech(spk->driver.thread);
return 1;
}
int
canSetSpeechVolume (SpeechSynthesizer *spk) {
return spk->setVolume != NULL;
}
int
toNormalizedSpeechVolume (unsigned char volume) {
return rescaleInteger(volume, SPK_VOLUME_DEFAULT, 100);
}
int
setSpeechVolume (SpeechSynthesizer *spk, int setting, int say) {
if (!canSetSpeechVolume(spk)) return 0;
logMessage(LOG_CATEGORY(SPEECH_EVENTS), "set volume: %d", setting);
speechRequest_setVolume(spk->driver.thread, setting);
if (say) {
sayIntegerSetting(
spk, gettext("volume"),
toNormalizedSpeechVolume(setting)
);
}
return 1;
}
int
canSetSpeechRate (SpeechSynthesizer *spk) {
return spk->setRate != NULL;
}
int
toNormalizedSpeechRate (unsigned char rate) {
return rate - SPK_RATE_DEFAULT;
}
int
setSpeechRate (SpeechSynthesizer *spk, int setting, int say) {
if (!canSetSpeechRate(spk)) return 0;
logMessage(LOG_CATEGORY(SPEECH_EVENTS), "set rate: %d", setting);
speechRequest_setRate(spk->driver.thread, setting);
if (say) {
sayIntegerSetting(
spk, gettext("rate"),
toNormalizedSpeechRate(setting)
);
}
return 1;
}
int
canSetSpeechPitch (SpeechSynthesizer *spk) {
return spk->setPitch != NULL;
}
int
toNormalizedSpeechPitch (unsigned char pitch) {
return pitch - SPK_PITCH_DEFAULT;
}
int
setSpeechPitch (SpeechSynthesizer *spk, int setting, int say) {
if (!canSetSpeechPitch(spk)) return 0;
logMessage(LOG_CATEGORY(SPEECH_EVENTS), "set pitch: %d", setting);
speechRequest_setPitch(spk->driver.thread, setting);
if (say) {
sayIntegerSetting(
spk, gettext("pitch"),
toNormalizedSpeechPitch(setting)
);
}
return 1;
}
int
canSetSpeechPunctuation (SpeechSynthesizer *spk) {
return spk->setPunctuation != NULL;
}
int
setSpeechPunctuation (SpeechSynthesizer *spk, SpeechPunctuation setting, int say) {
if (!canSetSpeechPunctuation(spk)) return 0;
logMessage(LOG_CATEGORY(SPEECH_EVENTS), "set punctuation: %d", setting);
speechRequest_setPunctuation(spk->driver.thread, setting);
return 1;
}