added queueing support

I have added queueing support so that when we read from the softsynth we
can put the text and commands we have read into a queue.  This will
allow us to retry calling espeak_synth() if we fill espeak's internal
buffer.
This commit is contained in:
William Hubbs 2008-08-16 19:48:40 -05:00
commit 655894ee2a
6 changed files with 288 additions and 93 deletions

View file

@ -2,26 +2,19 @@ CC = cc
INSTALL = /usr/bin/install
RM = /bin/rm -f
PREFIX = /usr
BINDIR = $(PREFIX)/bin
LDLIBS = -lespeak
SRCS = \
espeakup.c \
queue.c \
softsynth.c \
synth.c
OBJS = $(SRCS:.c=.o)
ifeq ("$(origin TAG)", "command line")
TIMESTAMP := _p$(shell date +%Y%m%d)
endif
CFLAGS = -ggdb
LDLIBS = -lespeak
VERSION := $(shell grep 'Version.*=' espeakup.c | sed 's/.*"\(.*\)";/\1/')
TAG := v$(VERSION)
TARPREFIX := espeakup-$(VERSION)
TARFILE := $(TARPREFIX)$(TIMESTAMP).tar
PREFIX = /usr
BINDIR = $(PREFIX)/bin
all: espeakup
@ -37,6 +30,15 @@ distclean: clean
espeakup: $(OBJS)
ifeq ("$(origin TAG)", "command line")
TIMESTAMP := _p$(shell date +%Y%m%d)
endif
VERSION := $(shell grep 'Version.*=' espeakup.c | sed 's/.*"\(.*\)";/\1/')
TAG := v$(VERSION)
TARPREFIX := espeakup-$(VERSION)
TARFILE := $(TARPREFIX)$(TIMESTAMP).tar
tarball:
git archive --format=tar --prefix=$(TARPREFIX)/ $(TAG) > $(TARFILE)
tar f $(TARFILE) --delete $(TARPREFIX)/.gitignore

View file

