espeakup/softsynth.c
2009-05-29 23:17:28 -05:00

180 lines
3.4 KiB
C

/*
* espeakup - interface which allows speakup to use espeak
*
* Copyright (C) 2008 William Hubbs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include "espeakup.h"
/* max buffer size */
const size_t maxBufferSize = 1025;
/* synth flush character */
const int synthFlushChar = 0x18;
static int softFD = 0;
static int process_command(struct synth_t *s, char *buf, int start)
{
char *cp;
int value;
enum adjust_t adj;
enum command_t cmd;
cp = buf + start;
switch (*cp) {
case 1:
cp++;
switch (*cp) {
case '+':
adj = ADJ_INC;
cp++;
break;
case '-':
adj = ADJ_DEC;
cp++;
break;
default:
adj = ADJ_SET;
break;
}
value = 0;
while (isdigit(*cp)) {
value = value * 10 + (*cp - '0');
cp++;
}
switch (*cp) {
case 'b':
cmd = CMD_SET_PUNCTUATION;
break;
case 'f':
cmd = CMD_SET_FREQUENCY;
break;
case 'p':
cmd = CMD_SET_PITCH;
break;
case 's':
cmd = CMD_SET_RATE;
break;
case 'v':
cmd = CMD_SET_VOLUME;
break;
default:
cmd = CMD_UNKNOWN;
break;
}
cp++;
break;
default:
cmd = CMD_UNKNOWN;
cp++;
break;
}
if (cmd != CMD_FLUSH && cmd != CMD_UNKNOWN)
queue_add_cmd(cmd, adj, value);
return cp - (buf + start);
}
static void process_buffer(struct synth_t *s, char *buf, ssize_t length)
{
int start;
int end;
char txtBuf[maxBufferSize];
size_t txtLen;
start = 0;
end = 0;
while (start < length) {
while ((buf[end] < 0 || buf[end] >= ' ') && end < length)
end++;
if (end != start) {
txtLen = end - start;
strncpy(txtBuf, buf + start, txtLen);
*(txtBuf + txtLen) = 0;
queue_add_text(txtBuf, txtLen);
}
if (end < length)
start = end = end + process_command(s, buf, end);
else
start = length;
}
}
void open_softsynth(void)
{
softFD = open("/dev/softsynth", O_RDWR | O_NONBLOCK);
if (softFD < 0) {
perror("Unable to open the softsynth device");
exit(3);
}
}
void close_softsynth(void)
{
close(softFD);
}
void main_loop(struct synth_t *s)
{
fd_set set;
ssize_t length;
char buf[maxBufferSize];
char *cp;
while (1) {
FD_ZERO(&set);
FD_SET(softFD, &set);
if (select(softFD + 1, &set, NULL, NULL, NULL) < 0) {
if (errno == EINTR)
continue;
perror("Select failed");
break;
}
if (!FD_ISSET(softFD, &set))
continue;
length = read(softFD, buf, maxBufferSize - 1);
if (length < 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
perror("Read from softsynth failed");
break;
}
*(buf + length) = 0;
cp = strrchr(buf, synthFlushChar);
if (cp) {
queue_clear();
stop_speech();
memmove(buf, cp + 1, strlen(cp + 1) + 1);
length = strlen(buf);
}
process_buffer(s, buf, length);
}
}