[PATCH] executor: play tones using separate process (script voiceman-tone)
Dmitri Paduchikh
dpaduchikh на gmail.com
Пт Фев 22 20:08:27 MSK 2013
---
.gitignore | 2 +
configure.ac | 3 --
executors/default.c | 30 +++++++++---
executors/makefile.am | 19 ++++++--
executors/tone.c | 74 ----------------------------
executors/tonegen.c | 119 +++++++++++++++++++++++++++++++++++++++++++++
executors/voiceman-tone.in | 2 +
m4/ao.m4 | 112 ------------------------------------------
8 files changed, 162 insertions(+), 199 deletions(-)
delete mode 100644 executors/tone.c
create mode 100644 executors/tonegen.c
create mode 100644 executors/voiceman-tone.in
delete mode 100644 m4/ao.m4
diff --git a/.gitignore b/.gitignore
index 9e153fb..fb97c80 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,5 @@ configure
/shell/voiceman
/tools/voiceman-trim
/voiceman.conf
+/executors/tonegen
+/executors/voiceman-tone
diff --git a/configure.ac b/configure.ac
index 310484c..1b0298b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,9 +33,6 @@ if test "x$default_executor" = x; then
default_executor="voiceman-executor"
fi
-# Find the path to libao and set AO_CFLAGS and AO_LIBS
-#XIPH_PATH_AO
-
AC_SUBST(VOICEMAN_INCLUDES, '-I$(top_srcdir)/utils -I$(top_srcdir)/executors')
AC_SUBST(VOICEMAN_DAEMON_INCLUDES, '$(VOICEMAN_INCLUDES) -I$(top_srcdir)/daemon')
diff --git a/executors/default.c b/executors/default.c
index 7073fa6..8347722 100644
--- a/executors/default.c
+++ b/executors/default.c
@@ -36,10 +36,6 @@
#define QUEUE_ITEM_TEXT 1
#define QUEUE_ITEM_TONE 2
-void toneInit();
-void playTone(size_t freq, size_t lengthMs);
-void toneClose();
-
typedef struct QueueItem_
{
int type;
@@ -262,6 +258,30 @@ char isPlaying()
return pid != (pid_t)0 || playerPid != (pid_t)0;
}
+static void playTone(size_t freq, size_t ms)
+{
+ pid_t tonePid;
+ char freqParam[11];
+ char durParam[11];
+ const char *toneprog = BINDIR "/voiceman-tone";
+
+ snprintf(durParam, sizeof(durParam), "%u", (unsigned)ms);
+ snprintf(freqParam, sizeof(freqParam), "%u", (unsigned)freq);
+
+ tonePid = fork();
+ if (tonePid == -1) {
+ perror("fork()");
+ fflush(stderr);
+ return;
+ }
+ if (tonePid == 0) {
+ execl(toneprog, toneprog, durParam, freqParam, (char*)NULL);
+ _exit(EXIT_FAILURE);
+ } else {
+ playerPid = tonePid;
+ }
+}
+
void execute(char* synthCommand, char* playerCommand, char* text)
{
int pp[2];
@@ -597,8 +617,6 @@ int main(int argc, char* argv[])
sigemptyset(&blockedMask);
sigaddset(&blockedMask, SIGCHLD);
sigprocmask(SIG_BLOCK, &blockedMask, &origMask);
- toneInit();
exitCode = mainLoop(STDIN_FILENO, &origMask);
- toneClose();
return exitCode;
}
diff --git a/executors/makefile.am b/executors/makefile.am
index 4351d6e..89c0a59 100644
--- a/executors/makefile.am
+++ b/executors/makefile.am
@@ -1,10 +1,21 @@
-AM_CFLAGS = $(VOICEMAN_CFLAGS) $(AO_CFLAGS) $(VOICEMAN_INCLUDES) -std=gnu99
+AM_CFLAGS = $(VOICEMAN_CFLAGS) $(VOICEMAN_INCLUDES) -std=gnu99
+AM_CPPFLAGS = -DBINDIR=\"$(bindir)\"
bin_PROGRAMS=voiceman-executor
-voiceman_executor_LDADD = -lao -lm
-
voiceman_executor_SOURCES = \
-tone.c \
default.c
+
+pkglibexec_PROGRAMS = tonegen
+tonegen_SOURCES = tonegen.c
+tonegen_LDADD = -lm
+
+dist_noinst_DATA = voiceman-tone.in
+nodist_bin_SCRIPTS = voiceman-tone
+voiceman-tone: voiceman-tone.in makefile
+ sed 's#@dir@#$(pkglibexecdir)#g' $^ >$@.tmp
+ mv -f $@.tmp $@
+
+clean-local:
+ -rm -f voiceman-tone voiceman-tone.tmp
diff --git a/executors/tone.c b/executors/tone.c
deleted file mode 100644
index 311defe..0000000
--- a/executors/tone.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- Copyright (c) 2000-2012 Michael Pozhidaev<msp на altlinux.org>
- This file is part of the VoiceMan speech service.
-
- VoiceMan speech service 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.
-
- VoiceMan speech service 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.
-*/
-
-#include<assert.h>
-#include<stdlib.h>
-#include<math.h>
-#include<strings.h>
-#include<ao/ao.h>
-
-void toneInit()
-{
- ao_initialize();
-}
-
-void toneClose()
-{
- ao_shutdown();
-}
-
-void playTone(size_t fr, size_t lengthMs)
-{
- ao_device *device = NULL;
- ao_sample_format format;
- int default_driver;
- float freq=fr;
- size_t bufSize = 0;
- char* buffer = NULL;
- size_t samplesToPlay = 0;
- size_t i;
- assert(fr >= 0 && lengthMs >= 10);
- bzero(&format, sizeof(ao_sample_format));
- default_driver = ao_default_driver_id();
- format.bits = 16;
- format.channels = 2;
- format.rate = 44100;
- format.byte_format = AO_FMT_LITTLE;
- samplesToPlay = format.rate*lengthMs/1000;
- device = ao_open_live(default_driver, &format, NULL);
- if (device == NULL)
- {
- ao_shutdown();
- return;
- }
- bufSize = format.bits/8 * format.channels * samplesToPlay;
- buffer = (char*)calloc(bufSize, sizeof(char));
- if (buffer == NULL)
- {
- ao_close(device);
- ao_shutdown();
- return;
- }
- for (i = 0; i < samplesToPlay; i++)
- {
- int sample = (int)(0.75 * 32768.0 *
- sin(2 * M_PI * freq * ((float) i/format.rate)));
- buffer[4*i] = buffer[4*i+2] = sample & 0xff;
- buffer[4*i+1] = buffer[4*i+3] = (sample >> 8) & 0xff;
- }
- ao_play(device, buffer, bufSize);
- free(buffer);
- ao_close(device);
-}
diff --git a/executors/tonegen.c b/executors/tonegen.c
new file mode 100644
index 0000000..98ce919
--- /dev/null
+++ b/executors/tonegen.c
@@ -0,0 +1,119 @@
+/*
+ Copyright (c) Dmitri Paduchikh <dpaduchikh на gmail.com>
+
+ This file is part of the VoiceMan speech service.
+
+ VoiceMan speech service 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.
+
+ VoiceMan speech service 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <errno.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ double dur; /* duration in msecs */
+ double freq; /* pitch in Hz */
+ /* sample rate is 22050, S16_LE */
+ const double rate = 22050.0;
+ if (argc != 3) {
+ fprintf(stderr, "%s: usage: tonegen ms freq", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ {
+ char *endptr;
+ dur = strtol(argv[1], &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "%s: incorrect argument: %s\n", argv[0], argv[1]);
+ exit(EXIT_FAILURE);
+ }
+ freq = strtol(argv[2], &endptr, 0);
+ if (*endptr != '\0') {
+ fprintf(stderr, "%s: incorrect argument: %s\n", argv[0], argv[2]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ {
+ int16_t buf[1024];
+ const int bufsize = sizeof(buf)/sizeof(buf[0]);
+ int chunk, written;
+ int i = 0; /* number of samples to be computed */
+ int samples = lround(0.001*dur*rate);
+ double coeff = 2 * M_PI * freq / rate;
+ int fade = lround(0.002*rate);
+
+ while (i < fade && i <= samples) {
+ int j;
+ chunk = samples-i+1 < bufsize? samples-i+1 : bufsize;
+ chunk = fade-i < chunk? fade-i : chunk;
+ for (j = 0; j < chunk; i++, j++)
+ buf[j] = lround(24000.0 * ((double)i / (double)fade) * sin(coeff*i));
+ written = 0;
+ while (written < chunk*sizeof(buf[0])) {
+ int rc = write(1, buf + written, chunk*sizeof(buf[0]) - written);
+ if (rc == -1) {
+ if (errno == EINTR)
+ continue;
+ else {
+ perror("write");
+ exit(EXIT_FAILURE);
+ }
+ }
+ written += rc;
+ }
+ }
+
+ while (i < samples-fade) {
+ int j;
+ chunk = samples-fade-i < bufsize? samples-fade-i : bufsize;
+ for (j = 0; j < chunk; i++, j++)
+ buf[j] = lround(24000.0 * sin(coeff*i));
+ written = 0;
+ while (written < chunk*sizeof(buf[0])) {
+ int rc = write(1, buf + written, chunk*sizeof(buf[0]) - written);
+ if (rc == -1) {
+ if (errno == EINTR)
+ continue;
+ else {
+ perror("write");
+ exit(EXIT_FAILURE);
+ }
+ }
+ written += rc;
+ }
+ }
+
+ while (i <= samples) {
+ int j;
+ chunk = samples-i+1 < bufsize? samples-i+1 : bufsize;
+ for (j = 0; j < chunk; i++, j++)
+ buf[j] = lround(24000.0 * ((double)(samples-i) / (double)fade) * sin(coeff*i));
+ written = 0;
+ while (written < chunk*sizeof(buf[0])) {
+ int rc = write(1, buf + written, chunk*sizeof(buf[0]) - written);
+ if (rc == -1) {
+ if (errno == EINTR)
+ continue;
+ else {
+ perror("write");
+ exit(EXIT_FAILURE);
+ }
+ }
+ written += rc;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/executors/voiceman-tone.in b/executors/voiceman-tone.in
new file mode 100644
index 0000000..f43333a
--- /dev/null
+++ b/executors/voiceman-tone.in
@@ -0,0 +1,2 @@
+#!/bin/sh
+ на dir@/tonegen "$@" | aplay -q -t raw -f S16_LE -r 22050 -c1
diff --git a/m4/ao.m4 b/m4/ao.m4
deleted file mode 100644
index a852ad8..0000000
--- a/m4/ao.m4
+++ /dev/null
@@ -1,112 +0,0 @@
-# ao.m4
-# Configure paths for libao
-# Jack Moffitt <jack на icecast.org> 10-21-2000
-# Shamelessly stolen from Owen Taylor and Manish Singh
-
-dnl XIPH_PATH_AO([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
-dnl Test for libao, and define AO_CFLAGS and AO_LIBS
-dnl
-AC_DEFUN([XIPH_PATH_AO],
-[dnl
-dnl Get the cflags and libraries
-dnl
-AC_ARG_WITH(ao,[ --with-ao=PFX Prefix where libao is installed (optional)], ao_prefix="$withval", ao_prefix="")
-AC_ARG_WITH(ao-libraries,[ --with-ao-libraries=DIR Directory where libao library is installed (optional)], ao_libraries="$withval", ao_libraries="")
-AC_ARG_WITH(ao-includes,[ --with-ao-includes=DIR Directory where libao header files are installed (optional)], ao_includes="$withval", ao_includes="")
-AC_ARG_ENABLE(aotest, [ --disable-aotest Do not try to compile and run a test ao program],, enable_aotest=yes)
-
-
- if test "x$ao_libraries" != "x" ; then
- AO_LIBS="-L$ao_libraries"
- elif test "x$ao_prefix" != "x"; then
- AO_LIBS="-L$ao_prefix/lib"
- elif test "x$prefix" != "xNONE"; then
- AO_LIBS="-L$prefix/lib"
- fi
-
- if test "x$ao_includes" != "x" ; then
- AO_CFLAGS="-I$ao_includes"
- elif test "x$ao_prefix" != "x"; then
- AO_CFLAGS="-I$ao_prefix/include"
- elif test "x$prefix" != "xNONE"; then
- AO_CFLAGS="-I$prefix/include"
- fi
-
- # see where dl* and friends live
- AC_CHECK_FUNCS(dlopen, [AO_DL_LIBS=""], [
- AC_CHECK_LIB(dl, dlopen, [AO_DL_LIBS="-ldl"], [
- AC_MSG_WARN([could not find dlopen() needed by libao sound drivers
- your system may not be supported.])
- ])
- ])
-
- AO_LIBS="$AO_LIBS -lao $AO_DL_LIBS"
-
- AC_MSG_CHECKING(for ao)
- no_ao=""
-
-
- if test "x$enable_aotest" = "xyes" ; then
- ac_save_CFLAGS="$CFLAGS"
- ac_save_LIBS="$LIBS"
- CFLAGS="$CFLAGS $AO_CFLAGS"
- LIBS="$LIBS $AO_LIBS"
-dnl
-dnl Now check if the installed ao is sufficiently new.
-dnl
- rm -f conf.aotest
- AC_TRY_RUN([
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ao/ao.h>
-
-int main ()
-{
- system("touch conf.aotest");
- return 0;
-}
-
-],, no_ao=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
- CFLAGS="$ac_save_CFLAGS"
- LIBS="$ac_save_LIBS"
- fi
-
- if test "x$no_ao" = "x" ; then
- AC_MSG_RESULT(yes)
- ifelse([$1], , :, [$1])
- else
- AC_MSG_RESULT(no)
- if test -f conf.aotest ; then
- :
- else
- echo "*** Could not run ao test program, checking why..."
- CFLAGS="$CFLAGS $AO_CFLAGS"
- LIBS="$LIBS $AO_LIBS"
- AC_TRY_LINK([
-#include <stdio.h>
-#include <ao/ao.h>
-], [ return 0; ],
- [ echo "*** The test program compiled, but did not run. This usually means"
- echo "*** that the run-time linker is not finding ao or finding the wrong"
- echo "*** version of ao. If it is not finding ao, you'll need to set your"
- echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
- echo "*** to the installed location Also, make sure you have run ldconfig if that"
- echo "*** is required on your system"
- echo "***"
- echo "*** If you have an old version installed, it is best to remove it, although"
- echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
- [ echo "*** The test program failed to compile or link. See the file config.log for the"
- echo "*** exact error that occured. This usually means ao was incorrectly installed"
- echo "*** or that you have moved ao since it was installed." ])
- CFLAGS="$ac_save_CFLAGS"
- LIBS="$ac_save_LIBS"
- fi
- AO_CFLAGS=""
- AO_LIBS=""
- ifelse([$2], , :, [$2])
- fi
- AC_SUBST(AO_CFLAGS)
- AC_SUBST(AO_LIBS)
- rm -f conf.aotest
-])
--
1.8.1.4
Подробная информация о списке рассылки Homeros