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
+}