Package: flite
Version: 1.2-release-2.2
Severity: wishlist
Tags: patch

Attached is a patch I developed in early 2006 that adds Alsa audio
playback support to flite. By now, the functunality is well tested
mostly via eflite. Alsa support allows TTS users to play other sounds
wile flite is talking. Flite currently uses OSS for audio playback
which is generally deprecated. The patch should apply cleanly to the
Debian modified flite sources. It also selects Alsa as audio playback
method in the debian/rules script.

-- System Information:
Debian Release: lenny/sid
  APT prefers unstable
  APT policy: (800, 'unstable'), (750, 'experimental')
Architecture: i386 (i686)

Kernel: Linux 2.6.20.suspend2
Locale: LANG=en_US.iso88591, LC_CTYPE=en_US.iso88591 (charmap=ISO-8859-1)
Shell: /bin/sh linked to /bin/bash

Versions of packages flite depends on:
ii  libasound2                 1.0.14a-2     ALSA library
ii  libc6                      2.6.1-5       GNU C Library: Shared libraries
ii  libflite1                  1.2-release-3 a small run-time speech synthesis 

flite recommends no packages.

-- no debconf information
diff -uNr flite-1.2-release.orig/config/common_make_rules flite-1.2-release/config/common_make_rules
--- flite-1.2-release.orig/config/common_make_rules	2007-09-08 12:31:31.000000000 +0200
+++ flite-1.2-release/config/common_make_rules	2007-09-08 10:41:25.000000000 +0200
@@ -88,7 +88,7 @@
 	@ rm -rf shared_os && mkdir shared_os
 	@ rm -f $@ $(LIBDIR)/[EMAIL PROTECTED] $(LIBDIR)/[EMAIL PROTECTED] 
 	@ (cd shared_os && ar x ../$<)
-	@ (cd shared_os && $(CC) -shared -Wl,-soname,[EMAIL PROTECTED] -o ../[EMAIL PROTECTED] *.os)
+	@ (cd shared_os && $(CC) -shared -Wl,-soname,[EMAIL PROTECTED] -o ../[EMAIL PROTECTED] *.os $(AUDIOLIBS))
 	@(cd $(LIBDIR); ln -s [EMAIL PROTECTED] [EMAIL PROTECTED]; \
 	  ln -s [EMAIL PROTECTED] $@)
 	@ rm -rf shared_os
diff -uNr flite-1.2-release.orig/configure flite-1.2-release/configure
--- flite-1.2-release.orig/configure	2003-02-18 17:18:20.000000000 +0100
+++ flite-1.2-release/configure	2007-09-08 10:41:25.000000000 +0200
@@ -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 <<EOF
 #line 1426 "configure"
 #include "confdefs.h"
-#include <sys/asoundlib.h>
+#include <alsa/asoundlib.h>
 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
-#line 1460 "configure"
+#line 1461 "configure"
 #include "confdefs.h"
 #include <mmsystem.h>
 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*
diff -uNr flite-1.2-release.orig/configure.in flite-1.2-release/configure.in
--- flite-1.2-release.orig/configure.in	2003-02-18 01:45:45.000000000 +0100
+++ flite-1.2-release/configure.in	2007-09-08 10:41:25.000000000 +0200
@@ -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
diff -uNr flite-1.2-release.orig/debian/rules flite-1.2-release/debian/rules
--- flite-1.2-release.orig/debian/rules	2007-09-08 12:31:31.000000000 +0200
+++ flite-1.2-release/debian/rules	2007-09-08 10:41:38.000000000 +0200
@@ -22,7 +22,7 @@
 	dh_testdir
 	./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) \
 		--prefix=/usr --mandir=\$${prefix}/share/man \
-		--infodir=\$${prefix}/share/info --with-audio=oss --with-vox=cmu_us_kal16 --enable-shared
+		--infodir=\$${prefix}/share/info --with-audio=alsa --with-vox=cmu_us_kal16 --enable-shared
 
 build: build-stamp
 
diff -uNr flite-1.2-release.orig/src/audio/au_alsa.c flite-1.2-release/src/audio/au_alsa.c
--- flite-1.2-release.orig/src/audio/au_alsa.c	2001-12-04 19:05:52.000000000 +0100
+++ flite-1.2-release/src/audio/au_alsa.c	2007-09-08 10:41:25.000000000 +0200
@@ -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 ([EMAIL PROTECTED])           */
-/*               Date:  Sepetember 2001                                  */
-/*************************************************************************/
-/*                                                                       */
-/*  Access to ALSA audio devices                                          */
 /*                                                                       */
+/*  Native access to alsa audio devices on Linux                         */
+/*  Tested with libasound version 1.0.10                                 */
 /*************************************************************************/
 
-#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <assert.h>
+#include <errno.h>
+
 #include "cst_string.h"
 #include "cst_wave.h"
 #include "cst_audio.h"
 
-#include <sys/asoundlib.h>
+#include <alsa/asoundlib.h>
 
-#include <sys/stat.h>
-#include <fcntl.h>
 
-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;
-
-#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
-
-
-    memset(&pinfo, 0, sizeof(pinfo));
-    memset(&params, 0, sizeof(params));
-    memset(&setup, 0, sizeof(setup));
-
-    pinfo.channel = SND_PCM_CHANNEL_PLAYBACK;
-    snd_pcm_plugin_info(pcm,&pinfo);
-
-    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;
-
-    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:
+  cst_audiodev *ad;
+  unsigned 	int real_rate;
+  int err;
+
+  /* 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);
+
+  /* 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;
+  }
+
+  /* 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;
+  }
+
+  /* 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;
+  }
+
+  /* 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:
+	format = SND_PCM_FORMAT_U8;
 	break;
-    case CST_AUDIO_LINEAR8:
-	params.format.format = SND_PCM_SFMT_U8;
+  case CST_AUDIO_MULAW:
+	format = SND_PCM_FORMAT_MU_LAW;
 	break;
-    case CST_AUDIO_MULAW:
-	params.format.format = SND_PCM_SFMT_MU_LAW;
+  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,&params)) < 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();
-    }
-
-    pinfo.channel = SND_PCM_CHANNEL_PLAYBACK;
-    snd_pcm_plugin_info(pcm,&pinfo);
-
-    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 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;
+  }
+
+  /* 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);
+
+  /* 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;
+  }
+
+  /* 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;
+  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;
-
-    return snd_pcm_plugin_write(pcm,samples,num_bytes);
+  size_t frame_size;
+  ssize_t num_frames, res;
+  snd_pcm_t *pcm_handle;
+  char *buf = (char *) samples;
+
+  /* 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;
 }
-

Reply via email to