summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjaromil <jaromil@949728d9-16ea-0310-a75c-cbdf8430a4b8>2006-12-13 19:02:03 (GMT)
committer jaromil <jaromil@949728d9-16ea-0310-a75c-cbdf8430a4b8>2006-12-13 19:02:03 (GMT)
commit96a426708a853419fc327238518917b3f9ff55ba (patch)
tree078282bff1ef46373c4eef21e59af1634213727c
parentf2f50337c1a67eb7f0584b9afd7b1ff1e33fe4c8 (diff)
portaudio library
git-svn-id: svn://dyne.org/montevideo/ivysync@81 949728d9-16ea-0310-a75c-cbdf8430a4b8
-rw-r--r--branches/lydia/portaudio/LICENSE65
-rw-r--r--branches/lydia/portaudio/Makefile33
-rw-r--r--branches/lydia/portaudio/README81
-rw-r--r--branches/lydia/portaudio/libportaudio.abin0 -> 30716 bytes
-rw-r--r--branches/lydia/portaudio/pa_convert.c470
-rw-r--r--branches/lydia/portaudio/pa_host.h189
-rw-r--r--branches/lydia/portaudio/pa_lib.c806
-rw-r--r--branches/lydia/portaudio/pa_trace.c83
-rw-r--r--branches/lydia/portaudio/pa_trace.h67
-rw-r--r--branches/lydia/portaudio/pa_unix.c1128
-rw-r--r--branches/lydia/portaudio/pa_unix.h141
-rw-r--r--branches/lydia/portaudio/pa_unix_oss.c397
-rw-r--r--branches/lydia/portaudio/portaudio.h463
13 files changed, 3923 insertions, 0 deletions
diff --git a/branches/lydia/portaudio/LICENSE b/branches/lydia/portaudio/LICENSE
new file mode 100644
index 0000000..105da3f
--- /dev/null
+++ b/branches/lydia/portaudio/LICENSE
@@ -0,0 +1,65 @@
+Portable header file to contain:
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+Implementation files to contain:
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest version at: http://www.audiomulch.com/portaudio/
+ * <platform> Implementation
+ * Copyright (c) 1999-2000 <author(s)>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */ \ No newline at end of file
diff --git a/branches/lydia/portaudio/Makefile b/branches/lydia/portaudio/Makefile
new file mode 100644
index 0000000..eea546f
--- /dev/null
+++ b/branches/lydia/portaudio/Makefile
@@ -0,0 +1,33 @@
+# makefile written for gnu make
+CXX = g++
+CXXFLAGS = -Wall -ggdb
+VERSION = 19
+LIB = ./libportaudio.a
+
+
+# Add your system-dependent network libs here. These are
+# only used to build the tests (your application will need them too).
+# Linux: none
+# Solaris: -lsocket -lnsl
+#SYSTEMLIBS = -lsocket -lnsl
+SYSTEMLIBS =
+LDLIBS = $(LIB) $(SYSTEMLIBS)
+
+OBJ = pa_convert.o pa_lib.o pa_trace.o pa_unix.o pa_unix_oss.o
+
+
+all: $(LIB)
+
+$(LIB): $(OBJ)
+ $(AR) $(ARFLAGS) $(LIB) $(OBJ)
+
+doc doxygen:
+ doxygen Doxyfile
+
+distclean: clean
+
+clean:
+ rm -f *.o
+ rm -f *~
+ rm -f $(LIB)
+
diff --git a/branches/lydia/portaudio/README b/branches/lydia/portaudio/README
new file mode 100644
index 0000000..d1e5d7d
--- /dev/null
+++ b/branches/lydia/portaudio/README
@@ -0,0 +1,81 @@
+README for PortAudio
+Implementations for PC DirectSound and Mac SoundManager
+
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com//
+ *
+ * Copyright (c) 1999-2000 Phil Burk and Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+PortAudio is a portable audio I/O library designed for cross-platform
+support of audio. It uses a callback mechanism to request audio processing.
+Audio can be generated in various formats, including 32 bit floating point,
+and will be converted to the native format internally.
+
+Documentation:
+ See "pa_common/portaudio.h" for API spec.
+ See docs folder for a tutorial.
+ Also see http://www.portaudio.com/docs/
+ And see "pa_tests/patest_saw.c" for an example.
+
+For information on compiling programs with PortAudio, please see the
+tutorial at:
+
+ http://www.portaudio.com/docs/pa_tutorial.html
+
+Important Files and Folders:
+ pa_common/ = platform independant code
+ pa_common/portaudio.h = header file for PortAudio API. Specifies API.
+ pa_common/pa_lib.c = host independant code for all implementations.
+
+ pablio = simple blocking read/write interface
+
+Platform Implementations
+ pa_asio = ASIO for Windows and Macintosh
+ pa_beos = BeOS
+ pa_mac = Macintosh Sound Manager for OS 8,9 and Carbon
+ pa_mac_core = Macintosh Core Audio for OS X
+ pa_sgi = Silicon Graphics AL
+ pa_unix_oss = OSS implementation for various Unixes
+ pa_win_ds = Windows Direct Sound
+ pa_win_wmme = Windows MME (most widely supported)
+
+Test Programs
+ pa_tests/pa_fuzz.c = guitar fuzz box
+ pa_tests/pa_devs.c = print a list of available devices
+ pa_tests/pa_minlat.c = determine minimum latency for your machine
+ pa_tests/paqa_devs.c = self test that opens all devices
+ pa_tests/paqa_errs.c = test error detection and reporting
+ pa_tests/patest_clip.c = hear a sine wave clipped and unclipped
+ pa_tests/patest_dither.c = hear effects of dithering (extremely subtle)
+ pa_tests/patest_pink.c = fun with pink noise
+ pa_tests/patest_record.c = record and playback some audio
+ pa_tests/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad().
+ pa_tests/patest_sine.c = output a sine wave in a simple PA app
+ pa_tests/patest_sync.c = test syncronization of audio and video
+ pa_tests/patest_wire.c = pass input to output, wire simulator
diff --git a/branches/lydia/portaudio/libportaudio.a b/branches/lydia/portaudio/libportaudio.a
new file mode 100644
index 0000000..dc90eaf
--- /dev/null
+++ b/branches/lydia/portaudio/libportaudio.a
Binary files differ
diff --git a/branches/lydia/portaudio/pa_convert.c b/branches/lydia/portaudio/pa_convert.c
new file mode 100644
index 0000000..72e021e
--- /dev/null
+++ b/branches/lydia/portaudio/pa_convert.c
@@ -0,0 +1,470 @@
+/*
+ * pa_conversions.c
+ * portaudio
+ *
+ * Created by Phil Burk on Mon Mar 18 2002.
+ *
+ */
+#include <stdio.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+
+#define CLIP( val, min, max ) { val = ((val) < (min)) ? min : (((val) < (max)) ? (max) : (val)); }
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ short samp = (short) (*sourceBuffer * (32767.0f));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_Clip(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ long samp = (long) (*sourceBuffer * (32767.0f));
+ CLIP( samp, -0x8000, 0x7FFF );
+ *targetBuffer = (short) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_ClipDither(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (32766.0f)) + dither;
+ long samp = (long) dithered;
+ CLIP( samp, -0x8000, 0x7FFF );
+ *targetBuffer = (short) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_Dither(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (32766.0f)) + dither;
+ *targetBuffer = (short) dithered;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+
+/*************************************************************************/
+static void PaConvert_Int16_Float32(
+ short *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = *sourceBuffer * (1.0f / 32768.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ char samp = (char) (*sourceBuffer * (127.0));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_Clip(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ long samp = (long) (*sourceBuffer * 127.0f);
+ CLIP( samp, -0x80, 0x7F );
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_ClipDither(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (126.0f)) + dither;
+ long samp = (long) dithered;
+ CLIP( samp, -0x80, 0x7F );
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_Dither(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE; //FIXME
+ float dithered = (*sourceBuffer * (126.0f)) + dither;
+ long samp = (long) dithered;
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Int8_Float32(
+ char *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = *sourceBuffer * (1.0f / 128.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_UInt8(
+ float *sourceBuffer, int sourceStride,
+ unsigned char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ unsigned char samp = (unsigned char)(128 + (*sourceBuffer * (127.0)));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_UInt8_Float32(
+ unsigned char *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = (*sourceBuffer - 128) * (1.0f / 128.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int32(
+ float *sourceBuffer, int sourceStride,
+ long *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ int samp = (int) (*sourceBuffer * 0x7FFFFFFF);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int32_Clip(
+ float *sourceBuffer, int sourceStride,
+ long *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ int samp;
+ float fs = *sourceBuffer;
+ CLIP( fs, -1.0f, 0.999999f );
+ samp = (int) (*sourceBuffer * 0x7FFFFFFF);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Int32_Float32(
+ long *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = *sourceBuffer * (1.0f / 0x7FFFFFFF);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static PortAudioConverter *PaConvert_SelectProc( PaSampleFormat sourceFormat,
+ PaSampleFormat targetFormat, int ifClip, int ifDither )
+{
+ PortAudioConverter *proc = NULL;
+ switch( sourceFormat )
+ {
+ case paUInt8:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_UInt8_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+ case paInt8:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_Int8_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+ case paInt16:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_Int16_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case paInt32:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_Int32_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case paFloat32:
+ switch( targetFormat )
+ {
+ case paUInt8:
+ proc = (PortAudioConverter *) PaConvert_Float32_UInt8;
+ break;
+ case paInt8:
+ if( ifClip && ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_ClipDither;
+ else if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_Clip;
+ else if( ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_Dither;
+ else proc = (PortAudioConverter *) PaConvert_Float32_Int8;
+ break;
+ case paInt16:
+ if( ifClip && ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_ClipDither;
+ else if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_Clip;
+ else if( ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_Dither;
+ else proc = (PortAudioConverter *) PaConvert_Float32_Int16;
+ break;
+ case paInt32:
+ /* Don't bother dithering a 32 bit integer! */
+ if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int32_Clip;
+ else proc = (PortAudioConverter *) PaConvert_Float32_Int32;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return proc;
+
+}
+
+/*************************************************************************/
+PaError PaConvert_SetupInput( internalPortAudioStream *past,
+ PaSampleFormat nativeInputSampleFormat )
+{
+ past->past_NativeInputSampleFormat = nativeInputSampleFormat;
+ past->past_InputConversionSourceStride = 1;
+ past->past_InputConversionTargetStride = 1;
+
+ if( nativeInputSampleFormat != past->past_InputSampleFormat )
+ {
+ int ifDither = (past->past_Flags & paDitherOff) == 0;
+ past->past_InputConversionProc = PaConvert_SelectProc( nativeInputSampleFormat,
+ past->past_InputSampleFormat, 0, ifDither );
+ if( past->past_InputConversionProc == NULL ) return paSampleFormatNotSupported;
+ }
+ else
+ {
+ past->past_InputConversionProc = NULL; /* no conversion necessary */
+ }
+
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaConvert_SetupOutput( internalPortAudioStream *past,
+ PaSampleFormat nativeOutputSampleFormat )
+{
+
+ past->past_NativeOutputSampleFormat = nativeOutputSampleFormat;
+ past->past_OutputConversionSourceStride = 1;
+ past->past_OutputConversionTargetStride = 1;
+
+ if( nativeOutputSampleFormat != past->past_OutputSampleFormat )
+ {
+ int ifDither = (past->past_Flags & paDitherOff) == 0;
+ int ifClip = (past->past_Flags & paClipOff) == 0;
+
+ past->past_OutputConversionProc = PaConvert_SelectProc( past->past_OutputSampleFormat,
+ nativeOutputSampleFormat, ifClip, ifDither );
+ if( past->past_OutputConversionProc == NULL ) return paSampleFormatNotSupported;
+ }
+ else
+ {
+ past->past_OutputConversionProc = NULL; /* no conversion necessary */
+ }
+
+ return paNoError;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from native format to user format,
+** call user code,
+** then convert output to native format.
+** Returns result from user callback.
+*/
+long PaConvert_Process( internalPortAudioStream *past,
+ void *nativeInputBuffer,
+ void *nativeOutputBuffer )
+{
+ int userResult;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+ /* Get native input data. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ if( past->past_InputSampleFormat == past->past_NativeInputSampleFormat )
+ {
+ /* Already in native format so just read directly from native buffer. */
+ inputBuffer = nativeInputBuffer;
+ }
+ else
+ {
+ inputBuffer = past->past_InputBuffer;
+ /* Convert input data to user format. */
+ (*past->past_InputConversionProc)(nativeInputBuffer, past->past_InputConversionSourceStride,
+ inputBuffer, past->past_InputConversionTargetStride,
+ past->past_FramesPerUserBuffer * past->past_NumInputChannels );
+ }
+ }
+
+ /* Are we doing output? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ outputBuffer = (past->past_OutputConversionProc == NULL) ?
+ nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ /* Advance frame counter for timestamp. */
+ past->past_FrameCount += past->past_FramesPerUserBuffer; // FIXME - should this be in here?
+
+ /* Convert to native format if necessary. */
+ if( (past->past_OutputConversionProc != NULL ) && (outputBuffer != NULL) )
+ {
+ (*past->past_OutputConversionProc)( outputBuffer, past->past_OutputConversionSourceStride,
+ nativeOutputBuffer, past->past_OutputConversionTargetStride,
+ past->past_FramesPerUserBuffer * past->past_NumOutputChannels );
+ }
+
+ return userResult;
+}
diff --git a/branches/lydia/portaudio/pa_host.h b/branches/lydia/portaudio/pa_host.h
new file mode 100644
index 0000000..9ff4dce
--- /dev/null
+++ b/branches/lydia/portaudio/pa_host.h
@@ -0,0 +1,189 @@
+#ifndef PA_HOST_H
+#define PA_HOST_H
+
+/*
+ * $Id: pa_host.h 401 2004-07-23 17:41:54Z jaromil $
+ * Host dependant internal API for PortAudio
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.softsynth.com/portaudio/
+ * DirectSound and Macintosh Implementation
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#ifndef SUPPORT_AUDIO_CAPTURE
+#define SUPPORT_AUDIO_CAPTURE (1)
+#endif
+
+#ifndef int32
+ typedef long int32;
+#endif
+#ifndef uint32
+ typedef unsigned long uint32;
+#endif
+#ifndef int16
+ typedef short int16;
+#endif
+#ifndef uint16
+ typedef unsigned short uint16;
+#endif
+
+/* Used to convert between various sample formats. */
+typedef void (PortAudioConverter)(
+ void *inputBuffer, int inputStride,
+ void *outputBuffer, int outputStride,
+ int numSamples );
+
+#define PA_MAGIC (0x18273645)
+
+/************************************************************************************/
+/****************** Structures ******************************************************/
+/************************************************************************************/
+
+typedef struct internalPortAudioStream
+{
+ uint32 past_Magic; /* ID for struct to catch bugs. */
+
+ /* Begin user specified information. */
+ uint32 past_FramesPerUserBuffer;
+ uint32 past_NumUserBuffers;
+ double past_SampleRate; /* Closest supported sample rate. */
+ int past_NumInputChannels;
+ int past_NumOutputChannels;
+ PaDeviceID past_InputDeviceID;
+ PaDeviceID past_OutputDeviceID;
+ PaSampleFormat past_InputSampleFormat;
+ PaSampleFormat past_OutputSampleFormat;
+ PortAudioCallback *past_Callback;
+ void *past_UserData;
+ uint32 past_Flags;
+ /* End user specified information. */
+
+ void *past_DeviceData;
+ PaSampleFormat past_NativeOutputSampleFormat;
+ PaSampleFormat past_NativeInputSampleFormat;
+
+ /* Flags for communicating between foreground and background. */
+ volatile int past_IsActive; /* Background is still playing. */
+ volatile int past_StopSoon; /* Background should keep playing when buffers empty. */
+ volatile int past_StopNow; /* Background should stop playing now. */
+ /* These buffers are used when the native format does not match the user format. */
+ void *past_InputBuffer;
+ uint32 past_InputBufferSize; /* Size in bytes of the input buffer. */
+ void *past_OutputBuffer;
+ uint32 past_OutputBufferSize;
+ /* Measurements */
+ uint32 past_NumCallbacks;
+ PaTimestamp past_FrameCount; /* Frames output to buffer. */
+ /* For measuring CPU utilization. */
+ double past_AverageInsideCount;
+ double past_AverageTotalCount;
+ double past_Usage;
+ int past_IfLastExitValid;
+ /* Format Conversion */
+ /* These are setup by PaConversion_Setup() */
+ PortAudioConverter *past_InputConversionProc;
+ int past_InputConversionSourceStride;
+ int past_InputConversionTargetStride;
+ PortAudioConverter *past_OutputConversionProc;
+ int past_OutputConversionSourceStride;
+ int past_OutputConversionTargetStride;
+}
+internalPortAudioStream;
+
+/************************************************************************************/
+/******** These functions must be provided by a platform implementation. ************/
+/************************************************************************************/
+
+PaError PaHost_Init( void );
+PaError PaHost_Term( void );
+
+PaError PaHost_OpenStream( internalPortAudioStream *past );
+PaError PaHost_CloseStream( internalPortAudioStream *past );
+
+PaError PaHost_StartOutput( internalPortAudioStream *past );
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort );
+PaError PaHost_StartInput( internalPortAudioStream *past );
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort );
+PaError PaHost_StartEngine( internalPortAudioStream *past );
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort );
+PaError PaHost_StreamActive( internalPortAudioStream *past );
+
+void *PaHost_AllocateFastMemory( long numBytes );
+void PaHost_FreeFastMemory( void *addr, long numBytes );
+
+/* This only called if PA_VALIDATE_RATE IS CALLED. */
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+ double *closestFrameRatePtr );
+
+/**********************************************************************/
+/************ Common Utility Routines provided by PA ******************/
+/**********************************************************************/
+
+/* PaHost_IsInitialized() returns non-zero if PA is initialized, 0 otherwise */
+int PaHost_IsInitialized( void );
+
+internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream );
+
+int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable,
+ int numRates, double frameRate );
+
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer );
+
+/* Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit 1.31 fixed point value prior to >>15.
+** Range of output is +/- 65535
+** Multiply by PA_DITHER_SCALE to get a float between -2.0 and 2.0. */
+#define PA_DITHER_BITS (15)
+#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
+long PaConvert_TriangularDither( void );
+
+PaError PaConvert_SetupInput( internalPortAudioStream *past,
+ PaSampleFormat nativeInputSampleFormat );
+
+PaError PaConvert_SetupOutput( internalPortAudioStream *past,
+ PaSampleFormat nativeOutputSampleFormat );
+
+long PaConvert_Process( internalPortAudioStream *past,
+ void *nativeInputBuffer,
+ void *nativeOutputBuffer );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_HOST_H */
diff --git a/branches/lydia/portaudio/pa_lib.c b/branches/lydia/portaudio/pa_lib.c
new file mode 100644
index 0000000..3b8b0ca
--- /dev/null
+++ b/branches/lydia/portaudio/pa_lib.c
@@ -0,0 +1,806 @@
+/*
+ * $Id: pa_lib.c 401 2004-07-23 17:41:54Z jaromil $
+ * Portable Audio I/O Library
+ * Host Independant Layer
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Modification History:
+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
+ PLB20010820 - fix dither and shift for recording PaUInt8 format
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
+#ifdef _WIN32
+#ifndef __MWERKS__
+#include <memory.h>
+#endif /* __MWERKS__ */
+#else /* !_WIN32 */
+#include <memory.h>
+#endif /* _WIN32 */
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+/* The reason we might NOT want to validate the rate before opening the stream
+ * is because many DirectSound drivers lie about the rates they actually support.
+ */
+#define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */
+
+/*
+O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion
+*/
+
+#ifndef FALSE
+ #define FALSE (0)
+ #define TRUE (!FALSE)
+#endif
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
+
+static PaError Pa_KillStream( PortAudioStream *stream, int abort );
+
+/***********************************************************************/
+int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate )
+{
+ double err, minErr = allowableError;
+ int i, bestFit = -1;
+
+ for( i=0; i<numRates; i++ )
+ {
+ err = fabs( frameRate - rateTable[i] );
+ if( err < minErr )
+ {
+ minErr = err;
+ bestFit = i;
+ }
+ }
+ return bestFit;
+}
+
+/**************************************************************************
+** Make sure sample rate is legal and also convert to enumeration for driver.
+*/
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+ double *closestFrameRatePtr )
+{
+ long bestRateIndex;
+ const PaDeviceInfo *pdi;
+ pdi = Pa_GetDeviceInfo( id );
+ if( pdi == NULL )
+ {
+ return paInvalidDeviceId;
+ }
+
+ if( pdi->numSampleRates == -1 )
+ {
+ /* Is it out of range? */
+ if( (requestedFrameRate < pdi->sampleRates[0]) ||
+ (requestedFrameRate > pdi->sampleRates[1]) )
+ {
+ return paInvalidSampleRate;
+ }
+
+ *closestFrameRatePtr = requestedFrameRate;
+ }
+ else
+ {
+ bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate );
+ if( bestRateIndex < 0 ) return paInvalidSampleRate;
+ *closestFrameRatePtr = pdi->sampleRates[bestRateIndex];
+ }
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError Pa_OpenStream(
+ PortAudioStream** streamPtrPtr,
+ PaDeviceID inputDeviceID,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDeviceID,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ unsigned long streamFlags,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ internalPortAudioStream *past = NULL;
+ PaError result = paNoError;
+ int bitsPerInputSample;
+ int bitsPerOutputSample;
+ /* Print passed parameters. */
+ DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
+ streamPtrPtr, inputDeviceID, numInputChannels,
+ inputSampleFormat, inputDriverInfo ));
+ DBUG((" %d, %d, %d, %p, /* output */\n",
+ outputDeviceID, numOutputChannels,
+ outputSampleFormat, outputDriverInfo ));
+ DBUG((" %g, %d, %d, 0x%x, , %p )\n",
+ sampleRate, framesPerBuffer, numberOfBuffers,
+ streamFlags, userData ));
+
+ /* Check for parameter errors. */
+ if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag;
+ if( streamPtrPtr == NULL ) return paBadStreamPtr;
+ if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId;
+ if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) )
+ {
+ return paInvalidDeviceId;
+ }
+ if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount;
+
+#if SUPPORT_AUDIO_CAPTURE
+ if( inputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( inputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerInputSample = 8 * size;
+ if( (numInputChannels <= 0) ) return paInvalidChannelCount;
+ }
+#else
+ if( inputDeviceID >= 0 )
+ {
+ return paInvalidChannelCount;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ else
+ {
+ if( numInputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerInputSample = 0;
+ }
+
+ if( outputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( outputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerOutputSample = 8 * size;
+ if( (numOutputChannels <= 0) ) return paInvalidChannelCount;
+ }
+ else
+ {
+ if( numOutputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerOutputSample = 0;
+ }
+
+ if( callback == NULL ) return paNullCallback;
+
+ /* Allocate and clear stream structure. */
+ past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) );
+ if( past == NULL ) return paInsufficientMemory;
+ memset( past, 0, sizeof(internalPortAudioStream) );
+ AddTraceMessage("Pa_OpenStream: past", (long) past );
+
+ past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
+ past->past_FramesPerUserBuffer = framesPerBuffer;
+ past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() MUST CHECK FOR ZERO! */
+ past->past_Callback = callback;
+ past->past_UserData = userData;
+ past->past_OutputSampleFormat = outputSampleFormat;
+ past->past_InputSampleFormat = inputSampleFormat;
+ past->past_OutputDeviceID = outputDeviceID;
+ past->past_InputDeviceID = inputDeviceID;
+ past->past_NumInputChannels = numInputChannels;
+ past->past_NumOutputChannels = numOutputChannels;
+ past->past_Flags = streamFlags;
+
+ /* Check for absurd sample rates. */
+ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
+ {
+ result = paInvalidSampleRate;
+ goto cleanup;
+ }
+
+ /* Allocate buffers that may be used for format conversion from user to native buffers. */
+ if( numInputChannels > 0 )
+ {
+
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ /* Allocate single Input buffer for passing formatted samples to user callback. */
+ past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
+ past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
+ if( past->past_InputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_InputBuffer = NULL;
+ }
+
+ /* Allocate single Output buffer. */
+ if( numOutputChannels > 0 )
+ {
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8);
+ past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize);
+ if( past->past_OutputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_OutputBuffer = NULL;
+ }
+
+ result = PaHost_OpenStream( past );
+ if( result < 0 ) goto cleanup;
+
+ *streamPtrPtr = (void *) past;
+
+ return result;
+
+cleanup:
+ if( past != NULL ) Pa_CloseStream( past );
+ *streamPtrPtr = NULL;
+ return result;
+}
+
+
+/*************************************************************************/
+PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ return Pa_OpenStream(
+ stream,
+ ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
+ numInputChannels, sampleFormat, NULL,
+ ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
+ numOutputChannels, sampleFormat, NULL,
+ sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData );
+}
+
+/*************************************************************************/
+PaError Pa_CloseStream( PortAudioStream* stream)
+{
+ PaError result;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_CloseStream()\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ Pa_AbortStream( past );
+ result = PaHost_CloseStream( past );
+
+ if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize );
+ if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize );
+ PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) );
+
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StartStream( PortAudioStream *stream )
+{
+ PaError result = paHostError;
+ internalPortAudioStream *past;
+
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ past->past_FrameCount = 0.0;
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StartInput( past );
+ DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StartOutput( past );
+ DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ result = PaHost_StartEngine( past );
+ DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+
+ return paNoError;
+
+error:
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StopStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 0 );
+}
+
+/*************************************************************************/
+PaError Pa_AbortStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 1 );
+}
+
+/*************************************************************************/
+static PaError Pa_KillStream( PortAudioStream *stream, int abort )
+{
+ PaError result = paNoError;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_StopStream().\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) )
+ {
+ result = PaHost_StopEngine( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StopInput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StopOutput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+error:
+ past->past_Usage = 0;
+ past->past_IfLastExitValid = 0;
+
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StreamActive( PortAudioStream *stream )
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return PaHost_StreamActive( past );
+}
+
+/*************************************************************************/
+const char *Pa_GetErrorText( PaError errnum )
+{
+ const char *msg;
+
+ switch(errnum)
+ {
+ case paNoError: msg = "Success"; break;
+ case paHostError: msg = "Host error."; break;
+ case paInvalidChannelCount: msg = "Invalid number of channels."; break;
+ case paInvalidSampleRate: msg = "Invalid sample rate."; break;
+ case paInvalidDeviceId: msg = "Invalid device ID."; break;
+ case paInvalidFlag: msg = "Invalid flag."; break;
+ case paSampleFormatNotSupported: msg = "Sample format not supported"; break;
+ case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break;
+ case paInsufficientMemory: msg = "Insufficient memory."; break;
+ case paBufferTooBig: msg = "Buffer too big."; break;
+ case paBufferTooSmall: msg = "Buffer too small."; break;
+ case paNullCallback: msg = "No callback routine specified."; break;
+ case paBadStreamPtr: msg = "Invalid stream pointer."; break;
+ case paTimedOut : msg = "Wait Timed Out."; break;
+ case paInternalError: msg = "Internal PortAudio Error."; break;
+ case paDeviceUnavailable: msg = "Device Unavailable."; break;
+ default: msg = "Illegal error number."; break;
+ }
+ return msg;
+}
+
+/*
+ Get CPU Load as a fraction of total CPU time.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ The amount may vary depending on CPU load.
+ This function may be called from the callback function.
+*/
+double Pa_GetCPULoad( PortAudioStream* stream)
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return (double) paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return past->past_Usage;
+}
+
+/*************************************************************************/
+internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream )
+{
+ internalPortAudioStream* result = (internalPortAudioStream*) stream;
+
+ if( result == NULL || result->past_Magic != PA_MAGIC )
+ return NULL;
+ else
+ return result;
+}
+
+/*************************************************************
+** Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit integer prior to >>15.
+** Range of output is +/- 32767
+*/
+#define PA_DITHER_BITS (15)
+#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
+long PaConvert_TriangularDither( void )
+{
+ static unsigned long previous = 0;
+ static unsigned long randSeed1 = 22222;
+ static unsigned long randSeed2 = 5555555;
+ long current, highPass;
+ /* Generate two random numbers. */
+ randSeed1 = (randSeed1 * 196314165) + 907633515;
+ randSeed2 = (randSeed2 * 196314165) + 907633515;
+ /* Generate triangular distribution about 0.
+ * Shift before adding to prevent overflow which would skew the distribution.
+ * Also shift an extra bit for the high pass filter.
+ */
+#define DITHER_SHIFT ((32 - PA_DITHER_BITS) + 1)
+ current = (((long)randSeed1)>>DITHER_SHIFT) + (((long)randSeed2)>>DITHER_SHIFT);
+ /* High pass filter to reduce audibility. */
+ highPass = current - previous;
+ previous = current;
+ return highPass;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Int16, call user code, then convert output
+** to Int16 format for native use.
+** Assumes host native format is paInt16.
+** Returns result from user callback.
+*/
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer )
+{
+ long temp;
+ int userResult;
+ unsigned int i;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+#if SUPPORT_AUDIO_CAPTURE
+ /* Get native data from DirectSound. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ /* Convert from native format to PA format. */
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels;
+ switch(past->past_InputSampleFormat)
+ {
+
+ case paFloat32:
+ {
+ float *inBufPtr = (float *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] * (1.0f / 32767.0f);
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ /* Convert 16 bit data to 32 bit integers */
+ int *inBufPtr = (int *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] << 16;
+ }
+ break;
+ }
+
+ case paInt16:
+ {
+ /* Already in correct format so don't copy. */
+ inputBuffer = nativeInputBuffer;
+ break;
+ }
+
+ case paInt8:
+ {
+ /* Convert 16 bit data to 8 bit chars */
+ char *inBufPtr = (char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = (char)(nativeInputBuffer[i] >> 8);
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (char)(temp >> 8);
+ }
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ /* Convert 16 bit data to 8 bit unsigned chars */
+ unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = (unsigned char)((nativeInputBuffer[i] >> 8) + 0x80);
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+
+ /* Are we doing output time? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ /* May already be in native format so just write directly to native buffer. */
+ outputBuffer = (past->past_OutputSampleFormat == paInt16) ?
+ (void*)nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+ /* Convert to native format if necessary. */
+ if( outputBuffer != NULL )
+ {
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
+ switch(past->past_OutputSampleFormat)
+ {
+ case paFloat32:
+ {
+ float *outBufPtr = (float *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ if( past->past_Flags & paClipOff ) /* NOTHING */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] * (32767.0f));
+ }
+ }
+ else /* CLIP */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = (long)(outBufPtr[i] * 32767.0f);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ float dither = PaConvert_TriangularDither()*PA_DITHER_SCALE;
+ float dithered = (outBufPtr[i] * (32767.0f)) + dither;
+ temp = (long) (dithered);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ int *outBufPtr = (int *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] >> 16 );
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ /* Shift one bit down before dithering so that we have room for overflow from add. */
+ temp = (outBufPtr[i] >> 1) + PaConvert_TriangularDither();
+ temp = temp >> 15;
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt8:
+ {
+ char *outBufPtr = (char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (((int)outBufPtr[i]) << 8);
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ unsigned char *outBufPtr = (unsigned char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (((int)(outBufPtr[i] - 0x80)) << 8);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ return userResult;
+}
+
+/*************************************************************************/
+PaError Pa_Initialize( void )
+{
+ if( gInitCount++ > 0 ) return paNoError;
+ ResetTraceMessages();
+ return PaHost_Init();
+}
+
+PaError Pa_Terminate( void )
+{
+ PaError result = paNoError;
+
+ if( gInitCount == 0 ) return paNoError;
+ else if( --gInitCount == 0 )
+ {
+ result = PaHost_Term();
+ DumpTraceMessages();
+ }
+ return result;
+}
+
+int PaHost_IsInitialized()
+{
+ return gInitCount;
+}
+
+/*************************************************************************/
+PaError Pa_GetSampleSize( PaSampleFormat format )
+{
+ int size;
+ switch(format )
+ {
+
+ case paUInt8:
+ case paInt8:
+ size = 1;
+ break;
+
+ case paInt16:
+ size = 2;
+ break;
+
+ case paPackedInt24:
+ size = 3;
+ break;
+
+ case paFloat32:
+ case paInt32:
+ case paInt24:
+ size = 4;
+ break;
+
+ default:
+ size = paSampleFormatNotSupported;
+ break;
+ }
+ return (PaError) size;
+}
+
+
diff --git a/branches/lydia/portaudio/pa_trace.c b/branches/lydia/portaudio/pa_trace.c
new file mode 100644
index 0000000..90bc0b9
--- /dev/null
+++ b/branches/lydia/portaudio/pa_trace.c
@@ -0,0 +1,83 @@
+/*
+ * $Id: pa_trace.c 401 2004-07-23 17:41:54Z jaromil $
+ * Portable Audio I/O Library Trace Facility
+ * Store trace information in real-time for later printing.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pa_trace.h"
+
+#if TRACE_REALTIME_EVENTS
+
+static char *traceTextArray[MAX_TRACE_RECORDS];
+static int traceIntArray[MAX_TRACE_RECORDS];
+static int traceIndex = 0;
+static int traceBlock = 0;
+
+/*********************************************************************/
+void ResetTraceMessages()
+{
+ traceIndex = 0;
+}
+
+/*********************************************************************/
+void DumpTraceMessages()
+{
+ int i;
+ int numDump = (traceIndex < MAX_TRACE_RECORDS) ? traceIndex : MAX_TRACE_RECORDS;
+
+ printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );
+ for( i=0; i<numDump; i++ )
+ {
+ printf("%3d: %s = 0x%08X\n",
+ i, traceTextArray[i], traceIntArray[i] );
+ }
+ ResetTraceMessages();
+ fflush(stdout);
+}
+
+/*********************************************************************/
+void AddTraceMessage( char *msg, int data )
+{
+ if( (traceIndex == MAX_TRACE_RECORDS) && (traceBlock == 0) )
+ {
+ traceBlock = 1;
+ /* DumpTraceMessages(); */
+ }
+ else if( traceIndex < MAX_TRACE_RECORDS )
+ {
+ traceTextArray[traceIndex] = msg;
+ traceIntArray[traceIndex] = data;
+ traceIndex++;
+ }
+}
+
+#endif
diff --git a/branches/lydia/portaudio/pa_trace.h b/branches/lydia/portaudio/pa_trace.h
new file mode 100644
index 0000000..846b4d0
--- /dev/null
+++ b/branches/lydia/portaudio/pa_trace.h
@@ -0,0 +1,67 @@
+#ifndef PA_TRACE_H
+#define PA_TRACE_H
+/*
+ * $Id: pa_trace.h 401 2004-07-23 17:41:54Z jaromil $
+ * Portable Audio I/O Library Trace Facility
+ * Store trace information in real-time for later printing.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#define TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
+#define MAX_TRACE_RECORDS (2048)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+ /************************************************************************************/
+ /****************** Prototypes ******************************************************/
+ /************************************************************************************/
+
+#if TRACE_REALTIME_EVENTS
+
+ void DumpTraceMessages();
+ void ResetTraceMessages();
+ void AddTraceMessage( char *msg, int data );
+
+#else
+
+#define AddTraceMessage(msg,data) /* noop */
+#define ResetTraceMessages() /* noop */
+#define DumpTraceMessages() /* noop */
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PA_TRACE_H */
diff --git a/branches/lydia/portaudio/pa_unix.c b/branches/lydia/portaudio/pa_unix.c
new file mode 100644
index 0000000..5c54c51
--- /dev/null
+++ b/branches/lydia/portaudio/pa_unix.c
@@ -0,0 +1,1128 @@
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * Linux OSS Implementation by douglas repetto and Phil Burk
+ *
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+Modification History
+ 1/2001 - Phil Burk - initial hack for Linux
+ 2/2001 - Douglas Repetto - many improvements, initial query support
+ 4/2/2001 - Phil - stop/abort thread control, separate in/out native buffers
+ 5/28/2001 - Phil - use pthread_create() instead of clone(). Thanks Stephen Brandon!
+ use pthread_join() after thread shutdown.
+ 5/29/2001 - Phil - query for multiple devices, multiple formats,
+ input mode and input+output mode working,
+ Pa_GetCPULoad() implemented.
+ PLB20010817 - Phil & Janos Haber - don't halt if test of sample rate fails.
+ SB20010904 - Stephen Brandon - mods needed for GNUSTEP and SndKit
+ JH20010905 - Janos Haber - FreeBSD mods
+ 2001-09-22 - Heiko - (i.e. Heiko Purnhagen <purnhage@tnt.uni-hannover.de> ;-)
+ added 24k and 16k to ratesToTry[]
+ fixed Pa_GetInternalDevice()
+ changed DEVICE_NAME_BASE from /dev/audio to /dev/dsp
+ handled SNDCTL_DSP_SPEED in Pq_QueryDevice() more graceful
+ fixed Pa_StreamTime() for paqa_errs.c
+ fixed numCannel=2 oddity and error handling in Pa_SetupDeviceFormat()
+ grep also for HP20010922 ...
+ PLB20010924 - Phil - merged Heiko's changes
+ removed sNumDevices and potential related bugs,
+ use getenv("PA_MIN_LATENCY_MSEC") to set desired latency,
+ simplify CPU Load calculation by comparing real-time to framesPerBuffer,
+ always close device when querying even if error occurs,
+ PLB20010927 - Phil - Improved negotiation for numChannels.
+ SG20011005 - Stewart Greenhill - set numChannels back to reasonable value after query.
+ DH20010115 - David Herring - fixed uninitialized handle.
+
+ DM20020218 - Dominic Mazzoni - Try to open in nonblocking mode first, in case
+ the device is already open. New implementation of
+ Pa_StreamTime that uses SNDCTL_DSP_GETOPTR but
+ uses our own counter to avoid wraparound.
+ PLB20020222 - Phil Burk - Added WatchDog proc if audio running at high priority.
+ Check error return from read() and write().
+ Check CPU endianness instead of assuming Little Endian.
+ 20020621 - pa_unix_oss.c split into pa_unix.c, pa_unix.h, pa_unix_oss.c by
+ Augustus Saunders. Return values from usleep() ignored by Sam Bayer
+ because not cross-platform compatible (at least until we get configure
+ going). Pa_SetupDeviceFormat split into input and output sides to
+ reflect capabilities of Solaris.
+
+ 20030206 - Martin Rohrbach - various mods for Solaris
+
+ 20030410 - Bjorn Dittmer-Roche - fixed numerous problems associated with pthread_t
+
+ 20030630 - Thomas Richter - eliminated unused variable warnings.
+
+TODO
+O- put semaphore lock around shared data?
+O- handle native formats better
+O- handle stereo-only device better ???
+O- what if input and output of a device capabilities differ (e.g. es1371) ???
+*/
+
+#define HAVE_UNIX 1
+
+#ifdef HAVE_UNIX
+
+#include "pa_unix.h"
+
+typedef void *(*pthread_function_t)(void *);
+
+/************************************************* Shared Data ********/
+/* FIXME - put Mutex around this shared data. */
+static internalPortAudioDevice *sDeviceList = NULL;
+static int sDefaultInputDeviceID = paNoDevice;
+static int sDefaultOutputDeviceID = paNoDevice;
+static int sPaHostError = 0;
+
+/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ /* Query system timer for usage analysis and to prevent overuse of CPU. */
+ gettimeofday( &pahsc->pahsc_EntryTime, NULL );
+}
+
+static long SubtractTime_AminusB( struct timeval *timeA, struct timeval *timeB )
+{
+ long secs = timeA->tv_sec - timeB->tv_sec;
+ long usecs = secs * 1000000;
+ usecs += (timeA->tv_usec - timeB->tv_usec);
+ return usecs;
+}
+
+/******************************************************************************
+** Measure fractional CPU load based on real-time it took to calculate
+** buffers worth of output.
+*/
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+{
+ struct timeval currentTime;
+ long usecsElapsed;
+ double newUsage;
+
+#define LOWPASS_COEFFICIENT_0 (0.95)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+
+ if( gettimeofday( &currentTime, NULL ) == 0 )
+ {
+ usecsElapsed = SubtractTime_AminusB( &currentTime, &pahsc->pahsc_EntryTime );
+ /* Use inverse because it is faster than the divide. */
+ newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerBuffer;
+
+ past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
+ (LOWPASS_COEFFICIENT_1 * newUsage);
+
+ }
+}
+/****************************************** END CPU UTILIZATION *******/
+
+/*********************************************************************
+ * Determines the number of available devices by trying to open
+ * each "/dev/dsp#" or "/dsp/audio#" in order until it fails.
+ * Add each working device to a singly linked list of devices.
+ */
+PaError Pa_QueryDevices( void )
+{
+ internalPortAudioDevice *pad, *lastPad;
+ int go = 1;
+ int numDevices = 0;
+ PaError testResult;
+ PaError result = paNoError;
+ char *envdev;
+
+ sDefaultInputDeviceID = paNoDevice;
+ sDefaultOutputDeviceID = paNoDevice;
+
+ lastPad = NULL;
+
+ while( go )
+ {
+ /* Allocate structure to hold device info. */
+ pad = (internalPortAudioDevice *)
+ PaHost_AllocateFastMemory( sizeof(internalPortAudioDevice) );
+ if( pad == NULL ) return paInsufficientMemory;
+ memset( pad, 0, sizeof(internalPortAudioDevice) );
+
+ /* Build name for device. */
+ if( numDevices == 0 )
+ {
+ sprintf( pad->pad_DeviceName, DEVICE_NAME_BASE);
+ }
+ else
+ {
+ sprintf( pad->pad_DeviceName, DEVICE_NAME_BASE "%d", numDevices );
+ }
+
+ DBUG(("Try device %s\n", pad->pad_DeviceName ));
+ testResult = Pa_QueryDevice( pad->pad_DeviceName, pad );
+ DBUG(("Pa_QueryDevice returned %d\n", testResult ));
+ if( testResult != paNoError )
+ {
+ if( lastPad == NULL )
+ {
+ result = testResult; /* No good devices! */
+ }
+ go = 0;
+ PaHost_FreeFastMemory( pad, sizeof(internalPortAudioDevice) );
+ }
+ else
+ {
+ numDevices += 1;
+ /* Add to linked list of devices. */
+ if( lastPad )
+ {
+ lastPad->pad_Next = pad;
+ }
+ else
+ {
+ sDeviceList = pad; /* First element in linked list. */
+ }
+ lastPad = pad;
+ }
+ }
+
+ /* I'm sitting at a SunRay1 and I neither have /dev/audio# nor /dev/dsp#.
+ Instead, the correct audio device is stored in the environment variable
+ AUDIODEV and/or UTAUDIODEV, so check these devices as well if we haven't
+ checked them yet above - MR */
+
+ DBUG(("Checking for AUDIODEV and UTAUDIODEV\n"));
+ envdev = getenv("AUDIODEV");
+ if (envdev != NULL && !strstr(envdev, DEVICE_NAME_BASE)) {
+ result = paNoError;
+
+ /* Allocate structure to hold device info. */
+ pad = (internalPortAudioDevice *)
+ PaHost_AllocateFastMemory( sizeof(internalPortAudioDevice) );
+ if( pad == NULL ) return paInsufficientMemory;
+ memset( pad, 0, sizeof(internalPortAudioDevice) );
+
+ /* Build name for device. */
+ strcpy(pad->pad_DeviceName, envdev);
+
+ DBUG(("Try device %s\n", pad->pad_DeviceName ));
+ testResult = Pa_QueryDevice( pad->pad_DeviceName, pad );
+ DBUG(("Pa_QueryDevice returned %d\n", testResult ));
+ if( testResult != paNoError )
+ {
+ if( lastPad == NULL )
+ {
+ result = testResult; /* No good devices! */
+ }
+ PaHost_FreeFastMemory( pad, sizeof(internalPortAudioDevice) );
+ }
+ else
+ {
+ numDevices += 1;
+ /* Add to linked list of devices. */
+ if( lastPad )
+ {
+ lastPad->pad_Next = pad;
+ }
+ else
+ {
+ sDeviceList = pad; /* First element in linked list. */
+ }
+ lastPad = pad;
+ }
+ }
+
+ envdev = getenv("UTAUDIODEV");
+ if (envdev != NULL && !strstr(envdev, DEVICE_NAME_BASE) && getenv("AUDIODEV") != NULL && strcmp(envdev, getenv("AUDIODEV"))) {
+ result = paNoError;
+
+ /* Allocate structure to hold device info. */
+ pad = (internalPortAudioDevice *)
+ PaHost_AllocateFastMemory( sizeof(internalPortAudioDevice) );
+ if( pad == NULL ) return paInsufficientMemory;
+ memset( pad, 0, sizeof(internalPortAudioDevice) );
+
+ /* Build name for device. */
+ strcpy(pad->pad_DeviceName, envdev);
+
+ DBUG(("Try device %s\n", pad->pad_DeviceName ));
+ testResult = Pa_QueryDevice( pad->pad_DeviceName, pad );
+ DBUG(("Pa_QueryDevice returned %d\n", testResult ));
+ if( testResult != paNoError )
+ {
+ if( lastPad == NULL )
+ {
+ result = testResult; /* No good devices! */
+ }
+ PaHost_FreeFastMemory( pad, sizeof(internalPortAudioDevice) );
+ }
+ else
+ {
+ numDevices += 1;
+ /* Add to linked list of devices. */
+ if( lastPad )
+ {
+ lastPad->pad_Next = pad;
+ }
+ else
+ {
+ sDeviceList = pad; /* First element in linked list. */
+ }
+ lastPad = pad;
+ }
+ }
+
+ return result;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ int numDevices = 0;
+ internalPortAudioDevice *pad;
+
+ if( sDeviceList == NULL ) Pa_Initialize();
+ /* Count devices in list. */
+ pad = sDeviceList;
+ while( pad != NULL )
+ {
+ pad = pad->pad_Next;
+ numDevices++;
+ }
+
+ return numDevices;
+}
+
+/*************************************************************************/
+internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id )
+{
+ internalPortAudioDevice *pad;
+ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
+ pad = sDeviceList;
+ while( id > 0 )
+ {
+ pad = pad->pad_Next;
+ id--;
+ }
+ return pad;
+}
+
+/*************************************************************************/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ internalPortAudioDevice *pad;
+ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
+ pad = Pa_GetInternalDevice( id );
+ return &pad->pad_Info ;
+}
+
+static PaError Pa_MaybeQueryDevices( void )
+{
+ if( sDeviceList == NULL )
+ {
+ return Pa_QueryDevices();
+ }
+ return 0;
+}
+
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ /* return paNoDevice; */
+ return 0;
+}
+
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ return 0;
+}
+
+/**********************************************************************
+** Make sure that we have queried the device capabilities.
+*/
+
+PaError PaHost_Init( void )
+{
+ return Pa_MaybeQueryDevices();
+}
+
+/*******************************************************************************************
+ * The ol' Canary in a Coal Mine trick.
+ * Just update the time periodically.
+ * Runs at low priority so if audio thread runs wild, this thread will get starved
+ * and the watchdog will detect it.
+ */
+
+#define SCHEDULER_POLICY SCHED_RR
+#define WATCHDOG_MAX_SECONDS (3)
+#define WATCHDOG_INTERVAL_USEC (1000000)
+
+static int PaHost_CanaryProc( PaHostSoundControl *pahsc )
+{
+ int result = 0;
+
+#ifdef GNUSTEP
+ GSRegisterCurrentThread(); /* SB20010904 */
+#endif
+
+ while( pahsc->pahsc_CanaryRun) {
+ usleep( WATCHDOG_INTERVAL_USEC );
+ gettimeofday( &pahsc->pahsc_CanaryTime, NULL );
+ }
+
+ DBUG(("PaHost_CanaryProc: exiting.\n"));
+
+#ifdef GNUSTEP
+ GSUnregisterCurrentThread(); /* SB20010904 */
+#endif
+
+ return result;
+}
+
+/*******************************************************************************************
+ * Monitor audio thread and lower its it if it hogs the CPU.
+ * To prevent getting killed, the audio thread must update a
+ * variable with a timer value.
+ * If the value is not recent enough, then the
+ * thread will get killed.
+ */
+
+static PaError PaHost_WatchDogProc( PaHostSoundControl *pahsc )
+{
+ struct sched_param schp = { 0 };
+ int maxPri;
+
+#ifdef GNUSTEP
+ GSRegisterCurrentThread(); /* SB20010904 */
+#endif
+
+/* Run at a priority level above audio thread so we can still run if it hangs. */
+/* Rise more than 1 because of rumored off-by-one scheduler bugs. */
+ schp.sched_priority = pahsc->pahsc_AudioPriority + 4;
+ maxPri = sched_get_priority_max(SCHEDULER_POLICY);
+ if( schp.sched_priority > maxPri ) schp.sched_priority = maxPri;
+
+ if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)
+ {
+ ERR_RPT(("PaHost_WatchDogProc: cannot set watch dog priority!\n"));
+ goto killAudio;
+ }
+
+ /* Compare watchdog time with audio and canary thread times. */
+ /* Sleep for a while or until thread cancelled. */
+ while( pahsc->pahsc_WatchDogRun )
+ {
+
+ int delta;
+ struct timeval currentTime;
+
+ usleep( WATCHDOG_INTERVAL_USEC );
+ gettimeofday( &currentTime, NULL );
+
+ /* If audio thread is not advancing, then it must be hung so kill it. */
+ delta = currentTime.tv_sec - pahsc->pahsc_EntryTime.tv_sec;
+ DBUG(("PaHost_WatchDogProc: audio delta = %d\n", delta ));
+ if( delta > WATCHDOG_MAX_SECONDS )
+ {
+ goto killAudio;
+ }
+
+ /* If canary died, then lower audio priority and halt canary. */
+ delta = currentTime.tv_sec - pahsc->pahsc_CanaryTime.tv_sec;
+ if( delta > WATCHDOG_MAX_SECONDS )
+ {
+ ERR_RPT(("PaHost_WatchDogProc: canary died!\n"));
+ goto lowerAudio;
+ }
+ }
+
+ DBUG(("PaHost_WatchDogProc: exiting.\n"));
+#ifdef GNUSTEP
+ GSUnregisterCurrentThread(); /* SB20010904 */
+#endif
+ return 0;
+
+lowerAudio:
+ {
+ struct sched_param schat = { 0 };
+ if( sched_setscheduler(pahsc->pahsc_AudioThreadPID, SCHED_OTHER, &schat) != 0)
+ {
+ ERR_RPT(("PaHost_WatchDogProc: failed to lower audio priority. errno = %d\n", errno ));
+ /* Fall through into killing audio thread. */
+ }
+ else
+ {
+ ERR_RPT(("PaHost_WatchDogProc: lowered audio priority to prevent hogging of CPU.\n"));
+ goto cleanup;
+ }
+ }
+
+killAudio:
+ ERR_RPT(("PaHost_WatchDogProc: killing hung audio thread!\n"));
+ pthread_kill( pahsc->pahsc_AudioThread, SIGKILL );
+
+cleanup:
+ pahsc->pahsc_CanaryRun = 0;
+ DBUG(("PaHost_WatchDogProc: cancel Canary\n"));
+ pthread_cancel( pahsc->pahsc_CanaryThread );
+ DBUG(("PaHost_WatchDogProc: join Canary\n"));
+ pthread_join( pahsc->pahsc_CanaryThread, NULL );
+ DBUG(("PaHost_WatchDogProc: forget Canary\n"));
+ pahsc->pahsc_IsCanaryThreadValid = 0;
+
+#ifdef GNUSTEP
+ GSUnregisterCurrentThread(); /* SB20010904 */
+#endif
+ return 0;
+}
+
+/*******************************************************************************************/
+static void PaHost_StopWatchDog( PaHostSoundControl *pahsc )
+{
+/* Cancel WatchDog thread if there is one. */
+ if( pahsc->pahsc_IsWatchDogThreadValid )
+ {
+ pahsc->pahsc_WatchDogRun = 0;
+ DBUG(("PaHost_StopWatchDog: cancel WatchDog\n"));
+ pthread_cancel( pahsc->pahsc_WatchDogThread );
+ pthread_join( pahsc->pahsc_WatchDogThread, NULL );
+ pahsc->pahsc_IsWatchDogThreadValid = 0;
+ }
+/* Cancel Canary thread if there is one. */
+ if( pahsc->pahsc_IsCanaryThreadValid )
+ {
+ pahsc->pahsc_CanaryRun = 0;
+ DBUG(("PaHost_StopWatchDog: cancel Canary\n"));
+ pthread_cancel( pahsc->pahsc_CanaryThread );
+ DBUG(("PaHost_StopWatchDog: join Canary\n"));
+ pthread_join( pahsc->pahsc_CanaryThread, NULL );
+ pahsc->pahsc_IsCanaryThreadValid = 0;
+ }
+}
+
+/*******************************************************************************************/
+static PaError PaHost_StartWatchDog( PaHostSoundControl *pahsc )
+{
+ int hres;
+ PaError result = 0;
+
+ /* The watch dog watches for these timer updates */
+ gettimeofday( &pahsc->pahsc_EntryTime, NULL );
+ gettimeofday( &pahsc->pahsc_CanaryTime, NULL );
+
+ /* Launch a canary thread to detect priority abuse. */
+ pahsc->pahsc_CanaryRun = 1;
+ hres = pthread_create(&(pahsc->pahsc_CanaryThread),
+ NULL /*pthread_attr_t * attr*/,
+ (pthread_function_t)PaHost_CanaryProc, pahsc);
+ if( hres != 0 )
+ {
+ pahsc->pahsc_IsCanaryThreadValid = 0;
+ result = paHostError;
+ sPaHostError = hres;
+ goto error;
+ }
+ pahsc->pahsc_IsCanaryThreadValid = 1;
+
+ /* Launch a watchdog thread to prevent runaway audio thread. */
+ pahsc->pahsc_WatchDogRun = 1;
+ hres = pthread_create(&(pahsc->pahsc_WatchDogThread),
+ NULL /*pthread_attr_t * attr*/,
+ (pthread_function_t)PaHost_WatchDogProc, pahsc);
+ if( hres != 0 )
+ {
+ pahsc->pahsc_IsWatchDogThreadValid = 0;
+ result = paHostError;
+ sPaHostError = hres;
+ goto error;
+ }
+ pahsc->pahsc_IsWatchDogThreadValid = 1;
+ return result;
+
+error:
+ PaHost_StopWatchDog( pahsc );
+ return result;
+}
+
+/*******************************************************************************************
+ * Bump priority of audio thread if running with superuser priveledges.
+ * if priority bumped then launch a watchdog.
+ */
+static PaError PaHost_BoostPriority( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+ struct sched_param schp = { 0 };
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+
+ pahsc->pahsc_AudioThreadPID = getpid();
+ DBUG(("PaHost_BoostPriority: audio PID = %d\n", pahsc->pahsc_AudioThreadPID ));
+
+ /* Choose a priority in the middle of the range. */
+ pahsc->pahsc_AudioPriority = (sched_get_priority_max(SCHEDULER_POLICY) -
+ sched_get_priority_min(SCHEDULER_POLICY)) / 2;
+ schp.sched_priority = pahsc->pahsc_AudioPriority;
+
+ if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)
+ {
+ DBUG(("PortAudio: only superuser can use real-time priority.\n"));
+ }
+ else
+ {
+ DBUG(("PortAudio: audio callback priority set to level %d!\n", schp.sched_priority));
+ /* We are running at high priority so we should have a watchdog in case audio goes wild. */
+ result = PaHost_StartWatchDog( pahsc );
+ }
+
+ return result;
+}
+
+/*******************************************************************************************/
+static PaError Pa_AudioThreadProc( internalPortAudioStream *past )
+{
+ PaError result;
+ PaHostSoundControl *pahsc;
+ ssize_t bytes_read, bytes_written;
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+
+#ifdef GNUSTEP
+ GSRegisterCurrentThread(); /* SB20010904 */
+#endif
+
+ result = PaHost_BoostPriority( past );
+ if( result < 0 ) goto error;
+
+ past->past_IsActive = 1;
+ DBUG(("entering thread.\n"));
+
+ while( (past->past_StopNow == 0) && (past->past_StopSoon == 0) )
+ {
+ /* Read data from device */
+ if(pahsc->pahsc_NativeInputBuffer)
+ {
+ unsigned int totalread = 0;
+ DBUG(("Pa_AudioThreadProc: attempt to read %d bytes\n", pahsc->pahsc_BytesPerInputBuffer));
+ do
+ {
+ bytes_read = read(pahsc->pahsc_InputHandle,
+ (char *)pahsc->pahsc_NativeInputBuffer + totalread,
+ pahsc->pahsc_BytesPerInputBuffer - totalread);
+
+ if (bytes_read < 0)
+ {
+ ERR_RPT(("PortAudio: read interrupted!\n"));
+ break;
+ }
+
+ totalread += bytes_read;
+ } while( totalread < pahsc->pahsc_BytesPerInputBuffer);
+ }
+
+ /* Convert 16 bit native data to user data and call user routine. */
+ DBUG(("converting...\n"));
+ Pa_StartUsageCalculation( past );
+ result = Pa_CallConvertInt16( past,
+ pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_NativeOutputBuffer );
+ Pa_EndUsageCalculation( past );
+ if( result != 0)
+ {
+ DBUG(("hmm, Pa_CallConvertInt16() says: %d. i'm bailing.\n",
+ result));
+ break;
+ }
+
+ /* Write data to device. */
+ if( pahsc->pahsc_NativeOutputBuffer )
+ {
+ unsigned int totalwritten = 0;
+ do
+ {
+ bytes_written = write(pahsc->pahsc_OutputHandle,
+ (void *)pahsc->pahsc_NativeOutputBuffer,
+ pahsc->pahsc_BytesPerOutputBuffer);
+ if( bytes_written < 0 )
+ {
+ ERR_RPT(("PortAudio: write interrupted!"));
+ break;
+ }
+
+ totalwritten += bytes_written;
+ } while( totalwritten < pahsc->pahsc_BytesPerOutputBuffer);
+ }
+
+ Pa_UpdateStreamTime(pahsc);
+ }
+ DBUG(("Pa_AudioThreadProc: left audio loop.\n"));
+
+ past->past_IsActive = 0;
+ PaHost_StopWatchDog( pahsc );
+
+error:
+ DBUG(("leaving audio thread.\n"));
+#ifdef GNUSTEP
+ GSUnregisterCurrentThread(); /* SB20010904 */
+#endif
+ return result;
+}
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+**
+** set PA_MIN_LATENCY_MSEC=200
+**
+** in the cshrc file.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond )
+{
+ int minBuffers;
+ int minLatencyMsec = MIN_LATENCY_MSEC;
+ char *minLatencyText = getenv(PA_LATENCY_ENV_NAME);
+ if( minLatencyText != NULL )
+ {
+ PRINT(("PA_MIN_LATENCY_MSEC = %s\n", minLatencyText ));
+ minLatencyMsec = atoi( minLatencyText );
+ if( minLatencyMsec < 1 ) minLatencyMsec = 1;
+ else if( minLatencyMsec > 5000 ) minLatencyMsec = 5000;
+ }
+
+ minBuffers = (int) ((minLatencyMsec * framesPerSecond) / ( 1000.0 * framesPerBuffer ));
+ if( minBuffers < 2 ) minBuffers = 2;
+ return minBuffers;
+}
+
+/*******************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ unsigned int minNumBuffers;
+ internalPortAudioDevice *pad;
+ DBUG(("PaHost_OpenStream() called.\n" ));
+
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl));
+ if( pahsc == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ memset( pahsc, 0, sizeof(PaHostSoundControl) );
+ past->past_DeviceData = (void *) pahsc;
+
+ pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; /* No device currently opened. */
+ pahsc->pahsc_InputHandle = BAD_DEVICE_ID;
+ pahsc->pahsc_IsAudioThreadValid = 0;
+ pahsc->pahsc_IsWatchDogThreadValid = 0;
+
+ /* Allocate native buffers. */
+ pahsc->pahsc_BytesPerInputBuffer = past->past_FramesPerUserBuffer *
+ past->past_NumInputChannels * sizeof(short);
+ if( past->past_NumInputChannels > 0)
+ {
+ pahsc->pahsc_NativeInputBuffer = (short *) malloc(pahsc->pahsc_BytesPerInputBuffer);
+ if( pahsc->pahsc_NativeInputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ }
+ pahsc->pahsc_BytesPerOutputBuffer = past->past_FramesPerUserBuffer *
+ past->past_NumOutputChannels * sizeof(short);
+ if( past->past_NumOutputChannels > 0)
+ {
+ pahsc->pahsc_NativeOutputBuffer = (short *) malloc(pahsc->pahsc_BytesPerOutputBuffer);
+ if( pahsc->pahsc_NativeOutputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ }
+
+ /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */
+ minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
+ past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
+
+ pahsc->pahsc_InverseMicrosPerBuffer = past->past_SampleRate / (1000000.0 * past->past_FramesPerUserBuffer);
+ DBUG(("past_SampleRate = %g\n", past->past_SampleRate ));
+ DBUG(("past_FramesPerUserBuffer = %d\n", past->past_FramesPerUserBuffer ));
+ DBUG(("pahsc_InverseMicrosPerBuffer = %g\n", pahsc->pahsc_InverseMicrosPerBuffer ));
+
+ /* ------------------------- OPEN DEVICE -----------------------*/
+
+ /* just output */
+ if (past->past_OutputDeviceID == past->past_InputDeviceID)
+ {
+
+ if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0) )
+ {
+ pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
+ DBUG(("PaHost_OpenStream: attempt to open %s for O_RDWR\n", pad->pad_DeviceName ));
+
+ /* dmazzoni: test it first in nonblocking mode to
+ make sure the device is not busy */
+ pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDWR|O_NONBLOCK);
+ if(pahsc->pahsc_InputHandle==-1)
+ {
+ ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName ));
+ result = paHostError;
+ goto error;
+ }
+ close(pahsc->pahsc_InputHandle);
+
+ pahsc->pahsc_OutputHandle = pahsc->pahsc_InputHandle =
+ open(pad->pad_DeviceName,O_RDWR);
+ if(pahsc->pahsc_InputHandle==-1)
+ {
+ ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName ));
+ result = paHostError;
+ goto error;
+ }
+ Pa_SetLatency( pahsc->pahsc_OutputHandle,
+ past->past_NumUserBuffers, past->past_FramesPerUserBuffer,
+ past->past_NumOutputChannels );
+ result = Pa_SetupDeviceFormat( pahsc->pahsc_OutputHandle,
+ past->past_NumOutputChannels, (int)past->past_SampleRate );
+ }
+ }
+ else
+ {
+ if (past->past_NumOutputChannels > 0)
+ {
+ pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
+ DBUG(("PaHost_OpenStream: attempt to open %s for O_WRONLY\n", pad->pad_DeviceName ));
+ /* dmazzoni: test it first in nonblocking mode to
+ make sure the device is not busy */
+ pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY|O_NONBLOCK);
+ if(pahsc->pahsc_OutputHandle==-1)
+ {
+ ERR_RPT(("PaHost_OpenStream: could not open %s for O_WRONLY\n", pad->pad_DeviceName ));
+ result = paHostError;
+ goto error;
+ }
+ close(pahsc->pahsc_OutputHandle);
+
+ pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY);
+ if(pahsc->pahsc_OutputHandle==-1)
+ {
+ ERR_RPT(("PaHost_OpenStream: could not open %s for O_WRONLY\n", pad->pad_DeviceName ));
+ result = paHostError;
+ goto error;
+ }
+ Pa_SetLatency( pahsc->pahsc_OutputHandle,
+ past->past_NumUserBuffers, past->past_FramesPerUserBuffer,
+ past->past_NumOutputChannels );
+ result = Pa_SetupOutputDeviceFormat( pahsc->pahsc_OutputHandle,
+ past->past_NumOutputChannels, (int)past->past_SampleRate );
+ }
+
+ if (past->past_NumInputChannels > 0)
+ {
+ pad = Pa_GetInternalDevice( past->past_InputDeviceID );
+ DBUG(("PaHost_OpenStream: attempt to open %s for O_RDONLY\n", pad->pad_DeviceName ));
+ /* dmazzoni: test it first in nonblocking mode to
+ make sure the device is not busy */
+ pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY|O_NONBLOCK);
+ if(pahsc->pahsc_InputHandle==-1)
+ {
+ ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDONLY\n", pad->pad_DeviceName ));
+ result = paHostError;
+ goto error;
+ }
+ close(pahsc->pahsc_InputHandle);
+
+ pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY);
+ if(pahsc->pahsc_InputHandle==-1)
+ {
+ ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDONLY\n", pad->pad_DeviceName ));
+ result = paHostError;
+ goto error;
+ }
+ Pa_SetLatency( pahsc->pahsc_InputHandle, /* DH20010115 - was OutputHandle! */
+ past->past_NumUserBuffers, past->past_FramesPerUserBuffer,
+ past->past_NumInputChannels );
+ result = Pa_SetupInputDeviceFormat( pahsc->pahsc_InputHandle,
+ past->past_NumInputChannels, (int)past->past_SampleRate );
+ }
+ }
+
+
+ DBUG(("PaHost_OpenStream: SUCCESS - result = %d\n", result ));
+ return result;
+
+error:
+ ERR_RPT(("PaHost_OpenStream: ERROR - result = %d\n", result ));
+ PaHost_CloseStream( past );
+ return result;
+}
+
+/*************************************************************************/
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ past = past; /* unused */
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ past = past; /* unused */
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+ int hres;
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ past->past_StopSoon = 0;
+ past->past_StopNow = 0;
+ past->past_IsActive = 1;
+
+ /* Use pthread_create() instead of __clone() because:
+ * - pthread_create also works for other UNIX systems like Solaris,
+ * - the Java HotSpot VM crashes in pthread_setcanceltype() when using __clone()
+ */
+ hres = pthread_create(&(pahsc->pahsc_AudioThread),
+ NULL /*pthread_attr_t * attr*/,
+ (pthread_function_t)Pa_AudioThreadProc, past);
+ if( hres != 0 )
+ {
+ result = paHostError;
+ sPaHostError = hres;
+ pahsc->pahsc_IsAudioThreadValid = 0;
+ goto error;
+ }
+ pahsc->pahsc_IsAudioThreadValid = 1;
+
+error:
+ return result;
+}
+
+/*************************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ int hres;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ if( pahsc == NULL ) return paNoError;
+
+ /* Tell background thread to stop generating more data and to let current data play out. */
+ past->past_StopSoon = 1;
+ /* If aborting, tell background thread to stop NOW! */
+ if( abort ) past->past_StopNow = 1;
+
+ /* Join thread to recover memory resources. */
+ if( pahsc->pahsc_IsAudioThreadValid )
+ {
+ /* This check is needed for GNUSTEP - SB20010904 */
+ if ( !pthread_equal( pahsc->pahsc_AudioThread, pthread_self() ) )
+ {
+ hres = pthread_join( pahsc->pahsc_AudioThread, NULL );
+ }
+ else
+ {
+ DBUG(("Play thread was stopped from itself - can't do pthread_join()\n"));
+ hres = 0;
+ }
+
+ if( hres != 0 )
+ {
+ result = paHostError;
+ sPaHostError = hres;
+ }
+ pahsc->pahsc_IsAudioThreadValid = 0;
+ }
+
+ past->past_IsActive = 0;
+
+ return result;
+}
+
+/*************************************************************************/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+ past = past; /* unused */
+ abort = abort; /* unused */
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ past = past; /* unused */
+ abort = abort; /* unused */
+ return paNoError;
+}
+
+/*******************************************************************/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+
+ if( pahsc->pahsc_OutputHandle != BAD_DEVICE_ID )
+ {
+ int err = 0;
+ DBUG(("PaHost_CloseStream: attempt to close output device handle = %d\n",
+ pahsc->pahsc_OutputHandle ));
+
+ Pa_FlushStream(pahsc->pahsc_OutputHandle);
+
+ err = close(pahsc->pahsc_OutputHandle);
+ if( err < 0 )
+ {
+ ERR_RPT(("PaHost_CloseStream: warning, closing output device failed.\n"));
+ }
+ }
+
+ if( (pahsc->pahsc_InputHandle != BAD_DEVICE_ID) &&
+ (pahsc->pahsc_InputHandle != pahsc->pahsc_OutputHandle) )
+ {
+ int err = 0;
+ DBUG(("PaHost_CloseStream: attempt to close input device handle = %d\n",
+ pahsc->pahsc_InputHandle ));
+
+ Pa_FlushStream(pahsc->pahsc_InputHandle);
+
+ err = close(pahsc->pahsc_InputHandle);
+ if( err < 0 )
+ {
+ ERR_RPT(("PaHost_CloseStream: warning, closing input device failed.\n"));
+ }
+ }
+ pahsc->pahsc_OutputHandle = BAD_DEVICE_ID;
+ pahsc->pahsc_InputHandle = BAD_DEVICE_ID;
+
+ if( pahsc->pahsc_NativeInputBuffer )
+ {
+ free( pahsc->pahsc_NativeInputBuffer );
+ pahsc->pahsc_NativeInputBuffer = NULL;
+ }
+ if( pahsc->pahsc_NativeOutputBuffer )
+ {
+ free( pahsc->pahsc_NativeOutputBuffer );
+ pahsc->pahsc_NativeOutputBuffer = NULL;
+ }
+
+ free( pahsc );
+ past->past_DeviceData = NULL;
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_Term( void )
+{
+ /* Free all of the linked devices. */
+ internalPortAudioDevice *pad, *nextPad;
+ pad = sDeviceList;
+ while( pad != NULL )
+ {
+ nextPad = pad->pad_Next;
+ DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName ));
+ PaHost_FreeFastMemory( pad, sizeof(internalPortAudioDevice) );
+ pad = nextPad;
+ }
+ sDeviceList = NULL;
+ return 0;
+}
+
+/*************************************************************************
+ * Sleep for the requested number of milliseconds.
+ */
+void Pa_Sleep( long msec )
+{
+#if 0
+ struct timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ select( 0, NULL, NULL, NULL, &timeout );
+#else
+ long usecs = msec * 1000;
+ usleep( usecs );
+#endif
+}
+
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ void *addr = malloc( numBytes ); /* FIXME - do we need physical, wired, non-virtual memory? */
+ if( addr != NULL ) memset( addr, 0, numBytes );
+ return addr;
+}
+
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ numBytes = numBytes; /* unused */
+ if( addr != NULL ) free( addr );
+}
+
+
+/***********************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ return (PaError) (past->past_IsActive != 0);
+}
+
+/***********************************************************************/
+long Pa_GetHostError( void )
+{
+ return (long) sPaHostError;
+}
+
+
+#endif // HAVE_LINUX
diff --git a/branches/lydia/portaudio/pa_unix.h b/branches/lydia/portaudio/pa_unix.h
new file mode 100644
index 0000000..55b16d5
--- /dev/null
+++ b/branches/lydia/portaudio/pa_unix.h
@@ -0,0 +1,141 @@
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * Linux OSS Implementation by douglas repetto and Phil Burk
+ *
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Modification history:
+ 20020621: pa_unix_oss.c split into pa_unix.c, pa_unix.h, pa_unix_oss.c by
+ Augustus Saunders. See pa_unix.c for previous history. */
+
+/*
+ PROPOSED - should we add this to "portaudio.h". Problem with
+ Pa_QueryDevice() not having same driver name os Pa_OpenStream().
+
+ A PaDriverInfo structure can be passed to the underlying device
+ on the Pa_OpenStream() call. The contents and interpretation of
+ the structure is determined by the PA implementation.
+*/
+typedef struct PaDriverInfo /* PROPOSED */
+{
+ /* Size of structure. Allows driver to extend the structure without breaking existing applications. */
+ int size;
+ /* Can be used to request a specific device name. */
+ const char *name;
+ unsigned long data;
+}
+PaDriverInfo;
+
+#include <stdio.h>
+#include <stdlib.h>
+//#include <malloc.h>
+#include <memory.h>
+#include <math.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sched.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+#define BAD_DEVICE_ID (-1)
+
+#define MIN_LATENCY_MSEC (100)
+#define MIN_TIMEOUT_MSEC (100)
+#define MAX_TIMEOUT_MSEC (1000)
+
+/************************************************* Definitions ********/
+#ifdef __linux__
+ #define DEVICE_NAME_BASE "/dev/dsp"
+#else
+ #define DEVICE_NAME_BASE "/dev/audio"
+#endif
+
+#define MAX_CHARS_DEVNAME (32)
+#define MAX_SAMPLE_RATES (10)
+typedef struct internalPortAudioDevice
+{
+ struct internalPortAudioDevice *pad_Next; /* Singly linked list. */
+ double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */
+ char pad_DeviceName[MAX_CHARS_DEVNAME];
+ PaDeviceInfo pad_Info;
+}
+internalPortAudioDevice;
+
+/* Define structure to contain all OSS and Linux specific data. */
+typedef struct PaHostSoundControl
+{
+ int pahsc_OutputHandle;
+ int pahsc_InputHandle;
+ int pahsc_AudioPriority; /* priority of background audio thread */
+ pthread_t pahsc_AudioThread; /* background audio thread */
+ int pahsc_IsAudioThreadValid; /* Is pahsc_AudioThread valid?*/ pid_t pahsc_AudioThreadPID; /* background audio thread */
+ pthread_t pahsc_WatchDogThread; /* highest priority thread that protects system */
+ int pahsc_IsWatchDogThreadValid; /* Is pahsc_WatchDogThread valid?*/
+ int pahsc_WatchDogRun; /* Ask WatchDog to stop. */
+ pthread_t pahsc_CanaryThread; /* low priority thread that detects abuse by audio */
+ int pahsc_IsCanaryThreadValid; /* Is pahsc_CanaryThread valid?*/
+ struct timeval pahsc_CanaryTime;
+ int pahsc_CanaryRun; /* Ask Canary to stop. */
+ short *pahsc_NativeInputBuffer;
+ short *pahsc_NativeOutputBuffer;
+ unsigned int pahsc_BytesPerInputBuffer; /* native buffer size in bytes */
+ unsigned int pahsc_BytesPerOutputBuffer; /* native buffer size in bytes */
+ /* For measuring CPU utilization. */
+ struct timeval pahsc_EntryTime;
+ double pahsc_InverseMicrosPerBuffer; /* 1/Microseconds of real-time audio per user buffer. */
+
+ /* For calculating stream time */
+ int pahsc_LastPosPtr;
+ double pahsc_LastStreamBytes;
+}
+PaHostSoundControl;
+
+/************************************************* Prototypes **********/
+
+internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id );
+PaError Pa_QueryDevices( void );
+PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad );
+PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate );
+PaError Pa_SetupInputDeviceFormat( int devHandle, int numChannels, int sampleRate );
+PaError Pa_SetupOutputDeviceFormat( int devHandle, int numChannels, int sampleRate );
+void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, int channelsPerFrame );
+void Pa_UpdateStreamTime(PaHostSoundControl *pahsc);
+int Pa_FlushStream(int devHandle);
diff --git a/branches/lydia/portaudio/pa_unix_oss.c b/branches/lydia/portaudio/pa_unix_oss.c
new file mode 100644
index 0000000..01f93d8
--- /dev/null
+++ b/branches/lydia/portaudio/pa_unix_oss.c
@@ -0,0 +1,397 @@
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * Linux OSS Implementation by douglas repetto and Phil Burk
+ *
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Modification history:
+ 20020621: pa_unix_oss.c split into pa_unix.c, pa_unix.h, pa_unix_oss.c by
+ Augustus Saunders. See pa_unix.c for previous history. Pa_FlushStream
+ added by Augustus Saunders for Solaris compatibility.
+ PLB20021018 - Fill device info table with actual sample rates instead of wished for rates.
+ - Allow stream to open if sample rate within 10% of desired rate.
+ 20030630 - Thomas Richter - eliminated unused variable warnings.
+*/
+
+#define HAVE_UNIX 1
+#define HAVE_LINUX 1
+
+#ifdef HAVE_UNIX
+
+#include "pa_unix.h"
+
+#ifdef HAVE_LINUX
+#include <linux/soundcard.h>
+#else
+
+#ifdef HAVE_BSD
+#include <sys/soundcard.h>
+#else
+#include <machine/soundcard.h> /* JH20010905 */
+#endif
+
+#endif
+
+#ifndef AFMT_S16_NE
+#define AFMT_S16_NE Get_AFMT_S16_NE()
+/*********************************************************************
+ * Some versions of OSS do not define AFMT_S16_NE. So check CPU.
+ * PowerPC is Big Endian. X86 is Little Endian.
+ */
+int Get_AFMT_S16_NE( void )
+{
+ long testData = 1;
+ char *ptr = (char *) &testData;
+ int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */
+ return isLittle ? AFMT_S16_LE : AFMT_S16_BE;
+}
+#endif /* AFMT_S16_NE */
+
+
+/*********************************************************************
+ * Try to open the named device.
+ * If it opens, try to set various rates and formats and fill in
+ * the device info structure.
+ */
+PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad )
+{
+ int result = paHostError;
+ int tempDevHandle;
+ int numChannels, maxNumChannels;
+ int format;
+ int numSampleRates;
+ int sampleRate;
+ int numRatesToTry;
+ int lastRate;
+ int ratesToTry[9] = {96000, 48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000};
+ int i;
+
+ /* douglas:
+ we have to do this querying in a slightly different order. apparently
+ some sound cards will give you different info based on their settings.
+ e.g. a card might give you stereo at 22kHz but only mono at 44kHz.
+ the correct order for OSS is: format, channels, sample rate
+
+ */
+ if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 )
+ {
+ DBUG(("Pa_QueryDevice: could not open %s\n", deviceName ));
+ return paHostError;
+ }
+
+ /* Ask OSS what formats are supported by the hardware. */
+ pad->pad_Info.nativeSampleFormats = 0;
+
+ if (ioctl(tempDevHandle, SNDCTL_DSP_GETFMTS, &format) == -1)
+ {
+ ERR_RPT(("Pa_QueryDevice: could not get format info\n" ));
+ goto error;
+ }
+ if( format & AFMT_U8 ) pad->pad_Info.nativeSampleFormats |= paUInt8;
+ if( format & AFMT_S16_NE ) pad->pad_Info.nativeSampleFormats |= paInt16;
+
+ /* Negotiate for the maximum number of channels for this device. PLB20010927
+ * Consider up to 16 as the upper number of channels.
+ * Variable numChannels should contain the actual upper limit after the call.
+ * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.
+ */
+ maxNumChannels = 0;
+ for( numChannels = 1; numChannels <= 16; numChannels++ )
+ {
+ int temp = numChannels;
+ DBUG(("Pa_QueryDevice: use SNDCTL_DSP_CHANNELS, numChannels = %d\n", numChannels ))
+ if(ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 )
+ {
+ /* ioctl() failed so bail out if we already have stereo */
+ if( numChannels > 2 ) break;
+ }
+ else
+ {
+ /* ioctl() worked but bail out if it does not support numChannels.
+ * We don't want to leave gaps in the numChannels supported.
+ */
+ if( (numChannels > 2) && (temp != numChannels) ) break;
+ DBUG(("Pa_QueryDevice: temp = %d\n", temp ))
+ if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */
+ }
+ }
+
+ /* The above negotiation may fail for an old driver so try this older technique. */
+ if( maxNumChannels < 1 )
+ {
+ int stereo = 1;
+ if(ioctl(tempDevHandle, SNDCTL_DSP_STEREO, &stereo) < 0)
+ {
+ maxNumChannels = 1;
+ }
+ else
+ {
+ maxNumChannels = (stereo) ? 2 : 1;
+ }
+ DBUG(("Pa_QueryDevice: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", maxNumChannels ))
+ }
+
+ pad->pad_Info.maxOutputChannels = maxNumChannels;
+ DBUG(("Pa_QueryDevice: maxNumChannels = %d\n", maxNumChannels))
+
+ /* During channel negotiation, the last ioctl() may have failed. This can
+ * also cause sample rate negotiation to fail. Hence the following, to return
+ * to a supported number of channels. SG20011005 */
+ {
+ int temp = maxNumChannels;
+ if( temp > 2 ) temp = 2; /* use most reasonable default value */
+ ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp);
+ }
+
+ /* FIXME - for now, assume maxInputChannels = maxOutputChannels.
+ * Eventually do separate queries for O_WRONLY and O_RDONLY
+ */
+ pad->pad_Info.maxInputChannels = pad->pad_Info.maxOutputChannels;
+
+ DBUG(("Pa_QueryDevice: maxInputChannels = %d\n",
+ pad->pad_Info.maxInputChannels))
+
+
+ /* Determine available sample rates by trying each one and seeing result.
+ * OSS often supports funky rates such as 44188 instead of 44100!
+ */
+ numSampleRates = 0;
+ lastRate = 0;
+ numRatesToTry = sizeof(ratesToTry)/sizeof(int);
+ for (i = 0; i < numRatesToTry; i++)
+ {
+ sampleRate = ratesToTry[i];
+
+ if (ioctl(tempDevHandle, SNDCTL_DSP_SPEED, &sampleRate) >= 0 ) /* PLB20010817 */
+ {
+ /* Use whatever rate OSS tells us. PLB20021018 */
+ if (sampleRate != lastRate)
+ {
+ DBUG(("Pa_QueryDevice: adding sample rate: %d\n", sampleRate))
+ pad->pad_SampleRates[numSampleRates] = (float)sampleRate;
+ numSampleRates++;
+ lastRate = sampleRate;
+ }
+ else
+ {
+ DBUG(("Pa_QueryDevice: dang - got sample rate %d again!\n", sampleRate))
+ }
+ }
+ }
+
+ DBUG(("Pa_QueryDevice: final numSampleRates = %d\n", numSampleRates))
+ if (numSampleRates==0) /* HP20010922 */
+ {
+ /* Desparate attempt to keep running even though no good rates found! */
+ ERR_RPT(("Pa_QueryDevice: no supported sample rate (or SNDCTL_DSP_SPEED ioctl call failed). Force 44100 Hz\n" ));
+ pad->pad_SampleRates[numSampleRates++] = 44100;
+ }
+
+ pad->pad_Info.numSampleRates = numSampleRates;
+ pad->pad_Info.sampleRates = pad->pad_SampleRates; /* use pointer to embedded array */
+
+ pad->pad_Info.name = deviceName;
+
+ result = paNoError;
+
+error:
+ /* We MUST close the handle here or we won't be able to reopen it later!!! */
+ close(tempDevHandle);
+
+ return result;
+}
+
+/*******************************************************************************************/
+PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate )
+{
+ PaError result = paNoError;
+ int tmp;
+
+ /* Set format, channels, and rate in this order to keep OSS happy. */
+ /* Set data format. FIXME - handle more native formats. */
+ tmp = AFMT_S16_NE;
+ if( ioctl(devHandle,SNDCTL_DSP_SETFMT,&tmp) == -1)
+ {
+ ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_SETFMT\n" ));
+ return paHostError;
+ }
+ if( tmp != AFMT_S16_NE )
+ {
+ ERR_RPT(("Pa_SetupDeviceFormat: HW does not support AFMT_S16_NE\n" ));
+ return paHostError;
+ }
+
+
+ /* Set number of channels. */
+ tmp = numChannels;
+ if (ioctl(devHandle, SNDCTL_DSP_CHANNELS, &numChannels) == -1)
+ {
+ ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_CHANNELS\n" ));
+ return paHostError;
+ }
+ if( tmp != numChannels)
+ {
+ ERR_RPT(("Pa_SetupDeviceFormat: HW does not support %d channels\n", numChannels ));
+ return paHostError;
+ }
+
+ /* Set playing frequency. */
+ tmp = sampleRate;
+ if( ioctl(devHandle,SNDCTL_DSP_SPEED,&tmp) == -1)
+ {
+ ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_SPEED\n" ));
+ return paHostError;
+ }
+ else if( tmp != sampleRate )
+ {
+ int percentError = abs( (100 * (sampleRate - tmp)) / sampleRate );
+ PRINT(("Pa_SetupDeviceFormat: warning - requested sample rate = %d Hz - closest = %d\n",
+ sampleRate, tmp ));
+ /* Allow sample rate within 10% off of requested rate. PLB20021018
+ * Sometimes OSS uses a funky rate like 44188 instead of 44100.
+ */
+ if( percentError > 10 )
+ {
+ ERR_RPT(("Pa_SetupDeviceFormat: HW does not support %d Hz sample rate\n",sampleRate ));
+ return paHostError;
+ }
+ }
+
+ return result;
+}
+
+PaError Pa_SetupOutputDeviceFormat( int devHandle, int numChannels, int sampleRate )
+{
+ return Pa_SetupDeviceFormat(devHandle, numChannels, sampleRate);
+}
+
+PaError Pa_SetupInputDeviceFormat( int devHandle, int numChannels, int sampleRate )
+{
+ return Pa_SetupDeviceFormat(devHandle, numChannels, sampleRate);
+}
+
+
+/*******************************************************************************************
+** Set number of fragments and size of fragments to achieve desired latency.
+*/
+
+static int CalcHigherLogTwo( int n )
+{
+ int log2 = 0;
+ while( (1<<log2) < n ) log2++;
+ return log2;
+}
+
+void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, int channelsPerFrame )
+{
+ int tmp;
+ int bufferSize, powerOfTwo;
+
+ /* Increase size of buffers and reduce number of buffers to reduce latency inside driver. */
+ while( numBuffers > 8 )
+ {
+ numBuffers = (numBuffers + 1) >> 1;
+ framesPerBuffer = framesPerBuffer << 1;
+ }
+
+ /* calculate size of buffers in bytes */
+ bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME - other sizes? */
+
+ /* Calculate next largest power of two */
+ powerOfTwo = CalcHigherLogTwo( bufferSize );
+ DBUG(("Pa_SetLatency: numBuffers = %d, framesPerBuffer = %d, powerOfTwo = %d\n",
+ numBuffers, framesPerBuffer, powerOfTwo ));
+
+ /* Encode info into a single int */
+ tmp=(numBuffers<<16) + powerOfTwo;
+
+ if(ioctl(devHandle,SNDCTL_DSP_SETFRAGMENT,&tmp) == -1)
+ {
+ ERR_RPT(("Pa_SetLatency: could not SNDCTL_DSP_SETFRAGMENT\n" ));
+ /* Don't return an error. Best to just continue and hope for the best. */
+ ERR_RPT(("Pa_SetLatency: numBuffers = %d, framesPerBuffer = %d, powerOfTwo = %d\n",
+ numBuffers, framesPerBuffer, powerOfTwo ));
+ }
+}
+
+/***********************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ PaHostSoundControl *pahsc;
+
+ count_info info;
+ int delta;
+
+ if( past == NULL ) return paBadStreamPtr;
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ if( pahsc->pahsc_NativeOutputBuffer )
+ {
+ ioctl(pahsc->pahsc_OutputHandle, SNDCTL_DSP_GETOPTR, &info);
+ delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
+ return (pahsc->pahsc_LastStreamBytes + delta) / (past->past_NumOutputChannels * sizeof(short));
+ }
+ else
+ {
+ ioctl(pahsc->pahsc_InputHandle, SNDCTL_DSP_GETIPTR, &info);
+ delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
+ return (pahsc->pahsc_LastStreamBytes + delta) / (past->past_NumInputChannels * sizeof(short));
+ }
+}
+
+void Pa_UpdateStreamTime(PaHostSoundControl *pahsc)
+{
+ count_info info;
+ int delta;
+
+ /* Update current stream time (using a double so that
+ we don't wrap around like info.bytes does) */
+ if( pahsc->pahsc_NativeOutputBuffer )
+ {
+ ioctl(pahsc->pahsc_OutputHandle, SNDCTL_DSP_GETOPTR, &info);
+ }
+ else
+ {
+ ioctl(pahsc->pahsc_InputHandle, SNDCTL_DSP_GETIPTR, &info);
+ }
+ delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
+ pahsc->pahsc_LastStreamBytes += delta;
+ pahsc->pahsc_LastPosPtr = info.bytes;
+}
+
+PaError Pa_FlushStream(int devHandle)
+{
+ /* AS: This doesn't do anything under OSS; it was added for Solaris.*/
+ devHandle = devHandle; /* unused */
+ return paNoError;
+}
+
+#endif // HAVE_LINUX
diff --git a/branches/lydia/portaudio/portaudio.h b/branches/lydia/portaudio/portaudio.h
new file mode 100644
index 0000000..87d4ed3
--- /dev/null
+++ b/branches/lydia/portaudio/portaudio.h
@@ -0,0 +1,463 @@
+#ifndef PORT_AUDIO_H
+#define PORT_AUDIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: portaudio.h 401 2004-07-23 17:41:54Z jaromil $
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError,
+ paDeviceUnavailable
+} PaErrorNum;
+
+/*
+ Pa_Initialize() is the library initialisation function - call this before
+ using the library.
+
+*/
+
+PaError Pa_Initialize( void );
+
+/*
+ Pa_Terminate() is the library termination function - call this after
+ using the library.
+
+*/
+
+PaError Pa_Terminate( void );
+
+/*
+ Pa_GetHostError() returns a host specific error code.
+ This can be called after receiving a PortAudio error code of paHostError.
+
+*/
+
+long Pa_GetHostError( void );
+
+/*
+ Pa_GetErrorText() translates the supplied PortAudio error number
+ into a human readable message.
+
+*/
+
+const char *Pa_GetErrorText( PaError errnum );
+
+/*
+ Sample formats
+
+ These are formats used to pass sound data between the callback and the
+ stream. Each device has a "native" format which may be used when optimum
+ efficiency or control over conversion is required.
+
+ Formats marked "always available" are supported (emulated) by all
+ PortAudio implementations.
+
+ The floating point representation (paFloat32) uses +1.0 and -1.0 as the
+ maximum and minimum respectively.
+
+ paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
+
+*/
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6))
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pa_CountDevices()-1.
+
+ Devices may support input, output or both.
+
+*/
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+int Pa_CountDevices( void );
+
+typedef struct
+{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+ /* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+ /* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+}
+PaDeviceInfo;
+
+/*
+ Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the
+ default device ids for input and output respectively, or paNoDevice if
+ no device is available.
+ The result can be passed to Pa_OpenStream().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ids by using
+ the supplied application "pa_devs".
+
+*/
+
+PaDeviceID Pa_GetDefaultInputDeviceID( void );
+PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+
+
+
+/*
+ Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
+ for the device specified.
+ If the device parameter is out of range the function returns NULL.
+
+ PortAudio manages the memory referenced by the returned pointer, the client
+ must not manipulate or free the memory. The pointer is only guaranteed to be
+ valid between calls to Pa_Initialize() and Pa_Terminate().
+
+*/
+
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device );
+
+/*
+ PaTimestamp is used to represent a continuous sample clock with arbitrary
+ start time that can be used for syncronization. The type is used for the
+ outTime argument to the PortAudioCallback and as the result of Pa_StreamTime()
+
+*/
+
+typedef double PaTimestamp;
+
+/*
+ PortAudioCallback is implemented by PortAudio clients.
+
+ inputBuffer and outputBuffer are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream() (see below).
+
+ framesPerBuffer is the number of sample frames to be processed by the callback.
+
+ outTime is the time in samples when the buffer(s) processed by
+ this callback will begin being played at the audio output.
+ See also Pa_StreamTime()
+
+ userData is the value of a user supplied pointer passed to Pa_OpenStream()
+ intended for storing synthesis data etc.
+
+ return value:
+ The callback can return a non-zero value to stop the stream. This may be
+ useful in applications such as soundfile players where a specific duration
+ of output is required. However, it is not necessary to utilise this mechanism
+ as StopStream() will also terminate the stream. A callback returning a
+ non-zero value must fill the entire outputBuffer.
+
+ NOTE: None of the other stream functions may be called from within the
+ callback function except for Pa_GetCPULoad().
+
+*/
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+/*
+ Stream flags
+
+ These flags may be supplied (ored together) in the streamFlags argument to
+ the Pa_OpenStream() function.
+
+*/
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable default clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+/*
+ A single PortAudioStream provides multiple channels of real-time
+ input and output audio streaming to a client application.
+ Pointers to PortAudioStream objects are passed between PortAudio functions.
+*/
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+/*
+ Pa_OpenStream() opens a stream for either input, output or both.
+
+ stream is the address of a PortAudioStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PaDeviceID above.)
+ inputDevice may be paNoDevice to indicate that an input device is not required.
+
+ numInputChannels is the number of channels of sound to be delivered to the
+ callback. It can range from 1 to the value of maxInputChannels in the
+ PaDeviceInfo record for the device specified by the inputDevice parameter.
+ If inputDevice is paNoDevice numInputChannels is ignored.
+
+ inputSampleFormat is the sample format of inputBuffer provided to the callback
+ function. inputSampleFormat may be any of the formats described by the
+ PaSampleFormat enumeration (see above). PortAudio guarantees support for
+ the device's native formats (nativeSampleFormats in the device info record)
+ and additionally 16 and 32 bit integer and 32 bit floating point formats.
+ Support for other formats is implementation defined.
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ inputDriverInfo is never required for correct operation. If not used
+ inputDriverInfo should be NULL.
+
+ outputDevice is the id of the device used for output (see PaDeviceID above.)
+ outputDevice may be paNoDevice to indicate that an output device is not required.
+
+ numOutputChannels is the number of channels of sound to be supplied by the
+ callback. See the definition of numInputChannels above for more details.
+
+ outputSampleFormat is the sample format of the outputBuffer filled by the
+ callback function. See the definition of inputSampleFormat above for more
+ details.
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ sampleRate is the desired sampleRate. For full-duplex streams it is the
+ sample rate for both input and output
+
+ framesPerBuffer is the length in sample frames of all internal sample buffers
+ used for communication with platform specific audio routines. Wherever
+ possible this corresponds to the framesPerBuffer parameter passed to the
+ callback function.
+
+ numberOfBuffers is the number of buffers used for multibuffered communication
+ with the platform specific audio routines. If you pass zero, then an optimum
+ value will be chosen for you internally. This parameter is provided only
+ as a guide - and does not imply that an implementation must use multibuffered
+ i/o when reliable double buffering is available (such as SndPlayDoubleBuffer()
+ on the Macintosh.)
+
+ streamFlags may contain a combination of flags ORed together.
+ These flags modify the behaviour of the streaming process. Some flags may only
+ be relevant to certain buffer formats.
+
+ callback is a pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers (see above for details.)
+
+ userData is a client supplied pointer which is passed to the callback
+ function. It could for example, contain a pointer to instance data necessary
+ for processing the audio buffers.
+
+ return value:
+ Upon success Pa_OpenStream() returns PaNoError and places a pointer to a
+ valid PortAudioStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails a non-zero error code is returned (see
+ PaError above) and the value of stream is invalid.
+
+*/
+
+PaError Pa_OpenStream( PortAudioStream** stream,
+ PaDeviceID inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+/*
+ Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens
+ the default input and/or output devices. Most parameters have identical meaning
+ to their Pa_OpenStream() counterparts, with the following exceptions:
+
+ If either numInputChannels or numOutputChannels is 0 the respective device
+ is not opened. This has the same effect as passing paNoDevice in the device
+ arguments to Pa_OpenStream().
+
+ sampleFormat applies to both the input and output buffers.
+
+*/
+
+PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+/*
+ Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+
+*/
+
+PaError Pa_CloseStream( PortAudioStream* );
+
+/*
+ Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
+ Pa_StopStream() waits until all pending audio buffers have been played.
+ Pa_AbortStream() stops playing immediately without waiting for pending
+ buffers to complete.
+
+*/
+
+PaError Pa_StartStream( PortAudioStream *stream );
+
+PaError Pa_StopStream( PortAudioStream *stream );
+
+PaError Pa_AbortStream( PortAudioStream *stream );
+
+/*
+ Pa_StreamActive() returns one (1) when the stream is active (ie playing
+ or recording audio), zero (0) when not playing, or a negative error number
+ if the stream is invalid.
+ The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+ but may also become inactive if the callback returns a non-zero value.
+ In the latter case, the stream is considered inactive after the last
+ buffer has finished playing.
+
+*/
+
+PaError Pa_StreamActive( PortAudioStream *stream );
+
+/*
+ Pa_StreamTime() returns the current output time in samples for the stream.
+ This time may be used as a time reference (for example synchronizing audio to
+ MIDI).
+
+*/
+
+PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+/*
+ Pa_GetCPULoad() returns the CPU Load for the stream.
+ The "CPU Load" is a fraction of total CPU time consumed by the stream's
+ audio processing routines including, but not limited to the client supplied
+ callback.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ This function may be called from the callback function or the application.
+
+*/
+
+double Pa_GetCPULoad( PortAudioStream* stream );
+
+/*
+ Pa_GetMinNumBuffers() returns the minimum number of buffers required by
+ the current host based on minimum latency.
+ On the PC, for the DirectSound implementation, latency can be optionally set
+ by user by setting an environment variable.
+ For example, to set latency to 200 msec, put:
+
+ set PA_MIN_LATENCY_MSEC=200
+
+ in the AUTOEXEC.BAT file and reboot.
+ If the environment variable is not set, then the latency will be determined
+ based on the OS. Windows NT has higher latency than Win95.
+
+*/
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
+
+/*
+ Pa_Sleep() puts the caller to sleep for at least 'msec' milliseconds.
+ You may sleep longer than the requested time so don't rely on this for
+ accurate musical timing.
+
+ Pa_Sleep() is provided as a convenience for authors of portable code (such as
+ the tests and examples in the PortAudio distribution.)
+
+*/
+
+void Pa_Sleep( long msec );
+
+/*
+ Pa_GetSampleSize() returns the size in bytes of a single sample in the
+ supplied PaSampleFormat, or paSampleFormatNotSupported if the format is
+ no supported.
+
+*/
+
+PaError Pa_GetSampleSize( PaSampleFormat format );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_AUDIO_H */