@ -35,6 +35,12 @@ const char *shortOptions = "dhv";
/* path to our pid file */
const char *pidPath = "/var/run/espeakup.pid";
/* default voice settings */
const int defaultFrequency = 5;
const int defaultPitch = 5;
const int defaultRate = 5;
const int defaultVolume = 5;
int debug = 0;
int espeakup_is_running(void)
@ -123,13 +129,7 @@ void process_cli(int argc, char **argv)
int main(int argc, char **argv)
{
struct synth_t s = {
.frequency = 5,
.pitch = 5,
.rate = 5,
.voice = "default",
.volume = 5,
};
struct synth_t s;
/* process command line options */
process_cli(argc, argv);
@ -158,11 +158,10 @@ int main(int argc, char **argv)
espeak_SetSynthCallback(SynthCallback);
/* Setup initial voice parameters */
set_voice(&s);
set_frequency (&s);
set_pitch (&s);
set_rate (&s);
set_volume(&s);
set_frequency (&s, defaultFrequency, ADJ_SET);
set_pitch (&s, defaultPitch, ADJ_SET);
set_rate (&s, defaultRate, ADJ_SET);
set_volume(&s, defaultVolume, ADJ_SET);
/* register signal handler */
signal(SIGINT, espeakup_sighandler);

View file

@ -22,6 +22,23 @@
#include <espeak/speak_lib.h>
enum command_t {
CMD_SET_FREQUENCY,
CMD_SET_PITCH,
CMD_SET_RATE,
CMD_SET_VOICE,
CMD_SET_VOLUME,
CMD_SPEAK_TEXT,
CMD_FLUSH,
CMD_UNKNOWN,
};
enum adjust_t {
ADJ_DEC,
ADJ_SET,
ADJ_INC,
};
struct synth_t {
int frequency;
int pitch;
@ -35,11 +52,11 @@ struct synth_t {
extern int debug;
extern int SynthCallback(short *wav, int numsamples, espeak_EVENT *events);
extern espeak_ERROR set_frequency (struct synth_t *s);
extern espeak_ERROR set_pitch (struct synth_t *s);
extern espeak_ERROR set_rate (struct synth_t *s);
extern espeak_ERROR set_frequency(struct synth_t *s, int freq, enum adjust_t adj);
extern espeak_ERROR set_pitch (struct synth_t *s, int pitch, enum adjust_t adj);
extern espeak_ERROR set_rate (struct synth_t *s, int rate, enum adjust_t adj);
extern espeak_ERROR set_voice(struct synth_t *s);
extern espeak_ERROR set_volume (struct synth_t *s);
extern espeak_ERROR set_volume (struct synth_t *s, int vol, enum adjust_t adj);
extern espeak_ERROR stop_speech(void);
extern espeak_ERROR speak_text(struct synth_t *s);
extern void open_softsynth(void);

139
queue.c Normal file
View file

@ -0,0 +1,139 @@
/*
* 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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "espeakup.h"
struct queue_entry_t {
enum command_t cmd;
enum adjust_t adjust;
int value;
char *buf;
int len;
struct queue_entry_t *next;
};
static struct queue_entry_t *first = NULL;
static struct queue_entry_t *last = NULL;
static void queue_add(struct queue_entry_t *entry)
{
assert(entry);
entry->next = NULL;
if (! last)
last = entry;
if (! first) {
first = entry;
} else {
first->next = entry;
first = first->next;
}
}
static void queue_remove(void)
{
struct queue_entry_t *temp;
assert(last);
temp = last;
last = temp->next;
if (temp->cmd == CMD_SPEAK_TEXT)
free(temp->buf);
free(temp);
if (! last)
first = last;
}
void queue_clear(void)
{
while(last)
queue_remove();
}
void queue_add_cmd(enum command_t cmd, enum adjust_t adj, int value)
{
struct queue_entry_t *entry;
entry = malloc(sizeof(struct queue_entry_t));
if (! entry) {
perror("unable to allocate memory for queue entry");
return;
}
entry->cmd = cmd;
entry->adjust = adj;
entry->value = value;
queue_add(entry);
}
void queue_add_text(char *txt, size_t length)
{
struct queue_entry_t *entry;
entry = malloc(sizeof(struct queue_entry_t));
if (! entry) {
perror("unable to allocate memory for queue entry");
return;
}
entry->cmd = CMD_SPEAK_TEXT;
entry->adjust = ADJ_SET;
entry->buf = strdup(txt);
if (! entry->buf) {
perror("unable to allocate space for text");
free(entry);
return;
}
entry->len = length;
queue_add(entry);
}
void queue_process_entry(struct synth_t *s)
{
espeak_ERROR error;
if(! last)
return;
switch (last->cmd) {
case CMD_SET_FREQUENCY:
error = set_frequency(s, last->value, last->adjust);
break;
case CMD_SET_PITCH:
error = set_pitch(s, last->value, last->adjust);
break;
case CMD_SET_RATE:
error = set_rate(s, last->value, last->adjust);
break;
case CMD_SET_VOICE:
break;
case CMD_SET_VOLUME:
error = set_volume(s, last->value, last->adjust);
break;
case CMD_SPEAK_TEXT:
s->buf = last->buf;
s->len = last->len;
error = speak_text(s);
break;
}
if (error == EE_OK)
queue_remove();
}

View file

@ -26,72 +26,74 @@
#include "espeakup.h"
/* max buffer size */
const int maxBufferSize = 1025;
const size_t maxBufferSize = 1025;
static int softFD = 0;
static int process_command(struct synth_t *s, char *buf, int start)
{
int rc;
char value;
char param;
char *cp;
int value;
enum adjust_t adj;
enum command_t cmd;
rc = 1;
switch (buf[start]) {
cp = buf+start;
switch (*cp) {
case 1:
if (buf[start+1] == '+' || buf[start+1] == '-') {
value = buf[start+2]-'0';
param = buf[start+3];
if (buf[start+1] == '-')
value = -value;
switch (param) {
case 'f':
s->frequency += value;
set_frequency (s);
break;
case 'p':
s->pitch += value;
set_pitch (s);
break;
case 's':
s->rate += value;
set_rate (s);
break;
case 'v':
s->volume += value;
set_volume (s);
break;
}
rc = 4;
} else if (buf[start+1] >= '0' && buf[start+1] <= '9') {
value = buf[start+1]-'0';
param = buf[start+2];
switch (param) {
case 'f':
s->frequency = value;
set_frequency (s);
break;
case 'p':
s->pitch = value;
set_pitch (s);
break;
case 's':
s->rate = value;
set_rate (s);
break;
case 'v':
s->volume = value;
set_volume (s);
break;
}
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 'f':
cmd = CMD_SET_FREQUENCY;
cp++;
break;
case 'p':
cmd = CMD_SET_PITCH;
cp++;
break;
case 's':
cmd = CMD_SET_RATE;
cp++;
break;
case 'v':
cmd = CMD_SET_VOLUME;
cp++;
break;
}
rc = 3;
break;
case 24:
cmd = CMD_FLUSH;
stop_speech();
queue_clear();
cp++;
break;
default:
cmd = CMD_UNKNOWN;
cp++;
break;
}
return rc;
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, size_t length)
@ -110,9 +112,7 @@ static void process_buffer (struct synth_t *s, char *buf, size_t length)
txtLen = end-start;
strncpy (txtBuf, buf + start, txtLen);
*(txtBuf+txtLen) = 0;
s->buf = txtBuf;
s->len = txtLen;
speak_text(s);
queue_add_text(txtBuf, txtLen);
}
if (end < length)
start = end = end+process_command (s, buf, end);
@ -141,11 +141,13 @@ void main_loop (struct synth_t *s)
int i;
size_t length;
char buf[maxBufferSize];
struct timeval tv = {0, 0};
while (1) {
queue_process_entry(s);
FD_ZERO (&set);
FD_SET (softFD, &set);
i = select (softFD+1, &set, NULL, NULL, NULL);
i = select (softFD+1, &set, NULL, NULL, &tv);
if (i < 0) {
if (errno == EINTR)
continue;
@ -153,8 +155,12 @@ void main_loop (struct synth_t *s)
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;
}

48
synth.c
View file

@ -31,19 +31,46 @@ int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
return 0;
}
espeak_ERROR set_frequency (struct synth_t *s)
espeak_ERROR set_frequency (struct synth_t *s, int freq, enum adjust_t adj)
{
return (espeak_SetParameter(espeakRANGE, s->frequency * frequencyMultiplier, 0));
espeak_ERROR rc;
if (adj == ADJ_DEC)
freq = -freq;
if (adj != ADJ_SET)
freq += s->frequency;
rc = espeak_SetParameter(espeakRANGE, freq * frequencyMultiplier, 0);
if (rc == EE_OK)
s->frequency = freq;
return rc;
}
espeak_ERROR set_pitch (struct synth_t *s)
espeak_ERROR set_pitch (struct synth_t *s, int pitch, enum adjust_t adj)
{
return (espeak_SetParameter(espeakPITCH, s->pitch * pitchMultiplier, 0));
espeak_ERROR rc;
if (adj == ADJ_DEC)
pitch = -pitch;
if (adj != ADJ_SET)
pitch += s->pitch;
rc = espeak_SetParameter(espeakPITCH, pitch * pitchMultiplier, 0);
if (rc == EE_OK)
s->pitch = pitch;
return rc;
}
espeak_ERROR set_rate (struct synth_t *s)
espeak_ERROR set_rate (struct synth_t *s, int rate, enum adjust_t adj)
{
return (espeak_SetParameter(espeakRATE, s->rate * rateMultiplier + rateOffset, 0));
espeak_ERROR rc;
if (adj == ADJ_DEC)
rate = -rate;
if (adj != ADJ_SET)
rate += s->rate;
rc = espeak_SetParameter(espeakRATE, rate * rateMultiplier + rateOffset, 0);
if (rc == EE_OK)
s->rate = rate;
return rc;
}
espeak_ERROR set_voice(struct synth_t *s)
@ -51,9 +78,14 @@ espeak_ERROR set_voice(struct synth_t *s)
return (espeak_SetVoiceByName(s->voice));
}
espeak_ERROR set_volume (struct synth_t *s)
espeak_ERROR set_volume (struct synth_t *s, int vol, enum adjust_t adj)
{
return (espeak_SetParameter(espeakVOLUME, (s->volume+1) * volumeMultiplier, 0));
espeak_ERROR rc;
rc = espeak_SetParameter(espeakVOLUME, (vol+1) * volumeMultiplier, 0);
if (rc == EE_OK)
s->volume = vol;
}
espeak_ERROR stop_speech(void)