PageRenderTime 112ms CodeModel.GetById 16ms app.highlight 88ms RepoModel.GetById 1ms app.codeStats 1ms

/native/external/espeak/src/wave.cpp

http://eyes-free.googlecode.com/
C++ | 1083 lines | 713 code | 157 blank | 213 comment | 108 complexity | e2724a9893fe25e701256787f0619c31 MD5 | raw file
   1/***************************************************************************
   2 *   Copyright (C) 2007, Gilles Casse <gcasse@oralux.org>                  *
   3 *   based on AudioIO.cc (Audacity-1.2.4b) and wavegen.cpp                 *
   4 *                                                                         *
   5 *   This program is free software; you can redistribute it and/or modify  *
   6 *   it under the terms of the GNU General Public License as published by  *
   7 *   the Free Software Foundation; either version 3 of the License, or     *
   8 *   (at your option) any later version.                                   *
   9 *                                                                         *
  10 *   This program is distributed in the hope that it will be useful,       *
  11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
  12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
  13 *   GNU General Public License for more details.                          *
  14 *                                                                         *
  15 *   You should have received a copy of the GNU General Public License     *
  16 *   along with this program; if not, write to the                         *
  17 *   Free Software Foundation, Inc.,                                       *
  18 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  19 ***************************************************************************/
  20
  21#include "speech.h"
  22
  23#ifdef USE_ASYNC
  24// This source file is only used for asynchronious modes
  25
  26#include <stdio.h>
  27#include <string.h>
  28#include <stdlib.h>
  29#include <math.h>
  30#include <assert.h>
  31#include <sys/time.h>
  32#include <time.h>
  33
  34#include "portaudio.h"
  35#ifndef PLATFORM_WINDOWS
  36#include <unistd.h>
  37#endif
  38#include "wave.h"
  39#include "debug.h"
  40
  41//<Definitions
  42
  43enum {ONE_BILLION=1000000000};
  44
  45#ifdef USE_PORTAUDIO
  46
  47#undef USE_PORTAUDIO
  48// determine portaudio version by looking for a #define which is not in V18
  49#ifdef paNeverDropInput
  50#define USE_PORTAUDIO   19
  51#else
  52#define USE_PORTAUDIO   18
  53#endif
  54
  55
  56static t_wave_callback* my_callback_is_output_enabled=NULL;
  57
  58#define N_WAV_BUF   10
  59#define SAMPLE_RATE 22050
  60#define FRAMES_PER_BUFFER 512
  61#define BUFFER_LENGTH (SAMPLE_RATE*2*sizeof(uint16_t))
  62#define THRESHOLD (BUFFER_LENGTH/5)
  63static char myBuffer[BUFFER_LENGTH];
  64static char* myRead=NULL; 
  65static char* myWrite=NULL; 
  66static int out_channels=1;
  67static int my_stream_could_start=0;
  68
  69static int mInCallbackFinishedState = false;
  70#if (USE_PORTAUDIO == 18)
  71static PortAudioStream *pa_stream=NULL;
  72#endif
  73#if (USE_PORTAUDIO == 19)
  74static struct PaStreamParameters myOutputParameters;
  75static PaStream *pa_stream=NULL;
  76#endif
  77
  78static int userdata[4];
  79static PaError pa_init_err=0;
  80
  81// time measurement
  82// The read and write position audio stream in the audio stream are measured in ms.
  83// 
  84// * When the stream is opened, myReadPosition and myWritePosition are cleared.
  85// * myWritePosition is updated in wave_write.
  86// * myReadPosition is updated in pa_callback (+ sample delay).
  87
  88static uint32_t myReadPosition = 0; // in ms
  89static uint32_t myWritePosition = 0;
  90
  91//>
  92//<init_buffer, get_used_mem
  93
  94static void init_buffer()
  95{
  96  myWrite = myBuffer;
  97  myRead = myBuffer;
  98  memset(myBuffer,0,BUFFER_LENGTH);
  99  myReadPosition = myWritePosition = 0;
 100  SHOW("init_buffer > myRead=0x%x, myWrite=0x%x, BUFFER_LENGTH=0x%x, myReadPosition = myWritePosition = 0\n", (int)myRead, (int)myWrite, BUFFER_LENGTH);
 101}
 102
 103static unsigned int get_used_mem()
 104{
 105  char* aRead = myRead;
 106  char* aWrite = myWrite;
 107  unsigned int used = 0;
 108
 109  assert ((aRead >= myBuffer)
 110	  && (aRead <= myBuffer + BUFFER_LENGTH)
 111	  && (aWrite >= myBuffer)
 112	  && (aWrite <= myBuffer + BUFFER_LENGTH));
 113
 114  if (aRead < aWrite)
 115    {
 116      used = aWrite - aRead;
 117    }
 118  else
 119    {
 120      used = aWrite + BUFFER_LENGTH - aRead;
 121    }
 122  SHOW("get_used_mem > %d\n", used);
 123
 124  return used;
 125}
 126
 127//>
 128//<start stream
 129
 130static void start_stream()
 131{
 132  PaError err;
 133  SHOW_TIME("start_stream");
 134
 135  my_stream_could_start=0;  
 136  mInCallbackFinishedState = false;
 137
 138  err = Pa_StartStream(pa_stream);
 139  SHOW("start_stream > Pa_StartStream=%d (%s)\n", err, Pa_GetErrorText(err));
 140  
 141#if USE_PORTAUDIO == 19
 142  if(err == paStreamIsNotStopped)
 143    {
 144      SHOW_TIME("start_stream > restart stream (begin)");
 145      // not sure why we need this, but PA v19 seems to need it
 146      err = Pa_StopStream(pa_stream);
 147      SHOW("start_stream > Pa_StopStream=%d (%s)\n", err, Pa_GetErrorText(err));
 148      err = Pa_StartStream(pa_stream);
 149      SHOW("start_stream > Pa_StartStream=%d (%s)\n", err, Pa_GetErrorText(err));
 150      SHOW_TIME("start_stream > restart stream (end)");
 151    }
 152#endif
 153}
 154
 155//>
 156//<pa_callback
 157
 158/* This routine will be called by the PortAudio engine when audio is needed.
 159** It may called at interrupt level on some machines so don't do anything
 160** that could mess up the system like calling malloc() or free().
 161*/
 162#if USE_PORTAUDIO == 18
 163static int pa_callback(void *inputBuffer, void *outputBuffer,
 164			unsigned long framesPerBuffer, PaTimestamp outTime, void *userData )
 165#else
 166  static int pa_callback(const void *inputBuffer, void *outputBuffer,
 167			  long unsigned int framesPerBuffer, const PaStreamCallbackTimeInfo *outTime,
 168			  PaStreamCallbackFlags flags, void *userData )
 169#endif
 170{
 171  int aResult=0; // paContinue
 172  char* aWrite = myWrite;
 173  size_t n = out_channels*sizeof(uint16_t)*framesPerBuffer;
 174
 175  myReadPosition += framesPerBuffer;
 176  SHOW("pa_callback > myReadPosition=%u, framesPerBuffer=%lu (n=0x%x) \n",(int)myReadPosition, framesPerBuffer, n);
 177
 178  if (aWrite >= myRead)
 179    {
 180      if((size_t)(aWrite - myRead) >= n)
 181	{
 182	  memcpy(outputBuffer, myRead, n);
 183	  myRead += n;
 184	}
 185      else
 186	{
 187	  SHOW_TIME("pa_callback > underflow");
 188	  aResult=1; // paComplete;
 189	  mInCallbackFinishedState = true;
 190	  size_t aUsedMem=0;
 191	  aUsedMem = (size_t)(aWrite - myRead);
 192	  if (aUsedMem)
 193	    {
 194	      memcpy(outputBuffer, myRead, aUsedMem);
 195	    }
 196	  char* p = (char*)outputBuffer + aUsedMem;
 197	  memset(p, 0, n - aUsedMem); 
 198	  //	  myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t));
 199	  myRead = aWrite;
 200	}
 201    }
 202  else // myRead > aWrite
 203    {
 204      if ((size_t)(myBuffer + BUFFER_LENGTH - myRead) >= n)
 205	{
 206	  memcpy(outputBuffer, myRead, n);
 207	  myRead += n;
 208	}
 209      else if ((size_t)(aWrite + BUFFER_LENGTH - myRead) >= n)
 210	{
 211	  int aTopMem = myBuffer + BUFFER_LENGTH - myRead;
 212	  if (aTopMem)
 213	    {
 214	      SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n",(int)myRead, (int)aTopMem);
 215	      memcpy(outputBuffer, myRead, aTopMem);
 216	    }
 217	  int aRest = n - aTopMem;
 218	  if (aRest)
 219	    {
 220	      SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n",(int)myRead, (int)aRest);
 221	      char* p = (char*)outputBuffer + aTopMem;
 222	      memcpy(p, myBuffer, aRest);
 223	    }
 224	  myRead = myBuffer + aRest;
 225	}
 226      else
 227	{ 
 228	  SHOW_TIME("pa_callback > underflow");
 229	  aResult=1; // paComplete;
 230
 231	  int aTopMem = myBuffer + BUFFER_LENGTH - myRead;
 232	  if (aTopMem)
 233	    {
 234	      SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n",(int)myRead, (int)aTopMem);
 235	      memcpy(outputBuffer, myRead, aTopMem);
 236	    }
 237	  int aRest = aWrite - myBuffer;
 238	  if (aRest)
 239	    {
 240	      SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n",(int)myRead, (int)aRest);
 241	      char* p = (char*)outputBuffer + aTopMem;
 242	      memcpy(p, myBuffer, aRest);
 243	    }
 244
 245	  size_t aUsedMem = aTopMem + aRest;
 246	  char* p = (char*)outputBuffer + aUsedMem;
 247	  memset(p, 0, n - aUsedMem); 
 248	  //	  myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t));
 249	  myRead = aWrite;
 250	}
 251    }
 252
 253  SHOW("pa_callback > myRead=%x\n",(int)myRead);
 254
 255
 256  // #if USE_PORTAUDIO == 18
 257  //   if(aBufferEmpty)
 258  //     {
 259  //       static int end_timer = 0;
 260  //       if(end_timer == 0)
 261  // 	end_timer = 4;
 262  //       if(end_timer > 0)
 263  // 	{
 264  // 	  end_timer--;
 265  // 	  if(end_timer == 0)
 266  // 	    return(1);
 267  // 	}
 268  //     }
 269  //   return(0);
 270  // #else
 271
 272#ifdef ARCH_BIG
 273	{
 274		// BIG-ENDIAN, swap the order of bytes in each sound sample in the portaudio buffer
 275		int c;
 276		unsigned char *out_ptr;
 277		unsigned char *out_end;
 278		out_ptr = (unsigned char *)outputBuffer;
 279		out_end = out_ptr + framesPerBuffer*2 * out_channels;
 280		while(out_ptr < out_end)
 281		{
 282			c = out_ptr[0];
 283			out_ptr[0] = out_ptr[1];
 284			out_ptr[1] = c;
 285			out_ptr += 2;
 286		}
 287	}
 288#endif
 289
 290
 291  return(aResult);
 292  //#endif
 293
 294}  //  end of WaveCallBack
 295
 296//>
 297
 298
 299void wave_flush(void* theHandler)
 300{
 301  ENTER("wave_flush");
 302
 303  if (my_stream_could_start)
 304    {
 305//       #define buf 1024
 306//       static char a_buffer[buf*2];
 307//       memset(a_buffer,0,buf*2);
 308//       wave_write(theHandler, a_buffer, buf*2);
 309      start_stream();
 310    }
 311}
 312
 313//<wave_open_sound
 314
 315static int wave_open_sound()
 316{
 317  ENTER("wave_open_sound");
 318
 319  PaError err=paNoError;
 320  PaError active;
 321
 322#if USE_PORTAUDIO == 18
 323  active = Pa_StreamActive(pa_stream);
 324#else
 325  active = Pa_IsStreamActive(pa_stream);
 326#endif
 327
 328  if(active == 1)
 329    {
 330      SHOW_TIME("wave_open_sound > already active");
 331      return(0);
 332    }
 333  if(active < 0)
 334    {
 335      out_channels = 1;
 336
 337#if USE_PORTAUDIO == 18
 338      //      err = Pa_OpenDefaultStream(&pa_stream,0,1,paInt16,SAMPLE_RATE,FRAMES_PER_BUFFER,N_WAV_BUF,pa_callback,(void *)userdata);
 339
 340   PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID();
 341
 342   PaError err = Pa_OpenStream( &pa_stream,
 343				/* capture parameters */
 344				paNoDevice,
 345				0,
 346				paInt16,
 347				NULL,
 348				/* playback parameters */
 349				playbackDevice,
 350				out_channels,
 351				paInt16,
 352				NULL,
 353				/* general parameters */
 354				SAMPLE_RATE, FRAMES_PER_BUFFER, 0,
 355				//paClipOff | paDitherOff,
 356				paNoFlag,
 357				pa_callback, (void *)userdata);
 358   
 359      SHOW("wave_open_sound > Pa_OpenDefaultStream(1): err=%d (%s)\n",err, Pa_GetErrorText(err));      
 360
 361      if(err == paInvalidChannelCount)
 362	{
 363	  SHOW_TIME("wave_open_sound > try stereo");
 364	  // failed to open with mono, try stereo
 365	  out_channels = 2;
 366	  //	  myOutputParameters.channelCount = out_channels;
 367	  PaError err = Pa_OpenStream( &pa_stream,
 368				       /* capture parameters */
 369				       paNoDevice,
 370				       0,
 371				       paInt16,
 372				       NULL,
 373				       /* playback parameters */
 374				       playbackDevice,
 375				       out_channels,
 376				       paInt16,
 377				       NULL,
 378				       /* general parameters */
 379				       SAMPLE_RATE, FRAMES_PER_BUFFER, 0,
 380				       //paClipOff | paDitherOff,
 381				       paNoFlag,
 382				       pa_callback, (void *)userdata);
 383// 	  err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16,
 384// 				     SAMPLE_RATE,
 385// 				     FRAMES_PER_BUFFER,
 386// 				     N_WAV_BUF,pa_callback,(void *)userdata);
 387	  SHOW("wave_open_sound > Pa_OpenDefaultStream(2): err=%d (%s)\n",err, Pa_GetErrorText(err));
 388	  err=0; // avoid warning
 389	}
 390   mInCallbackFinishedState = false; // v18 only
 391#else
 392      myOutputParameters.channelCount = out_channels;
 393      unsigned long framesPerBuffer = paFramesPerBufferUnspecified;
 394      err = Pa_OpenStream(
 395			  &pa_stream,
 396			  NULL, /* no input */
 397			  &myOutputParameters,
 398			  SAMPLE_RATE,
 399			  framesPerBuffer,
 400			  paNoFlag,
 401			  //			  paClipOff | paDitherOff,
 402			  pa_callback,
 403			  (void *)userdata);
 404      if ((err!=paNoError) 
 405	  && (err!=paInvalidChannelCount)) //err==paUnanticipatedHostError
 406	{
 407	  fprintf(stderr, "wave_open_sound > Pa_OpenStream : err=%d (%s)\n",err,Pa_GetErrorText(err));
 408	  framesPerBuffer = FRAMES_PER_BUFFER;
 409	  err = Pa_OpenStream(
 410			      &pa_stream,
 411			      NULL, /* no input */
 412			      &myOutputParameters,
 413			      SAMPLE_RATE,
 414			      framesPerBuffer,
 415			      paNoFlag,
 416			      //			  paClipOff | paDitherOff,
 417			      pa_callback,
 418			      (void *)userdata);
 419	}
 420      if(err == paInvalidChannelCount)
 421	{
 422	  SHOW_TIME("wave_open_sound > try stereo");
 423	  // failed to open with mono, try stereo
 424	  out_channels = 2;
 425	  myOutputParameters.channelCount = out_channels;
 426	  err = Pa_OpenStream(
 427			       &pa_stream,
 428			       NULL, /* no input */
 429			       &myOutputParameters,
 430			       SAMPLE_RATE,
 431			       framesPerBuffer,
 432			       paNoFlag,
 433			       //			       paClipOff | paDitherOff,
 434			       pa_callback,
 435			       (void *)userdata);
 436
 437	  //	  err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16,(double)SAMPLE_RATE,FRAMES_PER_BUFFER,pa_callback,(void *)userdata);
 438	}
 439      mInCallbackFinishedState = false;
 440#endif
 441    }
 442
 443  SHOW("wave_open_sound > %s\n","LEAVE");
 444
 445  return (err != paNoError);
 446}
 447
 448//>
 449//<select_device
 450
 451#if (USE_PORTAUDIO == 19)
 452static void update_output_parameters(int selectedDevice, const PaDeviceInfo *deviceInfo)
 453{
 454  //  const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
 455  myOutputParameters.device = selectedDevice;
 456  //  myOutputParameters.channelCount = pdi->maxOutputChannels;
 457  myOutputParameters.channelCount = 1;
 458  myOutputParameters.sampleFormat = paInt16;
 459
 460  // Latency greater than 100ms for avoiding glitches 
 461  // (e.g. when moving a window in a graphical desktop)
 462  //  deviceInfo = Pa_GetDeviceInfo(selectedDevice);
 463  if (deviceInfo)
 464    {
 465      double aLatency = deviceInfo->defaultLowOutputLatency;
 466      double aCoeff = round(0.100 / aLatency);
 467//      myOutputParameters.suggestedLatency = aCoeff * aLatency;  // to avoid glitches ?
 468      myOutputParameters.suggestedLatency =  aLatency;          // for faster response ?
 469      SHOW("Device=%d, myOutputParameters.suggestedLatency=%f, aCoeff=%f\n",
 470	   selectedDevice,
 471	   myOutputParameters.suggestedLatency,
 472	   aCoeff);
 473    }
 474  else
 475    {
 476      myOutputParameters.suggestedLatency = (double)0.1; // 100ms
 477      SHOW("Device=%d, myOutputParameters.suggestedLatency=%f (default)\n",
 478	   selectedDevice,
 479	   myOutputParameters.suggestedLatency);
 480    }
 481    //pdi->defaultLowOutputLatency;
 482
 483  myOutputParameters.hostApiSpecificStreamInfo = NULL;
 484}
 485#endif
 486
 487static void select_device(const char* the_api)
 488{
 489	ENTER("select_device");
 490
 491#if (USE_PORTAUDIO == 19)
 492	int numDevices = Pa_GetDeviceCount();
 493	if( numDevices < 0 )
 494	{
 495		SHOW( "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
 496		assert(0);
 497	}
 498
 499	PaDeviceIndex i=0, selectedIndex=0, defaultAlsaIndex=numDevices;
 500	const PaDeviceInfo *deviceInfo=NULL;
 501	const PaDeviceInfo *selectedDeviceInfo=NULL;
 502
 503	if(option_device_number >= 0)
 504	{
 505		selectedIndex = option_device_number;
 506		selectedDeviceInfo = Pa_GetDeviceInfo(selectedIndex);
 507	}
 508
 509	if(selectedDeviceInfo == NULL)
 510	{
 511		for( i=0; i<numDevices; i++ )
 512		{
 513		deviceInfo = Pa_GetDeviceInfo( i );
 514	
 515			if (deviceInfo == NULL)
 516			{
 517				break;
 518			}
 519			const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
 520	
 521			if (hostInfo && hostInfo->type == paALSA)
 522			{ 
 523				// Check (once) the default output device
 524				if (defaultAlsaIndex == numDevices)
 525				{
 526					defaultAlsaIndex = hostInfo->defaultOutputDevice;
 527					const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( defaultAlsaIndex );
 528					update_output_parameters(defaultAlsaIndex, deviceInfo);
 529					if (Pa_IsFormatSupported(NULL, &myOutputParameters, SAMPLE_RATE) == 0)
 530					{
 531						SHOW( "select_device > ALSA (default), name=%s (#%d)\n", deviceInfo->name, defaultAlsaIndex);		  
 532						selectedIndex = defaultAlsaIndex;
 533						selectedDeviceInfo = deviceInfo;
 534						break;
 535					}
 536				}
 537	
 538				// if the default output device does not match, 
 539				// look for the device with the highest number of output channels 
 540				SHOW( "select_device > ALSA, i=%d (numDevices=%d)\n", i, numDevices);
 541	
 542				update_output_parameters(i, deviceInfo);
 543	
 544				if (Pa_IsFormatSupported(NULL, &myOutputParameters, SAMPLE_RATE) == 0)
 545				{
 546					SHOW( "select_device > ALSA, name=%s (#%d)\n", deviceInfo->name, i);
 547	
 548					if (!selectedDeviceInfo
 549						|| (selectedDeviceInfo->maxOutputChannels < deviceInfo->maxOutputChannels))
 550					{
 551						selectedIndex = i;
 552						selectedDeviceInfo = deviceInfo;
 553					}
 554				}
 555			}
 556		}
 557	}
 558
 559	if (selectedDeviceInfo)
 560	{
 561		update_output_parameters(selectedIndex, selectedDeviceInfo);
 562	}
 563	else 
 564	{
 565		i = Pa_GetDefaultOutputDevice();
 566		deviceInfo = Pa_GetDeviceInfo( i );
 567		update_output_parameters(i, deviceInfo);
 568	}
 569
 570#endif    
 571}
 572
 573//>
 574
 575
 576// int wave_Close(void* theHandler)
 577// {
 578//   SHOW_TIME("WaveCloseSound");
 579
 580//   //  PaError active;
 581
 582//   // check whether speaking has finished, and close the stream
 583//   if(pa_stream != NULL)
 584//     {
 585//       Pa_CloseStream(pa_stream);
 586//       pa_stream = NULL;
 587//       init_buffer();
 588
 589//       // #if USE_PORTAUDIO == 18
 590//       //       active = Pa_StreamActive(pa_stream);
 591//       // #else
 592//       //       active = Pa_IsStreamActive(pa_stream);
 593//       // #endif
 594//       //       if(active == 0)
 595//       // 	{
 596//       // 	  SHOW_TIME("WaveCloseSound > ok, not active");
 597//       // 	  Pa_CloseStream(pa_stream);
 598//       // 	  pa_stream = NULL;
 599//       // 	  return(1);
 600//       // 	}
 601//     }
 602//   return(0);
 603// }
 604
 605//<wave_set_callback_is_output_enabled
 606
 607void wave_set_callback_is_output_enabled(t_wave_callback* cb)
 608{
 609  my_callback_is_output_enabled = cb;
 610}
 611
 612//>
 613//<wave_init
 614
 615// TBD: the arg could be "alsa", "oss",...
 616void wave_init()
 617{
 618  ENTER("wave_init");
 619  PaError err;
 620
 621  pa_stream = NULL;
 622  mInCallbackFinishedState = false;
 623  init_buffer();
 624
 625  // PortAudio sound output library
 626  err = Pa_Initialize();
 627  pa_init_err = err;
 628  if(err != paNoError)
 629    {
 630      SHOW_TIME("wave_init > Failed to initialise the PortAudio sound");
 631    }
 632}
 633
 634//>
 635//<wave_open
 636
 637void* wave_open(const char* the_api)
 638{
 639  ENTER("wave_open");
 640  static int once=0;
 641
 642  // TBD: the_api (e.g. "alsa") is not used at the moment
 643  // select_device is called once
 644  if (!once)
 645    {
 646      select_device("alsa");
 647      once=1;
 648    }
 649  return((void*)1);
 650}
 651
 652//>
 653//<copyBuffer
 654
 655static size_t copyBuffer(char* dest, char* src, size_t theSizeInBytes)
 656{
 657  size_t bytes_written=0;
 658  if(out_channels==1)
 659    {
 660      SHOW("copyBuffer > memcpy %x (%d bytes)\n", (int)myWrite, theSizeInBytes);
 661      memcpy(dest, src, theSizeInBytes);
 662      bytes_written = theSizeInBytes;
 663    }
 664  else
 665    {
 666      SHOW("copyBuffer > memcpy %x (%d bytes)\n", (int)myWrite, 2*theSizeInBytes);
 667      unsigned int i;
 668      uint16_t* a_dest = (uint16_t*)dest;
 669      uint16_t* a_src = (uint16_t*)src;
 670      for(i=0; i<theSizeInBytes/2; i++)
 671	{
 672	  a_dest[2*i] = a_src[i];
 673	  a_dest[2*i + 1] = a_src[i];
 674	}
 675      bytes_written = 2*theSizeInBytes;
 676    }
 677  return bytes_written;
 678}
 679
 680//>
 681//<wave_write
 682
 683size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize)
 684{
 685  ENTER("wave_write");
 686  size_t bytes_written = 0;
 687  size_t bytes_to_write = (out_channels==1) ? theSize : theSize*2;
 688  my_stream_could_start = 0;
 689
 690  if(pa_stream == NULL)
 691    {
 692      SHOW_TIME("wave_write > wave_open_sound\n");
 693      if (0 != wave_open_sound())
 694	{
 695	  SHOW_TIME("wave_write > wave_open_sound fails!");
 696	  return 0;
 697	}
 698      my_stream_could_start=1;
 699    }
 700  else if (!wave_is_busy(NULL))
 701    {
 702      my_stream_could_start = 1;
 703    }
 704  assert(BUFFER_LENGTH >= bytes_to_write);
 705
 706  if (myWrite >= myBuffer + BUFFER_LENGTH)
 707    {
 708      myWrite = myBuffer;
 709    }
 710
 711  size_t aTotalFreeMem=0;
 712  char* aRead = myRead;
 713  SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);
 714
 715  while (1) 
 716    {
 717      if (my_callback_is_output_enabled 
 718	  && (0==my_callback_is_output_enabled()))
 719	{
 720	  SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
 721	  return 0;
 722	}
 723
 724      aRead = myRead;
 725
 726      if (myWrite >= aRead)
 727	{
 728	  aTotalFreeMem = aRead + BUFFER_LENGTH - myWrite;
 729	}
 730      else
 731	{
 732	  aTotalFreeMem = aRead - myWrite;
 733	}
 734
 735      if (aTotalFreeMem>1)
 736	{
 737	  // -1 because myWrite must be different of aRead
 738	  // otherwise buffer would be considered as empty
 739	  aTotalFreeMem -= 1;
 740	}
 741
 742      if (aTotalFreeMem >= bytes_to_write)
 743	{
 744	  break;
 745	}
 746      //      SHOW_TIME("wave_write > wait");
 747      SHOW("wave_write > wait: aTotalFreeMem=%d\n", aTotalFreeMem);
 748      SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);
 749      usleep(10000);
 750    }
 751
 752  aRead = myRead;
 753
 754  if (myWrite >= aRead)
 755    {
 756      SHOW_TIME("wave_write > myWrite > aRead");
 757      size_t aFreeMem = myBuffer + BUFFER_LENGTH - myWrite;
 758      if (aFreeMem >= bytes_to_write)
 759	{
 760	  myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize);
 761	}
 762      else
 763	{
 764	  int bytes_written = copyBuffer(myWrite, theMono16BitsWaveBuffer, aFreeMem);
 765	  myWrite = myBuffer;
 766	  myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem, bytes_to_write-bytes_written);
 767	}
 768    }
 769  else
 770    {
 771      SHOW_TIME("wave_write > myWrite <= aRead");
 772      myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize);
 773    }
 774
 775  bytes_written = theSize;
 776  myWritePosition += theSize/sizeof(uint16_t); // add number of samples
 777
 778  if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER))
 779    {
 780      start_stream();
 781    }
 782
 783  SHOW_TIME("wave_write > LEAVE");
 784
 785  return bytes_written;
 786}
 787
 788//>
 789//<wave_close
 790
 791int wave_close(void* theHandler)
 792{
 793  SHOW_TIME("wave_close > ENTER");
 794
 795  static int aStopStreamCount = 0;
 796
 797#if (USE_PORTAUDIO == 19)
 798  if( pa_stream == NULL )
 799    {
 800      SHOW_TIME("wave_close > LEAVE (NULL stream)");
 801      return 0;
 802    }
 803      
 804  if( Pa_IsStreamStopped( pa_stream ) )
 805    {
 806      SHOW_TIME("wave_close > LEAVE (stopped)");
 807      return 0;
 808    }
 809#else
 810  if( pa_stream == NULL )
 811    {
 812      SHOW_TIME("wave_close > LEAVE (NULL stream)");
 813      return 0;
 814    }
 815  
 816  if( Pa_StreamActive( pa_stream ) == false && mInCallbackFinishedState == false )
 817    {
 818      SHOW_TIME("wave_close > LEAVE (not active)");
 819      return 0;
 820    }
 821#endif
 822
 823  // Avoid race condition by making sure this function only
 824  // gets called once at a time
 825  aStopStreamCount++;
 826  if (aStopStreamCount != 1)
 827    {
 828      SHOW_TIME("wave_close > LEAVE (stopStreamCount)");
 829      return 0;
 830    }
 831  
 832  // Comment from Audacity-1.2.4b adapted to the eSpeak context. 
 833  //
 834  // We got here in one of two ways:
 835  //
 836  // 1. The calling program calls the espeak_Cancel function and we 
 837  //    therefore want to stop as quickly as possible.  
 838  //    So we use AbortStream().  If this is
 839  //    the case the portaudio stream is still in the Running state
 840  //    (see PortAudio state machine docs).
 841  //
 842  // 2. The callback told PortAudio to stop the stream since it had
 843  //    reached the end of the selection.  
 844  //    The event polling thread discovered this by noticing that 
 845  //    wave_is_busy() returned false.
 846  //    wave_is_busy() (which calls Pa_GetStreamActive()) will not return
 847  //    false until all buffers have finished playing, so we can call
 848  //    AbortStream without losing any samples.  If this is the case
 849  //    we are in the "callback finished state" (see PortAudio state
 850  //    machine docs).
 851  //
 852  // The moral of the story: We can call AbortStream safely, without
 853  // losing samples.
 854  //
 855  // DMM: This doesn't seem to be true; it seems to be necessary to
 856  // call StopStream if the callback brought us here, and AbortStream
 857  // if the user brought us here.
 858  //
 859  
 860#if (USE_PORTAUDIO == 19)
 861  if (pa_stream)
 862    {
 863      Pa_AbortStream( pa_stream );
 864      SHOW_TIME("wave_close > Pa_AbortStream (end)");
 865
 866      Pa_CloseStream( pa_stream );
 867      SHOW_TIME("wave_close > Pa_CloseStream (end)");
 868      pa_stream = NULL;
 869      mInCallbackFinishedState = false;
 870    }
 871#else
 872  if (pa_stream)
 873    {
 874      if (mInCallbackFinishedState)
 875	{
 876	  Pa_StopStream( pa_stream );
 877	  SHOW_TIME("wave_close > Pa_StopStream (end)");
 878	}
 879      else
 880	{
 881	  Pa_AbortStream( pa_stream );
 882	  SHOW_TIME("wave_close > Pa_AbortStream (end)");
 883	}
 884      Pa_CloseStream( pa_stream );
 885      SHOW_TIME("wave_close > Pa_CloseStream (end)");
 886
 887      pa_stream = NULL;
 888      mInCallbackFinishedState = false;
 889    }
 890#endif
 891  init_buffer();
 892
 893  aStopStreamCount = 0; // last action
 894  SHOW_TIME("wave_close > LEAVE");
 895  return 0;
 896}
 897
 898// int wave_close(void* theHandler)
 899// {
 900//   ENTER("wave_close");
 901
 902//   if(pa_stream != NULL)
 903//     {
 904//       PaError err = Pa_AbortStream(pa_stream);
 905//       SHOW_TIME("wave_close > Pa_AbortStream (end)");
 906//       SHOW("wave_close Pa_AbortStream > err=%d\n",err);
 907//       while(1)
 908// 	{
 909// 	  PaError active;
 910// #if USE_PORTAUDIO == 18
 911// 	  active = Pa_StreamActive(pa_stream);
 912// #else
 913// 	  active = Pa_IsStreamActive(pa_stream);
 914// #endif
 915// 	  if (active != 1)
 916// 	    {
 917// 	      break;
 918// 	    }
 919// 	  SHOW("wave_close > active=%d\n",err);
 920// 	  usleep(10000); /* sleep until playback has finished */
 921// 	}
 922//       err = Pa_CloseStream( pa_stream );
 923//       SHOW_TIME("wave_close > Pa_CloseStream (end)");
 924//       SHOW("wave_close Pa_CloseStream > err=%d\n",err);
 925//       pa_stream = NULL;
 926//       init_buffer();
 927//     }
 928//   return 0;
 929// }
 930
 931//>
 932//<wave_is_busy
 933
 934int wave_is_busy(void* theHandler)
 935{
 936  PaError active=0;
 937
 938  SHOW_TIME("wave_is_busy");
 939
 940  if (pa_stream)
 941    {
 942#if USE_PORTAUDIO == 18
 943      active = Pa_StreamActive(pa_stream) 
 944	&& (mInCallbackFinishedState == false);
 945#else
 946      active = Pa_IsStreamActive(pa_stream)
 947	&& (mInCallbackFinishedState == false);
 948#endif
 949    }
 950  
 951  SHOW("wave_is_busy: %d\n",active);
 952
 953
 954  return (active==1);
 955}
 956
 957//>
 958//<wave_terminate
 959
 960void wave_terminate()
 961{
 962  ENTER("wave_terminate");
 963
 964  Pa_Terminate();
 965
 966}
 967
 968//>
 969//<wave_get_read_position, wave_get_write_position, wave_get_remaining_time
 970
 971uint32_t wave_get_read_position(void* theHandler)
 972{
 973  SHOW("wave_get_read_position > myReadPosition=%u\n", myReadPosition);
 974  return myReadPosition;
 975}
 976
 977uint32_t wave_get_write_position(void* theHandler)
 978{
 979  SHOW("wave_get_write_position > myWritePosition=%u\n", myWritePosition);
 980  return myWritePosition;
 981}
 982
 983int wave_get_remaining_time(uint32_t sample, uint32_t* time)
 984{
 985  double a_time=0;
 986
 987  if (!time || !pa_stream)
 988    {
 989      SHOW("event get_remaining_time> %s\n","audio device not available");	  
 990      return -1;
 991    }
 992
 993  if (sample > myReadPosition)
 994    {
 995      // TBD: take in account time suplied by portaudio V18 API
 996      a_time = sample - myReadPosition;
 997      a_time = 0.5 + (a_time * 1000.0) / SAMPLE_RATE;
 998    }
 999  else
1000    {
1001      a_time = 0;
1002    }
1003
1004  SHOW("wave_get_remaining_time > sample=%d, time=%d\n", sample, (uint32_t)a_time);
1005
1006  *time = (uint32_t)a_time;
1007
1008  return 0;
1009}
1010
1011//>
1012//<wave_test_get_write_buffer
1013
1014void *wave_test_get_write_buffer()
1015{
1016  return myWrite;
1017}
1018
1019
1020#else
1021// notdef USE_PORTAUDIO
1022
1023
1024void wave_init() {}
1025void* wave_open(const char* the_api) {return (void *)1;}
1026size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;}
1027int wave_close(void* theHandler) {return 0;}
1028int wave_is_busy(void* theHandler) {return 0;}
1029void wave_terminate() {}
1030uint32_t wave_get_read_position(void* theHandler) {return 0;}
1031uint32_t wave_get_write_position(void* theHandler) {return 0;}
1032void wave_flush(void* theHandler) {}
1033typedef int (t_wave_callback)(void);
1034void wave_set_callback_is_output_enabled(t_wave_callback* cb) {}
1035extern void* wave_test_get_write_buffer() {return NULL;}
1036
1037int wave_get_remaining_time(uint32_t sample, uint32_t* time)
1038{
1039	if (!time) return(-1);
1040	*time = (uint32_t)0;
1041	return 0;
1042}
1043
1044#endif  // of USE_PORTAUDIO
1045
1046//>
1047//<clock_gettime2, add_time_in_ms
1048
1049void clock_gettime2(struct timespec *ts)
1050{
1051  struct timeval tv;
1052
1053  if (!ts)
1054    {
1055      return;
1056    }
1057
1058  assert (gettimeofday(&tv, NULL) != -1);
1059  ts->tv_sec = tv.tv_sec;
1060  ts->tv_nsec = tv.tv_usec*1000;
1061}
1062
1063void add_time_in_ms(struct timespec *ts, int time_in_ms)
1064{
1065  if (!ts)
1066    {
1067      return;
1068    }
1069
1070  uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
1071  while(t_ns >= ONE_BILLION)
1072    {
1073      SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
1074      ts->tv_sec += 1;
1075      t_ns -= ONE_BILLION;	  
1076    }
1077  ts->tv_nsec = (long int)t_ns;
1078}
1079
1080
1081#endif   // USE_ASYNC
1082
1083//>