|
|
2fbb5d |
diff -uNr flite-1.3-release/configure.in flite-1.3-release-mod/configure.in
|
|
|
2fbb5d |
--- flite-1.3-release/configure.in 2005-08-13 13:43:21.000000000 +0200
|
|
|
2fbb5d |
+++ flite-1.3-release-mod/configure.in 2006-11-13 21:16:27.000000000 +0200
|
|
|
2fbb5d |
@@ -206,10 +206,10 @@
|
|
|
2fbb5d |
AC_CHECK_HEADER(sys/audioio.h,
|
|
|
2fbb5d |
[AUDIODRIVER="sun"
|
|
|
2fbb5d |
AUDIODEFS=-DCST_AUDIO_SUNOS])
|
|
|
2fbb5d |
-dnl AC_CHECK_HEADER(sys/asoundlib.h,
|
|
|
2fbb5d |
-dnl [AUDIODRIVER="alsa"
|
|
|
2fbb5d |
-dnl AUDIODEFS=-DCST_AUDIO_ALSA
|
|
|
2fbb5d |
-dnl AUDIOLIBS=-lasound])
|
|
|
2fbb5d |
+AC_CHECK_HEADER(alsa/asoundlib.h,
|
|
|
2fbb5d |
+ [AUDIODRIVER="alsa"
|
|
|
2fbb5d |
+ AUDIODEFS=-DCST_AUDIO_ALSA
|
|
|
2fbb5d |
+ AUDIOLIBS=-lasound])
|
|
|
2fbb5d |
AC_CHECK_HEADER(mmsystem.h,
|
|
|
2fbb5d |
[AUDIODRIVER="wince"
|
|
|
2fbb5d |
AUDIODEFS=-DCST_AUDIO_WINCE
|
|
|
2fbb5d |
diff -uNr flite-1.3-release/src/audio/au_alsa.c flite-1.3-release-mod/src/audio/au_alsa.c
|
|
|
2fbb5d |
--- flite-1.3-release/src/audio/au_alsa.c 1970-01-01 02:00:00.000000000 +0200
|
|
|
2fbb5d |
+++ flite-1.3-release-mod/src/audio/au_alsa.c 2006-11-13 21:16:54.000000000 +0200
|
|
|
2fbb5d |
@@ -0,0 +1,311 @@
|
|
|
2fbb5d |
+/*************************************************************************/
|
|
|
2fbb5d |
+/* */
|
|
|
2fbb5d |
+/* Language Technologies Institute */
|
|
|
2fbb5d |
+/* Carnegie Mellon University */
|
|
|
2fbb5d |
+/* Copyright (c) 2000 */
|
|
|
2fbb5d |
+/* All Rights Reserved. */
|
|
|
2fbb5d |
+/* */
|
|
|
2fbb5d |
+/* Permission is hereby granted, free of charge, to use and distribute */
|
|
|
2fbb5d |
+/* this software and its documentation without restriction, including */
|
|
|
2fbb5d |
+/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
|
2fbb5d |
+/* distribute, sublicense, and/or sell copies of this work, and to */
|
|
|
2fbb5d |
+/* permit persons to whom this work is furnished to do so, subject to */
|
|
|
2fbb5d |
+/* the following conditions: */
|
|
|
2fbb5d |
+/* 1. The code must retain the above copyright notice, this list of */
|
|
|
2fbb5d |
+/* conditions and the following disclaimer. */
|
|
|
2fbb5d |
+/* 2. Any modifications must be clearly marked as such. */
|
|
|
2fbb5d |
+/* 3. Original authors' names are not deleted. */
|
|
|
2fbb5d |
+/* 4. The authors' names are not used to endorse or promote products */
|
|
|
2fbb5d |
+/* derived from this software without specific prior written */
|
|
|
2fbb5d |
+/* permission. */
|
|
|
2fbb5d |
+/* */
|
|
|
2fbb5d |
+/* CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK */
|
|
|
2fbb5d |
+/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
|
|
|
2fbb5d |
+/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
|
|
|
2fbb5d |
+/* SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE */
|
|
|
2fbb5d |
+/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
|
|
|
2fbb5d |
+/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
|
|
|
2fbb5d |
+/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
|
|
|
2fbb5d |
+/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
|
|
|
2fbb5d |
+/* THIS SOFTWARE. */
|
|
|
2fbb5d |
+/* */
|
|
|
2fbb5d |
+/*********************************************************************** */
|
|
|
2fbb5d |
+/* Author: Lukas Loehrer ( */
|
|
|
2fbb5d |
+/* Date: January 2005 */
|
|
|
2fbb5d |
+/*************************************************************************/
|
|
|
2fbb5d |
+/* */
|
|
|
2fbb5d |
+/* Native access to alsa audio devices on Linux */
|
|
|
2fbb5d |
+/* Tested with libasound version 1.0.10 */
|
|
|
2fbb5d |
+/*************************************************************************/
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+#include <stdlib.h>
|
|
|
2fbb5d |
+#include <unistd.h>
|
|
|
2fbb5d |
+#include <sys/types.h>
|
|
|
2fbb5d |
+#include <assert.h>
|
|
|
2fbb5d |
+#include <errno.h>
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+#include "cst_string.h"
|
|
|
2fbb5d |
+#include "cst_wave.h"
|
|
|
2fbb5d |
+#include "cst_audio.h"
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+#include <alsa/asoundlib.h>
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+/*static char *pcm_dev_name = "hw:0,0"; */
|
|
|
2fbb5d |
+static char *pcm_dev_name ="default";
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+static inline void print_pcm_state(snd_pcm_t *handle, char *msg)
|
|
|
2fbb5d |
+{
|
|
|
2fbb5d |
+ fprintf(stderr, "PCM state at %s = %s\n", msg,
|
|
|
2fbb5d |
+ snd_pcm_state_name(snd_pcm_state(handle)));
|
|
|
2fbb5d |
+}
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+cst_audiodev *audio_open_alsa(int sps, int channels, cst_audiofmt fmt)
|
|
|
2fbb5d |
+{
|
|
|
2fbb5d |
+ cst_audiodev *ad;
|
|
|
2fbb5d |
+ unsigned int real_rate;
|
|
|
2fbb5d |
+ int err;
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* alsa specific stuff */
|
|
|
2fbb5d |
+ snd_pcm_t *pcm_handle;
|
|
|
2fbb5d |
+ snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
|
|
|
2fbb5d |
+ snd_pcm_hw_params_t *hwparams;
|
|
|
2fbb5d |
+ snd_pcm_format_t format;
|
|
|
2fbb5d |
+ snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Allocate the snd_pcm_hw_params_t structure on the stack. */
|
|
|
2fbb5d |
+ snd_pcm_hw_params_alloca(&hwparams);
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Open pcm device */
|
|
|
2fbb5d |
+ err = snd_pcm_open(&pcm_handle, pcm_dev_name, stream, 0);
|
|
|
2fbb5d |
+ if (err < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ cst_errmsg("audio_open_alsa: failed to open audio device %s. %s\n",
|
|
|
2fbb5d |
+ pcm_dev_name, snd_strerror(err));
|
|
|
2fbb5d |
+ return NULL;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Init hwparams with full configuration space */
|
|
|
2fbb5d |
+ err = snd_pcm_hw_params_any(pcm_handle, hwparams);
|
|
|
2fbb5d |
+ if (err < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ snd_pcm_close(pcm_handle);
|
|
|
2fbb5d |
+ cst_errmsg("audio_open_alsa: failed to get hardware parameters from audio device. %s\n", snd_strerror(err));
|
|
|
2fbb5d |
+ return NULL;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Set access mode */
|
|
|
2fbb5d |
+ err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, access);
|
|
|
2fbb5d |
+ if (err < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ snd_pcm_close(pcm_handle);
|
|
|
2fbb5d |
+ cst_errmsg("audio_open_alsa: failed to set access mode. %s.\n", snd_strerror(err));
|
|
|
2fbb5d |
+ return NULL;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Determine matching alsa sample format */
|
|
|
2fbb5d |
+ /* This could be implemented in a more */
|
|
|
2fbb5d |
+ /* flexible way (byte order conversion). */
|
|
|
2fbb5d |
+ switch (fmt)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ case CST_AUDIO_LINEAR16:
|
|
|
2fbb5d |
+ if (CST_LITTLE_ENDIAN)
|
|
|
2fbb5d |
+ format = SND_PCM_FORMAT_S16_LE;
|
|
|
2fbb5d |
+ else
|
|
|
2fbb5d |
+ format = SND_PCM_FORMAT_S16_BE;
|
|
|
2fbb5d |
+ break;
|
|
|
2fbb5d |
+ case CST_AUDIO_LINEAR8:
|
|
|
2fbb5d |
+ format = SND_PCM_FORMAT_U8;
|
|
|
2fbb5d |
+ break;
|
|
|
2fbb5d |
+ case CST_AUDIO_MULAW:
|
|
|
2fbb5d |
+ format = SND_PCM_FORMAT_MU_LAW;
|
|
|
2fbb5d |
+ break;
|
|
|
2fbb5d |
+ default:
|
|
|
2fbb5d |
+ snd_pcm_close(pcm_handle);
|
|
|
2fbb5d |
+ cst_errmsg("audio_open_alsa: failed to find suitable format.\n");
|
|
|
2fbb5d |
+ return NULL;
|
|
|
2fbb5d |
+ break;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Set samble format */
|
|
|
2fbb5d |
+ err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format);
|
|
|
2fbb5d |
+ if (err <0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ snd_pcm_close(pcm_handle);
|
|
|
2fbb5d |
+ cst_errmsg("audio_open_alsa: failed to set format. %s.\n", snd_strerror(err));
|
|
|
2fbb5d |
+ return NULL;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Set sample rate near the disired rate */
|
|
|
2fbb5d |
+ real_rate = sps;
|
|
|
2fbb5d |
+ err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &real_rate, 0);
|
|
|
2fbb5d |
+ if (err < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ snd_pcm_close(pcm_handle);
|
|
|
2fbb5d |
+ cst_errmsg("audio_open_alsa: failed to set sample rate near %d. %s.\n", sps, snd_strerror(err));
|
|
|
2fbb5d |
+ return NULL;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ /*FIXME: This is probably too strict */
|
|
|
2fbb5d |
+ assert(sps == real_rate);
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Set number of channels */
|
|
|
2fbb5d |
+ assert(channels >0);
|
|
|
2fbb5d |
+ err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels);
|
|
|
2fbb5d |
+ if (err < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ snd_pcm_close(pcm_handle);
|
|
|
2fbb5d |
+ cst_errmsg("audio_open_alsa: failed to set number of channels to %d. %s.\n", channels, snd_strerror(err));
|
|
|
2fbb5d |
+ return NULL;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Commit hardware parameters */
|
|
|
2fbb5d |
+ err = snd_pcm_hw_params(pcm_handle, hwparams);
|
|
|
2fbb5d |
+ if (err < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ snd_pcm_close(pcm_handle);
|
|
|
2fbb5d |
+ cst_errmsg("audio_open_alsa: failed to set hw parameters. %s.\n", snd_strerror(err));
|
|
|
2fbb5d |
+ return NULL;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Make sure the device is ready to accept data */
|
|
|
2fbb5d |
+ assert(snd_pcm_state(pcm_handle) == SND_PCM_STATE_PREPARED);
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Write hardware parameters to flite audio device data structure */
|
|
|
2fbb5d |
+ ad = cst_alloc(cst_audiodev, 1);
|
|
|
2fbb5d |
+ assert(ad != NULL);
|
|
|
2fbb5d |
+ ad->real_sps = ad->sps = sps;
|
|
|
2fbb5d |
+ ad->real_channels = ad->channels = channels;
|
|
|
2fbb5d |
+ ad->real_fmt = ad->fmt = fmt;
|
|
|
2fbb5d |
+ ad->platform_data = (void *) pcm_handle;
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ return ad;
|
|
|
2fbb5d |
+}
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+int audio_close_alsa(cst_audiodev *ad)
|
|
|
2fbb5d |
+{
|
|
|
2fbb5d |
+ int result;
|
|
|
2fbb5d |
+ snd_pcm_t *pcm_handle;
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ if (ad == NULL)
|
|
|
2fbb5d |
+ return 0;
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ pcm_handle = (snd_pcm_t *) ad->platform_data;
|
|
|
2fbb5d |
+ result = snd_pcm_close(pcm_handle);
|
|
|
2fbb5d |
+ if (result < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ cst_errmsg("audio_close_alsa: Error: %s.\n", snd_strerror(result));
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ cst_free(ad);
|
|
|
2fbb5d |
+ return result;
|
|
|
2fbb5d |
+}
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+/* Returns zero if recovery was successful. */
|
|
|
2fbb5d |
+static int recover_from_error(snd_pcm_t *pcm_handle, ssize_t res)
|
|
|
2fbb5d |
+{
|
|
|
2fbb5d |
+ if (res == -EPIPE) /* xrun */
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ res = snd_pcm_prepare(pcm_handle);
|
|
|
2fbb5d |
+ if (res < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ /* Failed to recover from xrun */
|
|
|
2fbb5d |
+ cst_errmsg("recover_from_write_error: failed to recover from xrun. %s\n.", snd_strerror(res));
|
|
|
2fbb5d |
+ return res;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ else if (res == -ESTRPIPE) /* Suspend */
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ while ((res = snd_pcm_resume(pcm_handle)) == -EAGAIN)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ snd_pcm_wait(pcm_handle, 1000);
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ if (res < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ res = snd_pcm_prepare(pcm_handle);
|
|
|
2fbb5d |
+ if (res <0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ /* Resume failed */
|
|
|
2fbb5d |
+ cst_errmsg("audio_recover_from_write_error: failed to resume after suspend. %s\n.", snd_strerror(res));
|
|
|
2fbb5d |
+ return res;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ else if (res < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ /* Unknown failure */
|
|
|
2fbb5d |
+ cst_errmsg("audio_recover_from_write_error: %s.\n", snd_strerror(res));
|
|
|
2fbb5d |
+ return res;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ return 0;
|
|
|
2fbb5d |
+}
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+int audio_write_alsa(cst_audiodev *ad, void *samples, int num_bytes)
|
|
|
2fbb5d |
+{
|
|
|
2fbb5d |
+ size_t frame_size;
|
|
|
2fbb5d |
+ ssize_t num_frames, res;
|
|
|
2fbb5d |
+ snd_pcm_t *pcm_handle;
|
|
|
2fbb5d |
+ char *buf = (char *) samples;
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ /* Determine frame size in bytes */
|
|
|
2fbb5d |
+ frame_size = audio_bps(ad->real_fmt) * ad->real_channels;
|
|
|
2fbb5d |
+ /* Require that only complete frames are handed in */
|
|
|
2fbb5d |
+ assert((num_bytes % frame_size) == 0);
|
|
|
2fbb5d |
+ num_frames = num_bytes / frame_size;
|
|
|
2fbb5d |
+ pcm_handle = (snd_pcm_t *) ad->platform_data;
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ while (num_frames > 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ res = snd_pcm_writei(pcm_handle, buf, num_frames);
|
|
|
2fbb5d |
+ if (res != num_frames)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ if (res == -EAGAIN || (res > 0 && res < num_frames))
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ snd_pcm_wait(pcm_handle, 100);
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ else if (recover_from_error(pcm_handle, res) < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ return -1;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+ if (res >0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ num_frames -= res;
|
|
|
2fbb5d |
+ buf += res * frame_size;
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ return num_bytes;
|
|
|
2fbb5d |
+}
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+int audio_flush_alsa(cst_audiodev *ad)
|
|
|
2fbb5d |
+{
|
|
|
2fbb5d |
+ int result;
|
|
|
2fbb5d |
+ result = snd_pcm_drain((snd_pcm_t *) ad->platform_data);
|
|
|
2fbb5d |
+ if (result < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ cst_errmsg("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ /* Prepare device for more data */
|
|
|
2fbb5d |
+ result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
|
|
|
2fbb5d |
+if (result < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ cst_errmsg("audio_flush_alsa: Error: %s.\n", snd_strerror(result));
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ return result;
|
|
|
2fbb5d |
+}
|
|
|
2fbb5d |
+
|
|
|
2fbb5d |
+int audio_drain_alsa(cst_audiodev *ad)
|
|
|
2fbb5d |
+{
|
|
|
2fbb5d |
+ int result;
|
|
|
2fbb5d |
+ result = snd_pcm_drop((snd_pcm_t *) ad->platform_data);
|
|
|
2fbb5d |
+ if (result < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ cst_errmsg("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+/* Prepare device for more data */
|
|
|
2fbb5d |
+ result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data);
|
|
|
2fbb5d |
+if (result < 0)
|
|
|
2fbb5d |
+ {
|
|
|
2fbb5d |
+ cst_errmsg("audio_drain_alsa: Error: %s.\n", snd_strerror(result));
|
|
|
2fbb5d |
+ }
|
|
|
2fbb5d |
+ return result;
|
|
|
2fbb5d |
+}
|