Index: configure =================================================================== --- flite-1.2-release/configure (.../flite-1.2-orig) (revision 10) +++ flite-1.2-release/configure (.../release-v1.2) (revision 10) @@ -1415,16 +1415,16 @@ echo "$ac_t""no" 1>&6 fi -ac_safe=`echo "sys/asoundlib.h" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for sys/asoundlib.h""... $ac_c" 1>&6 -echo "configure:1421: checking for sys/asoundlib.h" >&5 +ac_safe=`echo "alsa/asoundlib.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for alsa/asoundlib.h""... $ac_c" 1>&6 +echo "configure:1421: checking for alsa/asoundlib.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < +#include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1431: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } @@ -1445,23 +1445,24 @@ echo "$ac_t""yes" 1>&6 AUDIODRIVER="alsa" AUDIODEFS=-DCST_AUDIO_ALSA + AUDIOLIBS=-lasound else echo "$ac_t""no" 1>&6 fi ac_safe=`echo "mmsystem.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for mmsystem.h""... $ac_c" 1>&6 -echo "configure:1455: checking for mmsystem.h" >&5 +echo "configure:1456: checking for mmsystem.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1465: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1466: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* Index: include/cst_sts.h =================================================================== --- flite-1.2-release/include/cst_sts.h (.../flite-1.2-orig) (revision 10) +++ flite-1.2-release/include/cst_sts.h (.../release-v1.2) (revision 10) @@ -47,9 +47,9 @@ /* else where, this information plus the indexes in the Unit relation */ /* allow reconstruction of the signal itself */ struct cst_sts_struct { - const unsigned short *frame; - const int size; /* in samples */ - const unsigned char *residual; + unsigned short *frame; + int size; /* in samples */ + unsigned char *residual; }; typedef struct cst_sts_struct cst_sts; Index: configure.in =================================================================== --- flite-1.2-release/configure.in (.../flite-1.2-orig) (revision 10) +++ flite-1.2-release/configure.in (.../release-v1.2) (revision 10) @@ -131,9 +131,10 @@ AC_CHECK_HEADER(sys/audioio.h, [AUDIODRIVER="sun" AUDIODEFS=-DCST_AUDIO_SUNOS]) -AC_CHECK_HEADER(sys/asoundlib.h, +AC_CHECK_HEADER(alsa/asoundlib.h, [AUDIODRIVER="alsa" - AUDIODEFS=-DCST_AUDIO_ALSA]) + AUDIODEFS=-DCST_AUDIO_ALSA + AUDIOLIBS=-lasound]) AC_CHECK_HEADER(mmsystem.h, [AUDIODRIVER="wince" AUDIODEFS=-DCST_AUDIO_WINCE Index: src/audio/au_alsa.c =================================================================== --- flite-1.2-release/src/audio/au_alsa.c (.../flite-1.2-orig) (revision 10) +++ flite-1.2-release/src/audio/au_alsa.c (.../release-v1.2) (revision 10) @@ -2,7 +2,7 @@ /* */ /* Language Technologies Institute */ /* Carnegie Mellon University */ -/* Copyright (c) 2001 */ +/* Copyright (c) 2000 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ @@ -29,158 +29,283 @@ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ +/*********************************************************************** */ +/* Author: Lukas Loehrer ( */ +/* Date: January 2005 */ /*************************************************************************/ -/* Author: Geoff Harrison (mandrake@cepstral.com) */ -/* Date: Sepetember 2001 */ -/*************************************************************************/ /* */ -/* Access to ALSA audio devices */ -/* */ +/* Native access to alsa audio devices on Linux */ +/* Tested with libasound version 1.0.10 */ /*************************************************************************/ -#include #include #include #include +#include +#include + #include "cst_string.h" #include "cst_wave.h" #include "cst_audio.h" -#include +#include -#include -#include -static int alsa_card = 0, alsa_device = 0; +/*static char *pcm_dev_name = "hw:0,0"; */ +static char *pcm_dev_name ="default"; +static inline void print_pcm_state(snd_pcm_t *handle, char *msg) +{ + fprintf(stderr, "PCM state at %s = %s\n", msg, + snd_pcm_state_name(snd_pcm_state(handle))); +} + cst_audiodev *audio_open_alsa(int sps, int channels, cst_audiofmt fmt) { - snd_pcm_channel_info_t pinfo; - snd_pcm_channel_params_t params; - snd_pcm_channel_setup_t setup; - snd_pcm_t *pcm; - cst_audiodev *ad; - int err; + cst_audiodev *ad; + unsigned int real_rate; + int err; -#ifdef __QNXNTO__ - if (snd_pcm_open_preferred(&pcm,&alsa_card,&alsa_device,SND_PCM_OPEN_PLAYBACK) < 0) - { - cst_errmsg("alsa_audio: failed to open audio device\n"); - cst_error(); - } - if (snd_pcm_plugin_set_disable(pcm,PLUGIN_DISABLE_MMAP) < 0) - { - cst_errmsg("alsa_audio: failed to disable mmap\n"); - snd_pcm_close(pcm); - cst_error(); - } -#else - if (snd_pcm_open(&pcm,alsa_card,alsa_device,SND_PCM_OPEN_PLAYBACK) < 0) - { - cst_errmsg("alsa_audio: failed to open audio device\n"); - cst_error(); - } -#endif + /* alsa specific stuff */ + snd_pcm_t *pcm_handle; + snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; + snd_pcm_hw_params_t *hwparams; + snd_pcm_format_t format; + snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED; + /* Allocate the snd_pcm_hw_params_t structure on the stack. */ + snd_pcm_hw_params_alloca(&hwparams); - memset(&pinfo, 0, sizeof(pinfo)); - memset(¶ms, 0, sizeof(params)); - memset(&setup, 0, sizeof(setup)); + /* Open pcm device */ + err = snd_pcm_open(&pcm_handle, pcm_dev_name, stream, 0); + if (err < 0) + { + cst_errmsg("audio_open_alsa: failed to open audio device %s. %s\n", + pcm_dev_name, snd_strerror(err)); + return NULL; + } - pinfo.channel = SND_PCM_CHANNEL_PLAYBACK; - snd_pcm_plugin_info(pcm,&pinfo); + /* Init hwparams with full configuration space */ + err = snd_pcm_hw_params_any(pcm_handle, hwparams); + if (err < 0) + { + snd_pcm_close(pcm_handle); + cst_errmsg("audio_open_alsa: failed to get hardware parameters from audio device. %s\n", snd_strerror(err)); + return NULL; + } - params.mode = SND_PCM_MODE_BLOCK; - params.channel = SND_PCM_CHANNEL_PLAYBACK; - params.start_mode = SND_PCM_START_DATA; - params.stop_mode = SND_PCM_STOP_STOP; + /* Set access mode */ + err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, access); + if (err < 0) + { + snd_pcm_close(pcm_handle); + cst_errmsg("audio_open_alsa: failed to set access mode. %s.\n", snd_strerror(err)); + return NULL; + } - params.buf.block.frag_size = pinfo.max_fragment_size; - params.buf.block.frags_max = 1; - params.buf.block.frags_min = 1; - - params.format.interleave = 1; - params.format.rate = sps; - params.format.voices = channels; - - switch (fmt) - { - case CST_AUDIO_LINEAR16: + /* Determine matching alsa sample format */ + /* This could be implemented in a more */ + /* flexible way (byte order conversion). */ + switch (fmt) + { + case CST_AUDIO_LINEAR16: if (CST_LITTLE_ENDIAN) - params.format.format = SND_PCM_SFMT_S16_LE; + format = SND_PCM_FORMAT_S16_LE; else - params.format.format = SND_PCM_SFMT_S16_BE; + format = SND_PCM_FORMAT_S16_BE; break; - case CST_AUDIO_LINEAR8: - params.format.format = SND_PCM_SFMT_U8; + case CST_AUDIO_LINEAR8: + format = SND_PCM_FORMAT_U8; break; - case CST_AUDIO_MULAW: - params.format.format = SND_PCM_SFMT_MU_LAW; + case CST_AUDIO_MULAW: + format = SND_PCM_FORMAT_MU_LAW; break; - } + default: + snd_pcm_close(pcm_handle); + cst_errmsg("audio_open_alsa: failed to find suitable format.\n"); + return NULL; + break; + } - if((err = snd_pcm_plugin_params(pcm,¶ms)) < 0) - { - cst_errmsg("alsa_audio params setting failed: %s\n",snd_strerror(err)); - snd_pcm_close(pcm); - cst_error(); - } - if((err = snd_pcm_plugin_setup(pcm,SND_PCM_CHANNEL_PLAYBACK)) > 0) { - cst_errmsg("alsa_audio sound prepare setting failed: %s\n",snd_strerror(err)); - snd_pcm_close(pcm); - cst_error(); - } - if((err = snd_pcm_plugin_prepare(pcm,SND_PCM_CHANNEL_PLAYBACK)) > 0) { - cst_errmsg("alsa_audio sound prepare setting failed: %s\n",snd_strerror(err)); - snd_pcm_close(pcm); - cst_error(); - } + /* Set samble format */ + err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format); + if (err <0) + { + snd_pcm_close(pcm_handle); + cst_errmsg("audio_open_alsa: failed to set format. %s.\n", snd_strerror(err)); + return NULL; + } - pinfo.channel = SND_PCM_CHANNEL_PLAYBACK; - snd_pcm_plugin_info(pcm,&pinfo); + /* Set sample rate near the disired rate */ + real_rate = sps; + err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &real_rate, 0); + if (err < 0) + { + snd_pcm_close(pcm_handle); + cst_errmsg("audio_open_alsa: failed to set sample rate near %d. %s.\n", sps, snd_strerror(err)); + return NULL; + } + /*FIXME: This is probably too strict */ + assert(sps == real_rate); - ad = cst_alloc(cst_audiodev, 1); - ad->platform_data = pcm; - ad->sps = ad->real_sps = sps; - ad->channels = ad->real_channels = channels; - ad->fmt = ad->real_fmt = fmt; + /* Set number of channels */ + assert(channels >0); + err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels); + if (err < 0) + { + snd_pcm_close(pcm_handle); + cst_errmsg("audio_open_alsa: failed to set number of channels to %d. %s.\n", channels, snd_strerror(err)); + return NULL; + } - return ad; + /* Commit hardware parameters */ + err = snd_pcm_hw_params(pcm_handle, hwparams); + if (err < 0) + { + snd_pcm_close(pcm_handle); + cst_errmsg("audio_open_alsa: failed to set hw parameters. %s.\n", snd_strerror(err)); + return NULL; + } + + /* Make sure the device is ready to accept data */ + assert(snd_pcm_state(pcm_handle) == SND_PCM_STATE_PREPARED); + + /* Write hardware parameters to flite audio device data structure */ + ad = cst_alloc(cst_audiodev, 1); + assert(ad != NULL); + ad->real_sps = ad->sps = sps; + ad->real_channels = ad->channels = channels; + ad->real_fmt = ad->fmt = fmt; + ad->platform_data = (void *) pcm_handle; + + return ad; } int audio_close_alsa(cst_audiodev *ad) { - snd_pcm_t *pcm; + int result; + snd_pcm_t *pcm_handle; - if (ad == NULL) - return 0; + if (ad == NULL) + return 0; - pcm = ad->platform_data; - snd_pcm_plugin_flush(pcm,0); - snd_pcm_close(pcm); - cst_free(ad); + pcm_handle = (snd_pcm_t *) ad->platform_data; + result = snd_pcm_close(pcm_handle); + if (result < 0) + { + cst_errmsg("audio_close_alsa: Error: %s.\n", snd_strerror(result)); + } + cst_free(ad); + return result; +} - return 0; +/* Returns zero if recovery was successful. */ +static int recover_from_error(snd_pcm_t *pcm_handle, ssize_t res) +{ + if (res == -EPIPE) /* xrun */ + { + res = snd_pcm_prepare(pcm_handle); + if (res < 0) + { + /* Failed to recover from xrun */ + cst_errmsg("recover_from_write_error: failed to recover from xrun. %s\n.", snd_strerror(res)); + return res; + } + } + else if (res == -ESTRPIPE) /* Suspend */ + { + while ((res = snd_pcm_resume(pcm_handle)) == -EAGAIN) + { + snd_pcm_wait(pcm_handle, 1000); + } + if (res < 0) + { + res = snd_pcm_prepare(pcm_handle); + if (res <0) + { + /* Resume failed */ + cst_errmsg("audio_recover_from_write_error: failed to resume after suspend. %s\n.", snd_strerror(res)); + return res; + } + } + } + else if (res < 0) + { + /* Unknown failure */ + cst_errmsg("audio_recover_from_write_error: %s.\n", snd_strerror(res)); + return res; + } + return 0; } int audio_write_alsa(cst_audiodev *ad, void *samples, int num_bytes) { - snd_pcm_t *pcm = ad->platform_data; + size_t frame_size; + ssize_t num_frames, res; + snd_pcm_t *pcm_handle; + char *buf = (char *) samples; - return snd_pcm_plugin_write(pcm,samples,num_bytes); + /* Determine frame size in bytes */ + frame_size = audio_bps(ad->real_fmt) * ad->real_channels; + /* Require that only complete frames are handed in */ + assert((num_bytes % frame_size) == 0); + num_frames = num_bytes / frame_size; + pcm_handle = (snd_pcm_t *) ad->platform_data; + + while (num_frames > 0) + { + res = snd_pcm_writei(pcm_handle, buf, num_frames); + if (res != num_frames) + { + if (res == -EAGAIN || (res > 0 && res < num_frames)) + { + snd_pcm_wait(pcm_handle, 100); + } + else if (recover_from_error(pcm_handle, res) < 0) + { + return -1; + } + } + + if (res >0) + { + num_frames -= res; + buf += res * frame_size; + } + } + return num_bytes; } int audio_flush_alsa(cst_audiodev *ad) { - snd_pcm_t *pcm = ad->platform_data; - - return snd_pcm_plugin_flush(pcm,0); + int result; + result = snd_pcm_drain((snd_pcm_t *) ad->platform_data); + if (result < 0) + { + cst_errmsg("audio_flush_alsa: Error: %s.\n", snd_strerror(result)); + } + /* Prepare device for more data */ + result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data); +if (result < 0) + { + cst_errmsg("audio_flush_alsa: Error: %s.\n", snd_strerror(result)); + } + return result; } int audio_drain_alsa(cst_audiodev *ad) { - snd_pcm_t *pcm = ad->platform_data; - - return snd_pcm_plugin_playback_drain(pcm); + int result; + result = snd_pcm_drop((snd_pcm_t *) ad->platform_data); + if (result < 0) + { + cst_errmsg("audio_drain_alsa: Error: %s.\n", snd_strerror(result)); + } +/* Prepare device for more data */ + result = snd_pcm_prepare((snd_pcm_t *) ad->platform_data); +if (result < 0) + { + cst_errmsg("audio_drain_alsa: Error: %s.\n", snd_strerror(result)); + } + return result; } - Index: doc/Makefile =================================================================== --- flite-1.2-release/doc/Makefile (.../flite-1.2-orig) (revision 10) +++ flite-1.2-release/doc/Makefile (.../release-v1.2) (revision 10) @@ -53,6 +53,7 @@ @ if [ ! -d html ] ; \ then mkdir -p html ; fi (cd html; texi2html -number -split_chapter ../flite.texi) + mv html/flite/*.html html/ && rmdir html/flite @ for i in html/*.html ; \ do \ sed 's///' $$i >ttt.html; \ Index: config/common_make_rules =================================================================== --- flite-1.2-release/config/common_make_rules (.../flite-1.2-orig) (revision 10) +++ flite-1.2-release/config/common_make_rules (.../release-v1.2) (revision 10) @@ -88,7 +88,7 @@ @ rm -rf shared_os && mkdir shared_os @ rm -f $@ $(LIBDIR)/$@.${PROJECT_VERSION} $(LIBDIR)/$@.${PROJECT_SHLIB_VERSION} @ (cd shared_os && ar x ../$<) - @ (cd shared_os && $(CC) -shared -Wl,-soname,$@.${PROJECT_SHLIB_VERSION} -o ../$@.${PROJECT_VERSION} *.os) + @ (cd shared_os && $(CC) -shared -Wl,-soname,$@.${PROJECT_SHLIB_VERSION} -o ../$@.${PROJECT_VERSION} *.os $(AUDIOLIBS)) @ ln -s $(LIBDIR)/$@.${PROJECT_VERSION} $(LIBDIR)/$@.${PROJECT_SHLIB_VERSION} @ ln -s $(LIBDIR)/$@.${PROJECT_SHLIB_VERSION} $(LIBDIR)/$@ @ rm -rf shared_os