From c98797d938b4f5824f72dc7cbcb74d274d07007c Mon Sep 17 00:00:00 2001 From: phil Date: Tue, 22 Jan 2002 00:51:49 +0000 Subject: [PATCH 001/814] Initial revision --- Makefile.linux | 46 + fixdir.bat | 19 + pa_asio/Callback_adaptation_.pdf | Bin 0 -> 50527 bytes pa_asio/Pa_ASIO.pdf | Bin 0 -> 50778 bytes pa_asio/pa_asio.cpp | 3005 ++++++++++++++++++++++ pa_beos/PlaybackNode.cc | 538 ++++ pa_beos/PlaybackNode.h | 108 + pa_beos/pa_beos_mk.cc | 441 ++++ pa_common/pa_host.h | 142 + pa_common/pa_lib.c | 836 ++++++ pa_common/pa_trace.c | 83 + pa_common/pa_trace.h | 67 + pa_common/portaudio.h | 432 ++++ pa_dll_switch/PaDllEntry.h | 184 ++ pa_dll_switch/letter_from_tim_010817.txt | Bin 0 -> 1176 bytes pa_dll_switch/loadPA_DLL.cpp | 203 ++ pa_dll_switch/pa_lib.c | 827 ++++++ pa_dll_switch/portaudio.h | 439 ++++ pa_mac/pa_mac.c | 1567 +++++++++++ pa_mac_core/pa_mac_core.c | 1159 +++++++++ pa_sgi/Makefile | 52 + pa_sgi/pa_sgi.c | 991 +++++++ pa_tests/debug_dual.c | 183 ++ pa_tests/debug_multi_in.c | 179 ++ pa_tests/debug_multi_out.c | 165 ++ pa_tests/debug_record.c | 297 +++ pa_tests/debug_sine.c | 192 ++ pa_tests/debug_sine_wait.c | 138 + pa_tests/debug_test1.c | 114 + pa_tests/pa_devs.c | 98 + pa_tests/pa_fuzz.c | 155 ++ pa_tests/pa_minlat.c | 164 ++ pa_tests/paqa_devs.c | 317 +++ pa_tests/paqa_errs.c | 305 +++ pa_tests/patest1.c | 114 + pa_tests/patest_buffer.c | 181 ++ pa_tests/patest_clip.c | 156 ++ pa_tests/patest_dither.c | 151 ++ pa_tests/patest_latency.c | 171 ++ pa_tests/patest_leftright.c | 163 ++ pa_tests/patest_longsine.c | 124 + pa_tests/patest_many.c | 194 ++ pa_tests/patest_maxsines.c | 155 ++ pa_tests/patest_pink.c | 245 ++ pa_tests/patest_record.c | 303 +++ pa_tests/patest_ringmix.c | 41 + pa_tests/patest_saw.c | 118 + pa_tests/patest_sine.c | 138 + pa_tests/patest_sine8.c | 184 ++ pa_tests/patest_sine_formats.c | 198 ++ pa_tests/patest_sine_time.c | 165 ++ pa_tests/patest_stop.c | 285 ++ pa_tests/patest_sync.c | 227 ++ pa_tests/patest_underflow.c | 151 ++ pa_tests/patest_wire.c | 139 + pa_unix_oss/Makefile | 38 + pa_unix_oss/Makefile_freebsd | 36 + pa_unix_oss/low_latency_tip.txt | Bin 0 -> 3111 bytes pa_unix_oss/pa_unix_oss.c | 1072 ++++++++ pa_unix_oss/recplay.c | 114 + pa_win_ds/dsound_wrapper.c | 466 ++++ pa_win_ds/dsound_wrapper.h | 106 + pa_win_ds/pa_dsound.c | 983 +++++++ pa_win_ds/portaudio.def | 28 + pa_win_wmme/Makefile.cygwin | 34 + pa_win_wmme/pa_win_wmme.c | 1493 +++++++++++ pablio/README.txt | 39 + pablio/pablio.c | 307 +++ pablio/pablio.def | 35 + pablio/pablio.h | 109 + pablio/ringbuffer.c | 199 ++ pablio/ringbuffer.h | 101 + pablio/test_rw.c | 99 + pablio/test_rw_echo.c | 123 + pablio/test_w_saw.c | 108 + pablio/test_w_saw8.c | 106 + 76 files changed, 22645 insertions(+) create mode 100644 Makefile.linux create mode 100755 fixdir.bat create mode 100644 pa_asio/Callback_adaptation_.pdf create mode 100644 pa_asio/Pa_ASIO.pdf create mode 100644 pa_asio/pa_asio.cpp create mode 100644 pa_beos/PlaybackNode.cc create mode 100644 pa_beos/PlaybackNode.h create mode 100644 pa_beos/pa_beos_mk.cc create mode 100644 pa_common/pa_host.h create mode 100644 pa_common/pa_lib.c create mode 100644 pa_common/pa_trace.c create mode 100644 pa_common/pa_trace.h create mode 100644 pa_common/portaudio.h create mode 100644 pa_dll_switch/PaDllEntry.h create mode 100644 pa_dll_switch/letter_from_tim_010817.txt create mode 100644 pa_dll_switch/loadPA_DLL.cpp create mode 100644 pa_dll_switch/pa_lib.c create mode 100644 pa_dll_switch/portaudio.h create mode 100644 pa_mac/pa_mac.c create mode 100644 pa_mac_core/pa_mac_core.c create mode 100644 pa_sgi/Makefile create mode 100644 pa_sgi/pa_sgi.c create mode 100644 pa_tests/debug_dual.c create mode 100644 pa_tests/debug_multi_in.c create mode 100644 pa_tests/debug_multi_out.c create mode 100644 pa_tests/debug_record.c create mode 100644 pa_tests/debug_sine.c create mode 100644 pa_tests/debug_sine_wait.c create mode 100644 pa_tests/debug_test1.c create mode 100644 pa_tests/pa_devs.c create mode 100644 pa_tests/pa_fuzz.c create mode 100644 pa_tests/pa_minlat.c create mode 100644 pa_tests/paqa_devs.c create mode 100644 pa_tests/paqa_errs.c create mode 100644 pa_tests/patest1.c create mode 100644 pa_tests/patest_buffer.c create mode 100644 pa_tests/patest_clip.c create mode 100644 pa_tests/patest_dither.c create mode 100644 pa_tests/patest_latency.c create mode 100644 pa_tests/patest_leftright.c create mode 100644 pa_tests/patest_longsine.c create mode 100644 pa_tests/patest_many.c create mode 100644 pa_tests/patest_maxsines.c create mode 100644 pa_tests/patest_pink.c create mode 100644 pa_tests/patest_record.c create mode 100644 pa_tests/patest_ringmix.c create mode 100644 pa_tests/patest_saw.c create mode 100644 pa_tests/patest_sine.c create mode 100644 pa_tests/patest_sine8.c create mode 100644 pa_tests/patest_sine_formats.c create mode 100644 pa_tests/patest_sine_time.c create mode 100644 pa_tests/patest_stop.c create mode 100644 pa_tests/patest_sync.c create mode 100644 pa_tests/patest_underflow.c create mode 100644 pa_tests/patest_wire.c create mode 100644 pa_unix_oss/Makefile create mode 100644 pa_unix_oss/Makefile_freebsd create mode 100644 pa_unix_oss/low_latency_tip.txt create mode 100644 pa_unix_oss/pa_unix_oss.c create mode 100644 pa_unix_oss/recplay.c create mode 100644 pa_win_ds/dsound_wrapper.c create mode 100644 pa_win_ds/dsound_wrapper.h create mode 100644 pa_win_ds/pa_dsound.c create mode 100644 pa_win_ds/portaudio.def create mode 100644 pa_win_wmme/Makefile.cygwin create mode 100644 pa_win_wmme/pa_win_wmme.c create mode 100644 pablio/README.txt create mode 100644 pablio/pablio.c create mode 100644 pablio/pablio.def create mode 100644 pablio/pablio.h create mode 100644 pablio/ringbuffer.c create mode 100644 pablio/ringbuffer.h create mode 100644 pablio/test_rw.c create mode 100644 pablio/test_rw_echo.c create mode 100644 pablio/test_w_saw.c create mode 100644 pablio/test_w_saw8.c diff --git a/Makefile.linux b/Makefile.linux new file mode 100644 index 0000000..9f67ce6 --- /dev/null +++ b/Makefile.linux @@ -0,0 +1,46 @@ +# Make PortAudio for Linux +# Updated 2001/08/25 Bill Eldridge bill@rfa.org +# Updated 2001/10/16, philburk@softsynth.com, s/unix_oss/unix_oss/ + +# A pretty bare makefile, that figures out all the test files +# and compiles them against the library in the pa_unix_oss directory. + +# Do "make all" and then when happy, "make libinstall" +# (if not happy, "make clean") + +# The ldconfig stuff in libinstall is the wrong way to do it - +# someone tell me the right way, please + + +LIBS = -lm -lpthread + +CDEFINES = -I../pa_common +CFLAGS = -g +LIBINST = /usr/local/lib + +TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) + +LIBFILES:= ./pa_common/pa_lib.c ./pa_unix_oss/pa_unix_oss.c + +.c.o: + -gcc -c -I./pa_common $< -o $*.o + -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio + +all: sharedlib tests + +sharedlib: $(LIBFILES:.c=.o) + gcc -shared -o ./pa_unix_oss/libportaudio.so ./pa_common/pa_lib.o ./pa_unix_oss/pa_unix_oss.o + +libinstall: ./pa_unix_oss/libportaudio.so + @cp -f ./pa_unix_oss/libportaudio.so $(LIBINST) + @/sbin/ldconfig -v + +tests: $(TESTS:.c=.o) + +clean: + -@rm -f $(TESTS:.c=.o) + -@rm -f $(TESTS:.c=) + -@rm -f $(LIBFILES:.c=.o) + -@rm -f ./pa_unix_oss/libportaudio.so + + diff --git a/fixdir.bat b/fixdir.bat new file mode 100755 index 0000000..92d6c74 --- /dev/null +++ b/fixdir.bat @@ -0,0 +1,19 @@ +rem Use Astyle to fix style in 'C' files +cd %1% + +fixlines -p *.c +fixlines -p *.cpp +fixlines -p *.cc + +astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c +astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cpp +astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cc +del *.orig +@rem convert line terminators to Unix style LFs +fixlines -u *.c +fixlines -u *.cpp +fixlines -u *.cc +fixlines -u *.h +del *.bak + +cd ..\ diff --git a/pa_asio/Callback_adaptation_.pdf b/pa_asio/Callback_adaptation_.pdf new file mode 100644 index 0000000000000000000000000000000000000000..76bf67863524626aa079d74629c9dd9f720b0b54 GIT binary patch literal 50527 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 +#include + +#include "portaudio.h" +#include "pa_host.h" +#include "pa_trace.h" + +#include "asiosys.h" +#include "asio.h" +#include "asiodrivers.h" + +#if MAC +#include +#else +#include +#include +#include +#endif + +enum { + // number of input and outputs supported by the host application + // you can change these to higher or lower values + kMaxInputChannels = 32, + kMaxOutputChannels = 32 +}; + +/* ASIO specific device information. */ +typedef struct internalPortAudioDevice +{ + PaDeviceInfo pad_Info; +} internalPortAudioDevice; + + +/* ASIO driver internal data storage */ +typedef struct PaHostSoundControl +{ + // ASIOInit() + ASIODriverInfo pahsc_driverInfo; + + // ASIOGetChannels() + int32 pahsc_NumInputChannels; + int32 pahsc_NumOutputChannels; + + // ASIOGetBufferSize() - sizes in frames per buffer + int32 pahsc_minSize; + int32 pahsc_maxSize; + int32 pahsc_preferredSize; + int32 pahsc_granularity; + + // ASIOGetSampleRate() + ASIOSampleRate pahsc_sampleRate; + + // ASIOOutputReady() + bool pahsc_postOutput; + + // ASIOGetLatencies () + int32 pahsc_inputLatency; + int32 pahsc_outputLatency; + + // ASIOCreateBuffers () + ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's + + // ASIOGetChannelInfo() + ASIOChannelInfo pahsc_channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's + // The above two arrays share the same indexing, as the data in them are linked together + + // Information from ASIOGetSamplePosition() + // data is converted to double floats for easier use, however 64 bit integer can be used, too + double nanoSeconds; + double samples; + double tcSamples; // time code samples + + // bufferSwitchTimeInfo() + ASIOTime tInfo; // time info state + unsigned long sysRefTime; // system reference time, when bufferSwitch() was called + + // Signal the end of processing in this example + bool stopped; + + ASIOCallbacks pahsc_asioCallbacks; + + + int32 pahsc_userInputBufferFrameOffset; // Position in Input user buffer + int32 pahsc_userOutputBufferFrameOffset; // Position in Output user buffer + int32 pahsc_hostOutputBufferFrameOffset; // Position in Output ASIO buffer + + int32 past_FramesPerHostBuffer; // Number of frames in ASIO buffer + + int32 pahsc_InputBufferOffset; // Number of null frames for input buffer alignement + int32 pahsc_OutputBufferOffset; // Number of null frames for ouput buffer alignement + +#if MAC + UInt64 pahsc_EntryCount; + UInt64 pahsc_LastExitCount; +#elif WINDOWS + LARGE_INTEGER pahsc_EntryCount; + LARGE_INTEGER pahsc_LastExitCount; +#endif + + PaTimestamp pahsc_NumFramesDone; + + internalPortAudioStream *past; + +} PaHostSoundControl; + + +//---------------------------------------------------------- +// name of the ASIO device to be used +#if WINDOWS + //#define ASIO_DRIVER_NAME "ASIO Multimedia Driver" + #define ASIO_DRIVER_NAME "ASIO Sample" +#elif MAC + //#define ASIO_DRIVER_NAME "Apple Sound Manager" + #define ASIO_DRIVER_NAME "ASIO Delta1010" + //#define ASIO_DRIVER_NAME "DigiDesign DirectIO" +#endif + +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) + +#define DBUG(x) /* PRINT(x) */ +#define DBUGX(x) /* PRINT(x) /**/ + +/* We are trying to be compatible with CARBON but this has not been thoroughly tested. */ +#define CARBON_COMPATIBLE (0) +#define PA_MAX_DEVICE_INFO (32) + +#define MIN_INT8 (-0x80) +#define MAX_INT8 (0x7F) + +#define MIN_INT8_FP ((float)-0x80) +#define MAX_INT8_FP ((float)0x7F) + +#define MIN_INT16_FP ((float)-0x8000) +#define MAX_INT16_FP ((float)0x7FFF) + +#define MIN_INT16 (-0x8000) +#define MAX_INT16 (0x7FFF) + +#define MAX_INT32_FP (2147483520.0f) /* 0x0x7FFFFF80 - seems safe */ + +/************************************************************************************/ +/****************** Data ************************************************************/ +/************************************************************************************/ +static int sNumDevices = 0; +static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 }; +static int32 sPaHostError = 0; +static int sDefaultOutputDeviceID = 0; +static int sDefaultInputDeviceID = 0; + +PaHostSoundControl asioDriverInfo = {0}; + +#ifdef MAC +static bool swap = true; +#elif WINDOWS +static bool swap = false; +#endif + +// Prototypes +void bufferSwitch(long index, ASIOBool processNow); +ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); +void sampleRateChanged(ASIOSampleRate sRate); +long asioMessages(long selector, long value, void* message, double* opt); +static void Pa_StartUsageCalculation( internalPortAudioStream *past ); +static void Pa_EndUsageCalculation( internalPortAudioStream *past ); + +void Pa_ASIO_Convert_Inter_Input( + ASIOBufferInfo* nativeBuffer, + void* inputBuffer, + short NumInputChannels, + short NumOuputChannels, + short framePerBuffer, + short hostFrameOffset, + short userFrameOffset, + ASIOSampleType nativeFormat, + PaSampleFormat paFormat, + PaStreamFlags flags, + short index); + +void Pa_ASIO_Convert_Inter_Output( + ASIOBufferInfo* nativeBuffer, + void* outputBuffer, + short NumInputChannels, + short NumOuputChannels, + short framePerBuffer, + short hostFrameOffset, + short userFrameOffset, + ASIOSampleType nativeFormat, + PaSampleFormat paFormat, + PaStreamFlags flags, + short index); + + void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, + ASIOSampleType nativeFormat, + short NumInputChannels, + short NumOuputChannels, + int index, + int hostFrameOffset, + int frames); + +void Pa_ASIO_Callback_Input(long index); +void Pa_ASIO_Callback_Output(long index, long framePerBuffer); +void Pa_ASIO_Callback_End(); +void Pa_ASIO_Clear_User_Buffers(); + +// Some external references +extern AsioDrivers* asioDrivers ; +bool loadAsioDriver(char *name); +unsigned long get_sys_reference_time(); + + +// For callback debugging on Mac : to be removed in the final version + +/* +#define MidiSharePPC_68k +#include + +void SendVal (long val) +{ + MidiEvPtr ev = MidiNewEv(typeTempo); + if (ev) { + Tempo(ev) = val; + MidiSendIm(0,ev); + } +} + +void MidiPrintText ( char * s) +{ + MidiEvPtr e; + long c = 0; + + if (e = MidiNewEv(typeTextual)){ + for (c = 0 ; *s ; s++,c++) MidiAddField (e ,*s); + MidiSendIm (0, e); + } +} +*/ + + +/************************************************************************************/ +/****************** Macro ************************************************************/ +/************************************************************************************/ + +#define SwapLong(v) ((((v)>>24)&0xFF)|(((v)>>8)&0xFF00)|(((v)&0xFF00)<<8)|(((v)&0xFF)<<24)) ; +#define SwapShort(v) ((((v)>>8)&0xFF)|(((v)&0xFF)<<8)) ; + +#define ClipShort(v) (((v)MAX_INT16)?MAX_INT16:(v))) +#define ClipChar(v) (((v)MAX_INT8)?MAX_INT8:(v))) +#define ClipFloat(v) (((v)<-1.0f)?-1.0f:(((v)>1.0f)?1.0f:(v))) + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifndef max +#define max(a,b) ((a)>=(b)?(a):(b)) +#endif + + +// Utilities for alignement buffer size computation +int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);} +int PPCM (int a, int b) {return (a*b) / PGCD (a,b);} + +// Takes the size of host buffer and user buffer : returns the number of frames needed for buffer alignement +int Pa_ASIO_CalcFrameShift (int M, int N) +{ + int res = 0; + for (int i = M; i < PPCM (M,N) ; i+=M) { res = max (res, i%N); } + return res; +} + +// We have the following relation : +// Pa_ASIO_CalcFrameShift (M,N) + M = Pa_ASIO_CalcFrameShift (N,M) + N + +/* ASIO sample type to PortAudio sample type conversion */ +static PaSampleFormat Pa_ASIO_Convert_SampleFormat(ASIOSampleType type) +{ + switch (type) { + + case ASIOSTInt16MSB: + case ASIOSTInt16LSB: + case ASIOSTInt32MSB16: + case ASIOSTInt32LSB16: + return paInt16; + + case ASIOSTFloat32MSB: + case ASIOSTFloat32LSB: + case ASIOSTFloat64MSB: + case ASIOSTFloat64LSB: + return paFloat32; + + case ASIOSTInt32MSB: + case ASIOSTInt32LSB: + case ASIOSTInt32MSB18: + case ASIOSTInt32MSB20: + case ASIOSTInt32MSB24: + case ASIOSTInt32LSB18: + case ASIOSTInt32LSB20: + case ASIOSTInt32LSB24: + return paInt32; + + case ASIOSTInt24MSB: + case ASIOSTInt24LSB: + return paInt24; + + default: + return paCustomFormat; + } +} + +/* Allocate ASIO buffers, initialise channels */ +static ASIOError Pa_ASIO_CreateBuffers (PaHostSoundControl *asioDriverInfo, long InputChannels, + long OutputChannels, long framesPerBuffer) +{ + ASIOError err; + int i; + + ASIOBufferInfo *info = asioDriverInfo->bufferInfos; + + // Check parameters + if ((InputChannels > kMaxInputChannels) || (OutputChannels > kMaxInputChannels)) return ASE_InvalidParameter; + + for(i = 0; i < InputChannels; i++, info++){ + info->isInput = ASIOTrue; + info->channelNum = i; + info->buffers[0] = info->buffers[1] = 0; + } + + for(i = 0; i < OutputChannels; i++, info++){ + info->isInput = ASIOFalse; + info->channelNum = i; + info->buffers[0] = info->buffers[1] = 0; + } + + // Set up the asioCallback structure and create the ASIO data buffer + asioDriverInfo->pahsc_asioCallbacks.bufferSwitch = &bufferSwitch; + asioDriverInfo->pahsc_asioCallbacks.sampleRateDidChange = &sampleRateChanged; + asioDriverInfo->pahsc_asioCallbacks.asioMessage = &asioMessages; + asioDriverInfo->pahsc_asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo; + + DBUG(("PortAudio : ASIOCreateBuffers with size = %ld \n", framesPerBuffer)); + + err = ASIOCreateBuffers( asioDriverInfo->bufferInfos, InputChannels+OutputChannels, + framesPerBuffer, &asioDriverInfo->pahsc_asioCallbacks); + if (err != ASE_OK) return err; + + // Initialise buffers + for (i = 0; i < InputChannels + OutputChannels; i++) + { + asioDriverInfo->pahsc_channelInfos[i].channel = asioDriverInfo->bufferInfos[i].channelNum; + asioDriverInfo->pahsc_channelInfos[i].isInput = asioDriverInfo->bufferInfos[i].isInput; + err = ASIOGetChannelInfo(&asioDriverInfo->pahsc_channelInfos[i]); + if (err != ASE_OK) break; + } + + err = ASIOGetLatencies(&asioDriverInfo->pahsc_inputLatency, &asioDriverInfo->pahsc_outputLatency); + + DBUG(("PortAudio : InputLatency = %ld latency = %ld msec \n", + asioDriverInfo->pahsc_inputLatency, + (long)((asioDriverInfo->pahsc_inputLatency*1000)/ asioDriverInfo->past->past_SampleRate))); + DBUG(("PortAudio : OuputLatency = %ld latency = %ld msec \n", + asioDriverInfo->pahsc_outputLatency, + (long)((asioDriverInfo->pahsc_outputLatency*1000)/ asioDriverInfo->past->past_SampleRate))); + + return err; +} + + +/* + Query ASIO driver info : + + First we get all available ASIO drivers located in the ASIO folder, + then try to load each one. For each loaded driver, get all needed informations. +*/ +static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) +{ + +#define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */ +#define NUM_CUSTOMSAMPLINGRATES 9 /* must be the same number of elements as in the array below */ +#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES) + + ASIOSampleRate possibleSampleRates[] + = {8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0}; + + ASIOChannelInfo channelInfos; + long InputChannels,OutputChannels; + double *sampleRates; + char* names[PA_MAX_DEVICE_INFO] ; + PaDeviceInfo *dev; + int i; + int numDrivers; + ASIOError asioError; + + /* Allocate names */ + for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) names[i] = (char*)PaHost_AllocateFastMemory(32); + + /* MUST BE CHECKED : to force fragments loading on Mac */ + loadAsioDriver("dummy"); + + /* Get names of all available ASIO drivers */ + asioDrivers->getDriverNames(names,PA_MAX_DEVICE_INFO); + + /* Check all available ASIO drivers */ +#if MAC + numDrivers = asioDrivers->getNumFragments(); +#elif WINDOWS + numDrivers = asioDrivers->asioGetNumDev(); +#endif + DBUG(("PaASIO_QueryDeviceInfo: numDrivers = %d\n", numDrivers )); + + for (int driver = 0 ; driver < numDrivers ; driver++) + { + + #if WINDOWS + asioDriverInfo.pahsc_driverInfo.asioVersion = 2; // FIXME - is this right? PLB + asioDriverInfo.pahsc_driverInfo.sysRef = GetDesktopWindow(); // FIXME - is this right? PLB + #endif + + /* If the driver can be loaded : */ + if ( !loadAsioDriver(names[driver]) ) + { + DBUG(("PaASIO_QueryDeviceInfo could not loadAsioDriver %s\n", names[driver])); + } + else if( (asioError = ASIOInit(&asioDriverInfo.pahsc_driverInfo)) != ASE_OK ) + { + DBUG(("PaASIO_QueryDeviceInfo: ASIOInit returned %d for %s\n", asioError, names[driver])); + } + else if( (ASIOGetChannels(&InputChannels, &OutputChannels) != ASE_OK)) + { + DBUG(("PaASIO_QueryDeviceInfo could not ASIOGetChannels for %s\n", names[driver])); + } + else + { + + /* Gets the name */ + dev = &(ipad[driver].pad_Info); + dev->name = names[driver]; + names[driver] = 0; + + /* Gets Input and Output channels number */ + dev->maxInputChannels = InputChannels; + dev->maxOutputChannels = OutputChannels; + + DBUG(("PaASIO_QueryDeviceInfo: InputChannels = %d\n", InputChannels )); + DBUG(("PaASIO_QueryDeviceInfo: OutputChannels = %d\n", OutputChannels )); + + /* Make room in case device supports all rates. */ + sampleRates = (double*)PaHost_AllocateFastMemory( MAX_NUMSAMPLINGRATES * sizeof(double)); + dev->sampleRates = sampleRates; + dev->numSampleRates = 0; + + /* Loop through the possible sampling rates and check each to see if the device supports it. */ + for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) { + if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) { + DBUG(("PortAudio : possible sample rate = %d\n", (long)possibleSampleRates[index])); + dev->numSampleRates+=1; + *sampleRates = possibleSampleRates[index]; + sampleRates++; + } + } + + /* We assume that all channels have the same SampleType, so check the first */ + channelInfos.channel = 0; + channelInfos.isInput = 1; + ASIOGetChannelInfo(&channelInfos); + + dev->nativeSampleFormats = Pa_ASIO_Convert_SampleFormat(channelInfos.type); + + /* unload the driver */ + ASIODisposeBuffers(); + ASIOExit(); + + sNumDevices++; + } + } + + /* free only unused names */ + for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) if (names[i]) PaHost_FreeFastMemory(names[i],32); + + return paNoError; +} + +//---------------------------------------------------------------------------------- +// TAKEN FROM THE ASIO SDK: +void sampleRateChanged(ASIOSampleRate sRate) +{ + // do whatever you need to do if the sample rate changed + // usually this only happens during external sync. + // Audio processing is not stopped by the driver, actual sample rate + // might not have even changed, maybe only the sample rate status of an + // AES/EBU or S/PDIF digital input at the audio device. + // You might have to update time/sample related conversion routines, etc. +} + +//---------------------------------------------------------------------------------- +// TAKEN FROM THE ASIO SDK: +long asioMessages(long selector, long value, void* message, double* opt) +{ + // currently the parameters "value", "message" and "opt" are not used. + long ret = 0; + switch(selector) + { + case kAsioSelectorSupported: + if(value == kAsioResetRequest + || value == kAsioEngineVersion + || value == kAsioResyncRequest + || value == kAsioLatenciesChanged + // the following three were added for ASIO 2.0, you don't necessarily have to support them + || value == kAsioSupportsTimeInfo + || value == kAsioSupportsTimeCode + || value == kAsioSupportsInputMonitor) + ret = 1L; + break; + + case kAsioBufferSizeChange: + //printf("kAsioBufferSizeChange \n"); + break; + + case kAsioResetRequest: + // defer the task and perform the reset of the driver during the next "safe" situation + // You cannot reset the driver right now, as this code is called from the driver. + // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction + // Afterwards you initialize the driver again. + asioDriverInfo.stopped; // In this sample the processing will just stop + ret = 1L; + break; + case kAsioResyncRequest: + // This informs the application, that the driver encountered some non fatal data loss. + // It is used for synchronization purposes of different media. + // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the + // Windows Multimedia system, which could loose data because the Mutex was hold too long + // by another thread. + // However a driver can issue it in other situations, too. + ret = 1L; + break; + case kAsioLatenciesChanged: + // This will inform the host application that the drivers were latencies changed. + // Beware, it this does not mean that the buffer sizes have changed! + // You might need to update internal delay data. + ret = 1L; + //printf("kAsioLatenciesChanged \n"); + break; + case kAsioEngineVersion: + // return the supported ASIO version of the host application + // If a host applications does not implement this selector, ASIO 1.0 is assumed + // by the driver + ret = 2L; + break; + case kAsioSupportsTimeInfo: + // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback + // is supported. + // For compatibility with ASIO 1.0 drivers the host application should always support + // the "old" bufferSwitch method, too. + ret = 1; + break; + case kAsioSupportsTimeCode: + // informs the driver wether application is interested in time code info. + // If an application does not need to know about time code, the driver has less work + // to do. + ret = 0; + break; + } + return ret; +} + + +//---------------------------------------------------------------------------------- +// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float +#if NATIVE_INT64 + #define ASIO64toDouble(a) (a) +#else + const double twoRaisedTo32 = 4294967296.; + #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32) +#endif + + +ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow) +{ + // the actual processing callback. + // Beware that this is normally in a seperate thread, hence be sure that you take care + // about thread synchronization. This is omitted here for simplicity. + + static processedSamples = 0; + int result = 0; + + // store the timeInfo for later use + asioDriverInfo.tInfo = *timeInfo; + + // get the time stamp of the buffer, not necessary if no + // synchronization to other media is required + + if (timeInfo->timeInfo.flags & kSystemTimeValid) + asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime); + else + asioDriverInfo.nanoSeconds = 0; + + if (timeInfo->timeInfo.flags & kSamplePositionValid) + asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition); + else + asioDriverInfo.samples = 0; + + if (timeInfo->timeCode.flags & kTcValid) + asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples); + else + asioDriverInfo.tcSamples = 0; + + // get the system reference time + asioDriverInfo.sysRefTime = get_sys_reference_time(); + +#if 0 + // a few debug messages for the Windows device driver developer + // tells you the time when driver got its interrupt and the delay until the app receives + // the event notification. + static double last_samples = 0; + char tmp[128]; + sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples)); + OutputDebugString (tmp); + last_samples = asioDriverInfo.samples; +#endif + + // To avoid the callback accessing a desallocated stream + if( asioDriverInfo.past == NULL) return 0L; + + // Keep sample position + asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo; + + /* Has a user callback returned '1' to indicate finished at the last ASIO callback? */ + if( asioDriverInfo.past->past_StopSoon ) { + + Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos, + asioDriverInfo.pahsc_channelInfos[0].type, + asioDriverInfo.pahsc_NumInputChannels , + asioDriverInfo.pahsc_NumOutputChannels, + index, + 0, + asioDriverInfo.past_FramesPerHostBuffer); + + asioDriverInfo.past->past_IsActive = 0; + + // Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place + if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady(); + + }else { + + /* CPU usage */ + Pa_StartUsageCalculation(asioDriverInfo.past); + + Pa_ASIO_Callback_Input(index); + + // Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place + if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady(); + + Pa_ASIO_Callback_End(); + + /* CPU usage */ + Pa_EndUsageCalculation(asioDriverInfo.past); + } + + return 0L; +} + + +//---------------------------------------------------------------------------------- +void bufferSwitch(long index, ASIOBool processNow) +{ + // the actual processing callback. + // Beware that this is normally in a seperate thread, hence be sure that you take care + // about thread synchronization. This is omitted here for simplicity. + + // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created + // though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags + + ASIOTime timeInfo; + memset (&timeInfo, 0, sizeof (timeInfo)); + + // get the time stamp of the buffer, not necessary if no + // synchronization to other media is required + if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK) + timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid; + + // Call the real callback + bufferSwitchTimeInfo (&timeInfo, index, processNow); +} + +//---------------------------------------------------------------------------------- +unsigned long get_sys_reference_time() +{ + // get the system reference time + #if WINDOWS + return timeGetTime(); + #elif MAC + static const double twoRaisedTo32 = 4294967296.; + UnsignedWide ys; + Microseconds(&ys); + double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo); + return (unsigned long)(r / 1000.); + #endif +} + + +/************************************************************* +** Calculate 2 LSB dither signal with a triangular distribution. +** Ranged properly for adding to a 32 bit integer prior to >>15. +*/ +#define DITHER_BITS (15) +#define DITHER_SCALE (1.0f / ((1<>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS)); + /* High pass filter to reduce audibility. */ + highPass = current - previous; + previous = current; + return highPass; +} + +// TO BE COMPLETED WITH ALL SUPPORTED PA SAMPLE TYPES + +//------------------------------------------------------------------------------------------------------------------------------------------------------- + void Input_Int16_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +{ + long temp; + int i,j; + + for( j=0; j>16; + userBufPtr += NumInputChannels; + } + } + } + else + { + for( j=0; j> 1) + Pa_TriangularDither(); + temp = temp >> 15; + temp = (short) ClipShort(temp); + *userBufPtr = temp; + userBufPtr += NumInputChannels; + } + } + + } +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------- +// MUST BE TESTED + void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) +{ + long temp; + int i,j; + + if( flags & paDitherOff ) + { + for( j=0; j>8); + userBufPtr += NumInputChannels; + } + } + } + else + { + for( j=0; j> 8; + temp = ClipShort(temp); + *userBufPtr = (char)(temp>>8); + userBufPtr += NumInputChannels; + } + } + } +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------- + void Input_Int32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset, uint32 flags,bool swap) +{ + long temp; + int i,j; + + if( flags & paDitherOff ) + { + for( j=0; j>24); + userBufPtr += NumInputChannels; + } + } + } + else + { + for( j=0; j>16; // Shift to get a 16 bit value, then use the 16 bits to 8 bits code (MUST BE CHECHED) + temp += Pa_TriangularDither() >> 8; + temp = ClipShort(temp); + *userBufPtr = (char)(temp >> 8); + userBufPtr += NumInputChannels; + } + } + } +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------- +// MUST BE TESTED + + void Input_Float32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap) +{ + long temp; + int i,j; + + if( flags & paDitherOff ) + { + for( j=0; j>8) + 0x80); + userBufPtr += NumInputChannels; + } + } + } + else + { + for( j=0; j> 8; + temp = ClipShort(temp); + *userBufPtr = (unsigned char)((temp>>8) + 0x80); + userBufPtr += NumInputChannels; + } + } + } +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------- + void Input_Int32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap) +{ + long temp; + int i,j; + + if( flags & paDitherOff ) + { + for( j=0; j>24) + 0x80); + userBufPtr += NumInputChannels; + } + } + } + else + { + for( j=0; j>16; // Shift to get a 16 bit value, then use the 16 bits to 8 bits code (MUST BE CHECHED) + temp += Pa_TriangularDither() >> 8; + temp = ClipShort(temp); + *userBufPtr = (unsigned char)((temp>>8) + 0x80); + userBufPtr += NumInputChannels; + } + } + } +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------- +// MUST BE TESTED + + void Input_Float32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap) +{ + long temp; + int i,j; + + if( flags & paDitherOff ) + { + for( j=0; j> 16); + if (swap) temp = SwapShort(temp); + asioBufPtr[i] = temp; + userBufPtr += NumOuputChannels; + } + } + } + else + { + for (j= 0; j < NumOuputChannels; j++) + { + short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset]; + long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)]; + for( i=0; i> 1) + Pa_TriangularDither(); + temp = temp >> 15; + temp = (short) ClipShort(temp); + if (swap) temp = SwapShort(temp); + asioBufPtr[i] = temp; + userBufPtr += NumOuputChannels; + } + } + } +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------- + void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) +{ + long temp; + int i,j; + + for (j= 0; j < NumOuputChannels; j++) + { + long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset]; + long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)]; + for( i=0; ipast_FramesPerUserBuffer <= asioDriverInfo.past_FramesPerHostBuffer) { + asioDriverInfo.pahsc_hostOutputBufferFrameOffset = asioDriverInfo.pahsc_OutputBufferOffset; + asioDriverInfo.pahsc_userInputBufferFrameOffset = 0; // empty + asioDriverInfo.pahsc_userOutputBufferFrameOffset = asioDriverInfo.past->past_FramesPerUserBuffer; // empty + }else { + asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0; // empty + asioDriverInfo.pahsc_userInputBufferFrameOffset = asioDriverInfo.pahsc_InputBufferOffset; + asioDriverInfo.pahsc_userOutputBufferFrameOffset = asioDriverInfo.past->past_FramesPerUserBuffer; // empty + } +} + + +//------------------------------------------------------------------------------------------------------------------------------------------------------- +// FIXME : optimization for Input only or output only modes (really necessary ??) +void Pa_ASIO_Callback_Input( long index) +{ + internalPortAudioStream *past = asioDriverInfo.past; + long framesInputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer; // number of frames available into the host input buffer + long framesInputUserBuffer; // number of frames needed to complete the user input buffer + long framesOutputHostBuffer; // number of frames needed to complete the host output buffer + long framesOuputUserBuffer; // number of frames available into the user output buffer + long userResult; + long tmp; + + /* Fill host ASIO output with remaining frames in user output */ + framesOutputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer; + framesOuputUserBuffer = asioDriverInfo.past->past_FramesPerUserBuffer - asioDriverInfo.pahsc_userOutputBufferFrameOffset; + tmp = min(framesOutputHostBuffer, framesOuputUserBuffer); + framesOutputHostBuffer -= tmp; + Pa_ASIO_Callback_Output(index,tmp); + + /* Available frames in hostInputBuffer */ + while (framesInputHostBuffer > 0) { + + /* Number of frames needed to complete an user input buffer */ + framesInputUserBuffer = asioDriverInfo.past->past_FramesPerUserBuffer - asioDriverInfo.pahsc_userInputBufferFrameOffset; + + if (framesInputHostBuffer >= framesInputUserBuffer) { + + /* Convert ASIO input to user input */ + Pa_ASIO_Convert_Inter_Input (asioDriverInfo.bufferInfos, + past->past_InputBuffer, + asioDriverInfo.pahsc_NumInputChannels , + asioDriverInfo.pahsc_NumOutputChannels, + framesInputUserBuffer, + asioDriverInfo.past_FramesPerHostBuffer - framesInputHostBuffer, + asioDriverInfo.pahsc_userInputBufferFrameOffset, + asioDriverInfo.pahsc_channelInfos[0].type, + past->past_InputSampleFormat, + past->past_Flags, + index); + + /* Call PortAudio callback */ + userResult = asioDriverInfo.past->past_Callback(past->past_InputBuffer, past->past_OutputBuffer, + past->past_FramesPerUserBuffer,past->past_FrameCount,past->past_UserData ); + + /* User callback has asked us to stop in the middle of the host buffer */ + if( userResult != 0) { + + /* Put 0 in the end of the output buffer */ + Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos, + asioDriverInfo.pahsc_channelInfos[0].type, + asioDriverInfo.pahsc_NumInputChannels , + asioDriverInfo.pahsc_NumOutputChannels, + index, + asioDriverInfo.pahsc_hostOutputBufferFrameOffset, + asioDriverInfo.past_FramesPerHostBuffer - asioDriverInfo.pahsc_hostOutputBufferFrameOffset); + + past->past_StopSoon = 1; + return; + } + + + /* Full user ouput buffer : write offset */ + asioDriverInfo.pahsc_userOutputBufferFrameOffset = 0; + + /* Empty user input buffer : read offset */ + asioDriverInfo.pahsc_userInputBufferFrameOffset = 0; + + /* Fill host ASIO output */ + tmp = min (past->past_FramesPerUserBuffer,framesOutputHostBuffer); + Pa_ASIO_Callback_Output(index,tmp); + + framesOutputHostBuffer -= tmp; + framesInputHostBuffer -= framesInputUserBuffer; + + }else { + + /* Convert ASIO input to user input */ + Pa_ASIO_Convert_Inter_Input (asioDriverInfo.bufferInfos, + past->past_InputBuffer, + asioDriverInfo.pahsc_NumInputChannels , + asioDriverInfo.pahsc_NumOutputChannels, + framesInputHostBuffer, + asioDriverInfo.past_FramesPerHostBuffer - framesInputHostBuffer, + asioDriverInfo.pahsc_userInputBufferFrameOffset, + asioDriverInfo.pahsc_channelInfos[0].type, + past->past_InputSampleFormat, + past->past_Flags, + index); + + /* Update pahsc_userInputBufferFrameOffset */ + asioDriverInfo.pahsc_userInputBufferFrameOffset += framesInputHostBuffer; + + /* Update framesInputHostBuffer */ + framesInputHostBuffer = 0; + } + } + +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------- +void Pa_ASIO_Callback_Output(long index, long framePerBuffer) +{ + internalPortAudioStream *past = asioDriverInfo.past; + + if (framePerBuffer > 0) { + + /* Convert user output to ASIO ouput */ + Pa_ASIO_Convert_Inter_Output (asioDriverInfo.bufferInfos, + past->past_OutputBuffer, + asioDriverInfo.pahsc_NumInputChannels, + asioDriverInfo.pahsc_NumOutputChannels, + framePerBuffer, + asioDriverInfo.pahsc_hostOutputBufferFrameOffset, + asioDriverInfo.pahsc_userOutputBufferFrameOffset, + asioDriverInfo.pahsc_channelInfos[0].type, + past->past_InputSampleFormat, + past->past_Flags, + index); + + /* Update hostOuputFrameOffset */ + asioDriverInfo.pahsc_hostOutputBufferFrameOffset += framePerBuffer; + + /* Update userOutputFrameOffset */ + asioDriverInfo.pahsc_userOutputBufferFrameOffset += framePerBuffer; + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------- + void Pa_ASIO_Callback_End() + { + /* Empty ASIO ouput : write offset */ + asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0; + } + +//------------------------------------------------------------------------------------------------------------------------------------------------------- +void Pa_ASIO_Clear_User_Buffers() +{ + if( asioDriverInfo.past->past_InputBuffer != NULL ) + { + memset( asioDriverInfo.past->past_InputBuffer, 0, asioDriverInfo.past->past_InputBufferSize ); + } + if( asioDriverInfo.past->past_OutputBuffer != NULL ) + { + memset( asioDriverInfo.past->past_OutputBuffer, 0, asioDriverInfo.past->past_OutputBufferSize ); + } +} + +//------------------------------------------------------------------------------------------------------------------------------------------------------- + void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, + ASIOSampleType nativeFormat, + short NumInputChannels, + short NumOuputChannels, + int index, + int hostFrameOffset, + int frames) +{ + + switch (nativeFormat) { + + case ASIOSTInt16MSB: + case ASIOSTInt16LSB: + case ASIOSTInt32MSB16: + case ASIOSTInt32LSB16: + Pa_ASIO_Clear_Output_16(nativeBuffer, frames, NumInputChannels, NumOuputChannels, index, hostFrameOffset); + break; + + case ASIOSTFloat64MSB: + case ASIOSTFloat64LSB: + break; + + case ASIOSTFloat32MSB: + case ASIOSTFloat32LSB: + case ASIOSTInt32MSB: + case ASIOSTInt32LSB: + case ASIOSTInt32MSB18: + case ASIOSTInt32MSB20: + case ASIOSTInt32MSB24: + case ASIOSTInt32LSB18: + case ASIOSTInt32LSB20: + case ASIOSTInt32LSB24: + Pa_ASIO_Clear_Output_32(nativeBuffer, frames, NumInputChannels, NumOuputChannels, index, hostFrameOffset); + break; + + case ASIOSTInt24MSB: + case ASIOSTInt24LSB: + break; + + default: + break; + } +} + + +//--------------------------------------------------------------------------------------- +void Pa_ASIO_Convert_Inter_Input( + ASIOBufferInfo* nativeBuffer, + void* inputBuffer, + short NumInputChannels, + short NumOuputChannels, + short framePerBuffer, + short hostFrameOffset, + short userFrameOffset, + ASIOSampleType nativeFormat, + PaSampleFormat paFormat, + PaStreamFlags flags, + short index) +{ + + if((NumInputChannels > 0) && (nativeBuffer != NULL)) + { + /* Convert from native format to PA format. */ + switch(paFormat) + { + case paFloat32: + { + float *inBufPtr = (float *) inputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Input_Int16_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap); + break; + case ASIOSTInt16MSB: + Input_Int16_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + break; + case ASIOSTInt32LSB: + Input_Int32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); + break; + case ASIOSTInt32MSB: + Input_Int32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + break; + case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); + break; + case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + } + + break; + } + + case paInt32: + { + long *inBufPtr = (long *)inputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Input_Int16_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt16MSB: + Input_Int16_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTInt32LSB: + Input_Int32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt32MSB: + Input_Int32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + + } + break; + } + + case paInt16: + { + short *inBufPtr = (short *) inputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Input_Int16_Int16(nativeBuffer, inBufPtr, framePerBuffer , NumInputChannels, index , hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt16MSB: + Input_Int16_Int16(nativeBuffer, inBufPtr, framePerBuffer , NumInputChannels, index , hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTInt32LSB: + Input_Int32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); + break; + case ASIOSTInt32MSB: + Input_Int32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); + break; + case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + + } + break; + } + + case paInt8: + { + /* Convert 16 bit data to 8 bit chars */ + + char *inBufPtr = (char *) inputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Input_Int16_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap); + break; + case ASIOSTInt16MSB: + Input_Int16_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + case ASIOSTInt32LSB: + Input_Int32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); + break; + case ASIOSTInt32MSB: + Input_Int32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); + break; + case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + } + break; + } + + case paUInt8: + { + /* Convert 16 bit data to 8 bit unsigned chars */ + + unsigned char *inBufPtr = (unsigned char *)inputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Input_Int16_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); + break; + case ASIOSTInt16MSB: + Input_Int16_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + case ASIOSTInt32LSB: + Input_Int32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap); + break; + case ASIOSTInt32MSB: + Input_Int32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap); + break; + case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + Input_Float32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,!swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + + } + break; + } + + default: + break; + } + } +} + + +//--------------------------------------------------------------------------------------- +void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer, + void* outputBuffer, + short NumInputChannels, + short NumOuputChannels, + short framePerBuffer, + short hostFrameOffset, + short userFrameOffset, + ASIOSampleType nativeFormat, + PaSampleFormat paFormat, + PaStreamFlags flags, + short index) +{ + + if((NumOuputChannels > 0) && (nativeBuffer != NULL)) + { + /* Convert from PA format to native format */ + + switch(paFormat) + { + case paFloat32: + { + float *outBufPtr = (float *) outputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Output_Float32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags, swap); + break; + case ASIOSTInt16MSB: + Output_Float32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags,!swap); + break; + case ASIOSTInt32LSB: + Output_Float32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags,swap); + break; + case ASIOSTInt32MSB: + Output_Float32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + case ASIOSTFloat32LSB: + Output_Float32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset,flags,swap); + break; + case ASIOSTFloat32MSB: + Output_Float32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + } + break; + } + + case paInt32: + { + long *outBufPtr = (long *) outputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Output_Int32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); + break; + case ASIOSTInt16MSB: + Output_Int32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + case ASIOSTInt32LSB: + Output_Int32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); + break; + case ASIOSTInt32MSB: + Output_Int32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + case ASIOSTFloat32LSB: + Output_Int32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); + break; + case ASIOSTFloat32MSB: + Output_Int32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + } + break; + } + + case paInt16: + { + short *outBufPtr = (short *) outputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Output_Int16_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt16MSB: + Output_Int16_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTInt32LSB: + Output_Int16_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt32MSB: + Output_Int16_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTFloat32LSB: + Output_Int16_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTFloat32MSB: + Output_Int16_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + + } + break; + } + + + case paInt8: + { + char *outBufPtr = (char *) outputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Output_Int8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt16MSB: + Output_Int8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTInt32LSB: + Output_Int8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt32MSB: + Output_Int8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTFloat32LSB: + Output_Int8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTFloat32MSB: + Output_Int8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + } + break; + } + + case paUInt8: + { + unsigned char *outBufPtr = (unsigned char *) outputBuffer; + + switch (nativeFormat) { + case ASIOSTInt16LSB: + Output_IntU8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt16MSB: + Output_IntU8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTInt32LSB: + Output_IntU8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTInt32MSB: + Output_IntU8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + case ASIOSTFloat32LSB: + Output_IntU8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); + break; + case ASIOSTFloat32MSB: + Output_IntU8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); + break; + + case ASIOSTInt24LSB: // used for 20 bits as well + case ASIOSTInt24MSB: // used for 20 bits as well + + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can more easily used with these + + case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment + + + case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment + case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment + case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment + case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment + DBUG(("Not yet implemented : please report the problem\n")); + break; + } + break; + } + + default: + break; + } + } + +} + + + +/* Load a ASIO driver corresponding to the required device */ +static PaError Pa_ASIO_loadDevice (long device) +{ + PaDeviceInfo * dev = &(sDevices[device].pad_Info); + + if (!loadAsioDriver((char *) dev->name)) return paHostError; + if (ASIOInit(&asioDriverInfo.pahsc_driverInfo) != ASE_OK) return paHostError; + if (ASIOGetChannels(&asioDriverInfo.pahsc_NumInputChannels, &asioDriverInfo.pahsc_NumOutputChannels) != ASE_OK) return paHostError; + if (ASIOGetBufferSize(&asioDriverInfo.pahsc_minSize, &asioDriverInfo.pahsc_maxSize, &asioDriverInfo.pahsc_preferredSize, &asioDriverInfo.pahsc_granularity) != ASE_OK) return paHostError; + + if(ASIOOutputReady() == ASE_OK) + asioDriverInfo.pahsc_postOutput = true; + else + asioDriverInfo.pahsc_postOutput = false; + + return paNoError; +} + +//--------------------------------------------------- +static int GetHighestBitPosition( unsigned long n ) +{ + int pos = -1; + while( n != 0 ) + { + pos++; + n = n >> 1; + } + return pos; +} + +//----------------------------------------------------------------------------- +static int GetFirstMultiple(long min, long val ){ return ((min + val - 1) / val) * val; } + +//----------------------------------------------------------------------------- +static int GetFirstPossibleDivisor(long max, long val ) +{ + for (int i = 2; i < 20; i++) {if (((val%i) == 0) && ((val/i) <= max)) return (val/i); } + return val; +} + +//------------------------------------------------------------------------ +static int IsPowerOfTwo( unsigned long n ) { return ((n & (n-1)) == 0); } + + +/******************************************************************* +* Determine size of native ASIO audio buffer size +* Input parameters : FramesPerUserBuffer, NumUserBuffers +* Output values : FramesPerHostBuffer, OutputBufferOffset or InputtBufferOffset +*/ + +static PaError PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + long requestedBufferSize; + long firstMultiple, firstDivisor; + + // Compute requestedBufferSize + if( past->past_NumUserBuffers < 1 ){ + requestedBufferSize = past->past_FramesPerUserBuffer; + }else{ + requestedBufferSize = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; + } + + // Adjust FramesPerHostBuffer using requestedBufferSize, ASIO minSize and maxSize, + if (requestedBufferSize < asioDriverInfo.pahsc_minSize){ + + firstMultiple = GetFirstMultiple(asioDriverInfo.pahsc_minSize, requestedBufferSize); + + if (firstMultiple <= asioDriverInfo.pahsc_maxSize) + asioDriverInfo.past_FramesPerHostBuffer = firstMultiple; + else + asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_minSize; + + }else if (requestedBufferSize > asioDriverInfo.pahsc_maxSize){ + + firstDivisor = GetFirstPossibleDivisor(asioDriverInfo.pahsc_maxSize, requestedBufferSize); + + if ((firstDivisor >= asioDriverInfo.pahsc_minSize) && (firstDivisor <= asioDriverInfo.pahsc_maxSize)) + asioDriverInfo.past_FramesPerHostBuffer = firstDivisor; + else + asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_maxSize; + }else{ + asioDriverInfo.past_FramesPerHostBuffer = requestedBufferSize; + } + + // If ASIO buffer size needs to be a power of two + if( asioDriverInfo.pahsc_granularity < 0 ){ + // Needs to be a power of two. + + if( !IsPowerOfTwo( asioDriverInfo.past_FramesPerHostBuffer ) ) + { + int highestBit = GetHighestBitPosition(asioDriverInfo.past_FramesPerHostBuffer); + asioDriverInfo.past_FramesPerHostBuffer = 1 << (highestBit + 1); + } + } + + DBUG(("----------------------------------\n")); + DBUG(("PortAudio : minSize = %ld \n",asioDriverInfo.pahsc_minSize)); + DBUG(("PortAudio : preferredSize = %ld \n",asioDriverInfo.pahsc_preferredSize)); + DBUG(("PortAudio : maxSize = %ld \n",asioDriverInfo.pahsc_maxSize)); + DBUG(("PortAudio : granularity = %ld \n",asioDriverInfo.pahsc_granularity)); + DBUG(("PortAudio : User buffer size = %d\n", asioDriverInfo.past->past_FramesPerUserBuffer )); + DBUG(("PortAudio : ASIO buffer size = %d\n", asioDriverInfo.past_FramesPerHostBuffer )); + + if (asioDriverInfo.past_FramesPerHostBuffer > past->past_FramesPerUserBuffer){ + + // Computes the MINIMUM value of null frames shift for the output buffer alignement + asioDriverInfo.pahsc_OutputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer); + asioDriverInfo.pahsc_InputBufferOffset = 0; + DBUG(("PortAudio : Minimum BufferOffset for Output = %d\n", asioDriverInfo.pahsc_OutputBufferOffset)); + }else{ + + //Computes the MINIMUM value of null frames shift for the input buffer alignement + asioDriverInfo.pahsc_InputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer); + asioDriverInfo.pahsc_OutputBufferOffset = 0; + DBUG(("PortAudio : Minimum BufferOffset for Input = %d\n", asioDriverInfo.pahsc_InputBufferOffset)); + } + + return paNoError; +} + + +/***********************************************************************/ +int Pa_CountDevices() +{ + PaError err ; + + if( sNumDevices <= 0 ) + { + /* Force loading of ASIO drivers */ + err = Pa_ASIO_QueryDeviceInfo(sDevices); + if( err != paNoError ) goto error; + } + + return sNumDevices; + +error: + PaHost_Term(); + DBUG(("Pa_CountDevices: returns %d\n", err )); + return err; +} + +/***********************************************************************/ +PaError PaHost_Init( void ) +{ + /* Have we already initialized the device info? */ + return (Pa_CountDevices() < 0 ) ? paHostError : paNoError; +} + +/***********************************************************************/ +PaError PaHost_Term( void ) +{ + int i; + PaDeviceInfo *dev; + double *rates; + PaError result = paNoError; + + /* Free allocated sample rate arrays and names*/ + for( i=0; isampleRates; + if((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double)); + dev->sampleRates = NULL; + if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32); + dev->name = NULL; + } + + sNumDevices = 0; + + /* Dispose : if not done by Pa_CloseStream */ + if(ASIODisposeBuffers() != ASE_OK) result = paHostError; + if(ASIOExit() != ASE_OK) result = paHostError; + + /* remove the loaded ASIO driver */ + asioDrivers->removeCurrentDriver(); + + return result; +} + +/***********************************************************************/ +PaError PaHost_OpenStream( internalPortAudioStream *past ) +{ + PaError result = paNoError; + ASIOError err; + int32 device; + + /* TO DO : Check if a stream already runs */ + //if (asioDriverInfo.past != NULL) return paHostError; (does not work) + + /* Check the device number */ + if ((past->past_InputDeviceID != paNoDevice) + &&(past->past_OutputDeviceID != paNoDevice) + &&(past->past_InputDeviceID != past->past_OutputDeviceID)) + { + return paInvalidDeviceId; + } + + /* Allocation */ + memset(&asioDriverInfo, 0, sizeof(PaHostSoundControl)); + past->past_DeviceData = (void*) &asioDriverInfo; + + + /* FIXME */ + asioDriverInfo.past = past; + + /* load the ASIO device */ + device = (past->past_InputDeviceID < 0) ? past->past_OutputDeviceID : past->past_InputDeviceID; + result = Pa_ASIO_loadDevice(device); + if (result != paNoError) goto error; + + /* Check ASIO parameters and input parameters */ + if ((past->past_NumInputChannels > asioDriverInfo.pahsc_NumInputChannels) + || (past->past_NumOutputChannels > asioDriverInfo.pahsc_NumOutputChannels)) { + result = paInvalidChannelCount; + goto error; + } + + /* Set sample rate */ + if (ASIOSetSampleRate(past->past_SampleRate) != ASE_OK) { + result = paInvalidSampleRate; + goto error; + } + + /* if OK calc buffer size */ + result = PaHost_CalcNumHostBuffers( past ); + if (result != paNoError) goto error; + + + /* + Allocating input and output buffers number for the real past_NumInputChannels and past_NumOutputChannels + optimize the data transfer. + */ + + asioDriverInfo.pahsc_NumInputChannels = past->past_NumInputChannels; + asioDriverInfo.pahsc_NumOutputChannels = past->past_NumOutputChannels; + + /* Allocate ASIO buffers and callback*/ + err = Pa_ASIO_CreateBuffers(&asioDriverInfo, + asioDriverInfo.pahsc_NumInputChannels, + asioDriverInfo.pahsc_NumOutputChannels, + asioDriverInfo.past_FramesPerHostBuffer); + + if (err == ASE_OK) + return paNoError; + else if (err == ASE_NoMemory) + result = paInsufficientMemory; + else if (err == ASE_InvalidParameter) + result = paInvalidChannelCount; + else if (err == ASE_InvalidMode) + result = paBufferTooBig; + else + result = paHostError; + +error: + ASIOExit(); + return result; + +} + +/***********************************************************************/ +PaError PaHost_CloseStream( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc; + PaError result = paNoError; + + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + + #if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); + #endif + + /* Dispose */ + if(ASIODisposeBuffers() != ASE_OK) result = paHostError; + if(ASIOExit() != ASE_OK) result = paHostError; + + /* Free data and device for output. */ + past->past_DeviceData = NULL; + asioDriverInfo.past = NULL; + + return result; +} + +/***********************************************************************/ +PaError PaHost_StartOutput( internalPortAudioStream *past ) +{ + /* Clear the index 0 host output buffer */ + Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos, + asioDriverInfo.pahsc_channelInfos[0].type, + asioDriverInfo.pahsc_NumInputChannels, + asioDriverInfo.pahsc_NumOutputChannels, + 0, + 0, + asioDriverInfo.past_FramesPerHostBuffer); + + /* Clear the index 1 host output buffer */ + Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos, + asioDriverInfo.pahsc_channelInfos[0].type, + asioDriverInfo.pahsc_NumInputChannels, + asioDriverInfo.pahsc_NumOutputChannels, + 1, + 0, + asioDriverInfo.past_FramesPerHostBuffer); + + Pa_ASIO_Clear_User_Buffers(); + + Pa_ASIO_Adaptor_Init(); + + return paNoError; +} + +/***********************************************************************/ +PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) +{ + /* Nothing to do ?? */ + return paNoError; +} + +/***********************************************************************/ +PaError PaHost_StartInput( internalPortAudioStream *past ) +{ + /* Nothing to do ?? */ + return paNoError; +} + +/***********************************************************************/ +PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) +{ + /* Nothing to do */ + return paNoError; +} + +/***********************************************************************/ +PaError PaHost_StartEngine( internalPortAudioStream *past ) +{ + // TO DO : count of samples + past->past_IsActive = 1; + return (ASIOStart() == ASE_OK) ? paNoError : paHostError; +} + +/***********************************************************************/ +PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) +{ + // TO DO : count of samples + past->past_IsActive = 0; + return (ASIOStop() == ASE_OK) ? paNoError : paHostError; +} + +/***********************************************************************/ +// TO BE CHECKED +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; +} + +/*************************************************************************/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + PaHostSoundControl *pahsc; + internalPortAudioStream *past = (internalPortAudioStream *) stream; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + return pahsc->pahsc_NumFramesDone; +} + +/************************************************************************* + * 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 ) +{ + #if MAC + void *addr = NewPtrClear( numBytes ); + if( (addr == NULL) || (MemError () != 0) ) return NULL; + + #if (CARBON_COMPATIBLE == 0) + if( HoldMemory( addr, numBytes ) != noErr ) + { + DisposePtr( (Ptr) addr ); + return NULL; + } + #endif + return addr; + #elif WINDOWS + void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */ + if( addr != NULL ) memset( addr, 0, numBytes ); + return addr; + #endif +} + +/************************************************************************* + * 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 ) +{ + #if MAC + if( addr == NULL ) return; + #if CARBON_COMPATIBLE + (void) numBytes; + #else + UnholdMemory( addr, numBytes ); + #endif + DisposePtr( (Ptr) addr ); + #elif WINDOWS + if( addr != NULL ) free( addr ); + #endif +} + + +/*************************************************************************/ +void Pa_Sleep( long msec ) +{ + #if MAC + int32 sleepTime, endTime; + /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */ + sleepTime = ((msec * 60) + 999) / 1000; + if( sleepTime < 1 ) sleepTime = 1; + endTime = TickCount() + sleepTime; + do{ + DBUGX(("Sleep for %d ticks.\n", sleepTime )); + WaitNextEvent( 0, NULL, sleepTime, NULL ); /* Use this just to sleep without getting events. */ + sleepTime = endTime - TickCount(); + } while( sleepTime > 0 ); + #elif WINDOWS + Sleep( msec ); + #endif +} + +/*************************************************************************/ +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) +{ + if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; + return &sDevices[id].pad_Info; +} + +/*************************************************************************/ +PaDeviceID Pa_GetDefaultInputDeviceID( void ) +{ + return sDefaultInputDeviceID; +} + +/*************************************************************************/ +PaDeviceID Pa_GetDefaultOutputDeviceID( void ) +{ + return sDefaultOutputDeviceID; +} + +/*************************************************************************/ +int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) +{ + // TO BE IMPLEMENTED : using the ASIOGetLatency call?? + return 2; +} + +/*************************************************************************/ +int32 Pa_GetHostError( void ) +{ + int32 err = sPaHostError; + sPaHostError = 0; + return err; +} + + +#ifdef MAC + +/**************************************************************************/ +static void Pa_StartUsageCalculation( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + UnsignedWide widePad; + if( pahsc == NULL ) return; +/* Query system timer for usage analysis and to prevent overuse of CPU. */ + Microseconds( &widePad ); + pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad ); +} +/**************************************************************************/ +static void Pa_EndUsageCalculation( internalPortAudioStream *past ) +{ + UnsignedWide widePad; + UInt64 CurrentCount; + long InsideCount; + long TotalCount; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; +/* Measure CPU utilization during this callback. Note that this calculation +** assumes that we had the processor the whole time. +*/ +#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) + Microseconds( &widePad ); + CurrentCount = UnsignedWideToUInt64( widePad ); + if( past->past_IfLastExitValid ) + { + InsideCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_EntryCount); + TotalCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_LastExitCount); +/* Low pass filter the result because sometimes we get called several times in a row. +* That can cause the TotalCount to be very low which can cause the usage to appear +* unnaturally high. So we must filter numerator and denominator separately!!! +*/ + past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * InsideCount)); + past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * TotalCount)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + } + pahsc->pahsc_LastExitCount = CurrentCount; + past->past_IfLastExitValid = 1; +} + +#elif WINDOWS + +/********************************* 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. */ + QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); +} + +static void Pa_EndUsageCalculation( internalPortAudioStream *past ) +{ + LARGE_INTEGER CurrentCount = { 0, 0 }; + LONGLONG InsideCount; + LONGLONG TotalCount; +/* +** Measure CPU utilization during this callback. Note that this calculation +** assumes that we had the processor the whole time. +*/ +#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) + + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + + if( QueryPerformanceCounter( &CurrentCount ) ) + { + if( past->past_IfLastExitValid ) + { + InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; + TotalCount = CurrentCount.QuadPart - pahsc->pahsc_LastExitCount.QuadPart; +/* Low pass filter the result because sometimes we get called several times in a row. + * That can cause the TotalCount to be very low which can cause the usage to appear + * unnaturally high. So we must filter numerator and denominator separately!!! + */ + past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * InsideCount)); + past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * TotalCount)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + } + pahsc->pahsc_LastExitCount = CurrentCount; + past->past_IfLastExitValid = 1; + } +} + +#endif + + + + diff --git a/pa_beos/PlaybackNode.cc b/pa_beos/PlaybackNode.cc new file mode 100644 index 0000000..84d5453 --- /dev/null +++ b/pa_beos/PlaybackNode.cc @@ -0,0 +1,538 @@ +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * BeOS Media Kit Implementation by Joshua Haberman + * + * Copyright (c) 2001 Joshua Haberman + * + * 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. + * + * --- + * + * Significant portions of this file are based on sample code from Be. The + * Be Sample Code Licence follows: + * + * Copyright 1991-1999, Be Incorporated. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions, and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "PlaybackNode.h" + +#define PRINT(x) { printf x; fflush(stdout); } + +#ifdef DEBUG +#define DBUG(x) PRINT(x) +#else +#define DBUG(x) +#endif + + +PaPlaybackNode::PaPlaybackNode(uint32 channels, float frame_rate, uint32 frames_per_buffer, + PortAudioCallback* callback, void *user_data) : + BMediaNode("PortAudio input node"), + BBufferProducer(B_MEDIA_RAW_AUDIO), + BMediaEventLooper(), + mAborted(false), + mRunning(false), + mBufferGroup(NULL), + mDownstreamLatency(0), + mStartTime(0), + mCallback(callback), + mUserData(user_data), + mFramesPerBuffer(frames_per_buffer) +{ + DBUG(("Constructor called.\n")); + + mPreferredFormat.type = B_MEDIA_RAW_AUDIO; + mPreferredFormat.u.raw_audio.channel_count = channels; + mPreferredFormat.u.raw_audio.frame_rate = frame_rate; + mPreferredFormat.u.raw_audio.byte_order = + (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; + mPreferredFormat.u.raw_audio.buffer_size = + media_raw_audio_format::wildcard.buffer_size; + + mOutput.destination = media_destination::null; + mOutput.format = mPreferredFormat; + + /* The amount of time it takes for this node to produce a buffer when + * asked. Essentially, it is how long the user's callback takes to run. + * We set this to be the length of the sound data each buffer of the + * requested size can hold. */ + //mInternalLatency = (bigtime_t)(1000000 * frames_per_buffer / frame_rate); + + /* ACK! it seems that the mixer (at least on my machine) demands that IT + * specify the buffer size, so for now I'll just make a generic guess here */ + mInternalLatency = 1000000 / 20; +} + + + +PaPlaybackNode::~PaPlaybackNode() +{ + DBUG(("Destructor called.\n")); + Quit(); /* Stop the BMediaEventLooper thread */ +} + + +/************************* + * + * Local methods + * + */ + +bool PaPlaybackNode::IsRunning() +{ + return mRunning; +} + + +PaTimestamp PaPlaybackNode::GetStreamTime() +{ + BTimeSource *timeSource = TimeSource(); + PaTimestamp time = (timeSource->Now() - mStartTime) * + mPreferredFormat.u.raw_audio.frame_rate / 1000000; + return time; +} + + +void PaPlaybackNode::SetSampleFormat(PaSampleFormat inFormat, + PaSampleFormat outFormat) +{ + uint32 beOutFormat; + + switch(outFormat) + { + case paFloat32: + beOutFormat = media_raw_audio_format::B_AUDIO_FLOAT; + mOutputSampleWidth = 4; + break; + + case paInt16: + beOutFormat = media_raw_audio_format::B_AUDIO_SHORT; + mOutputSampleWidth = 2; + break; + + case paInt32: + beOutFormat = media_raw_audio_format::B_AUDIO_INT; + mOutputSampleWidth = 4; + break; + + case paInt8: + beOutFormat = media_raw_audio_format::B_AUDIO_CHAR; + mOutputSampleWidth = 1; + break; + + case paUInt8: + beOutFormat = media_raw_audio_format::B_AUDIO_UCHAR; + mOutputSampleWidth = 1; + break; + + case paInt24: + case paPackedInt24: + case paCustomFormat: + DBUG(("Unsupported output format: %x\n", outFormat)); + break; + + default: + DBUG(("Unknown output format: %x\n", outFormat)); + } + + mPreferredFormat.u.raw_audio.format = beOutFormat; + mFramesPerBuffer * mPreferredFormat.u.raw_audio.channel_count * mOutputSampleWidth; +} + +BBuffer *PaPlaybackNode::FillNextBuffer(bigtime_t time) +{ + /* Get a buffer from the buffer group */ + BBuffer *buf = mBufferGroup->RequestBuffer( + mOutput.format.u.raw_audio.buffer_size, BufferDuration()); + unsigned long frames = mOutput.format.u.raw_audio.buffer_size / + mOutputSampleWidth / mOutput.format.u.raw_audio.channel_count; + bigtime_t start_time; + int ret; + + if( !buf ) + { + DBUG(("Unable to allocate a buffer\n")); + return NULL; + } + + start_time = mStartTime + + (bigtime_t)((double)mSamplesSent / + (double)mOutput.format.u.raw_audio.frame_rate / + (double)mOutput.format.u.raw_audio.channel_count * + 1000000.0); + + /* Now call the user callback to get the data */ + ret = mCallback(NULL, /* Input buffer */ + buf->Data(), /* Output buffer */ + frames, /* Frames per buffer */ + mSamplesSent / mOutput.format.u.raw_audio.channel_count, /* timestamp */ + mUserData); + + if( ret ) + mAborted = true; + + media_header *hdr = buf->Header(); + + hdr->type = B_MEDIA_RAW_AUDIO; + hdr->size_used = mOutput.format.u.raw_audio.buffer_size; + hdr->time_source = TimeSource()->ID(); + hdr->start_time = start_time; + + return buf; +} + + + + +/************************* + * + * BMediaNode methods + * + */ + +BMediaAddOn *PaPlaybackNode::AddOn( int32 * ) const +{ + DBUG(("AddOn() called.\n")); + return NULL; /* we don't provide service to outside applications */ +} + + +status_t PaPlaybackNode::HandleMessage( int32 message, const void *data, + size_t size ) +{ + DBUG(("HandleMessage() called.\n")); + return B_ERROR; /* we don't define any custom messages */ +} + + + + +/************************* + * + * BMediaEventLooper methods + * + */ + +void PaPlaybackNode::NodeRegistered() +{ + DBUG(("NodeRegistered() called.\n")); + + /* Start the BMediaEventLooper thread */ + SetPriority(B_REAL_TIME_PRIORITY); + Run(); + + /* set up as much information about our output as we can */ + mOutput.source.port = ControlPort(); + mOutput.source.id = 0; + mOutput.node = Node(); + ::strcpy(mOutput.name, "PortAudio Playback"); +} + + +void PaPlaybackNode::HandleEvent( const media_timed_event *event, + bigtime_t lateness, bool realTimeEvent ) +{ + // DBUG(("HandleEvent() called.\n")); + status_t err; + + switch(event->type) + { + case BTimedEventQueue::B_START: + DBUG((" Handling a B_START event\n")); + if( RunState() != B_STARTED ) + { + mStartTime = event->event_time + EventLatency(); + mSamplesSent = 0; + mAborted = false; + mRunning = true; + media_timed_event firstEvent( mStartTime, + BTimedEventQueue::B_HANDLE_BUFFER ); + EventQueue()->AddEvent( firstEvent ); + } + break; + + case BTimedEventQueue::B_STOP: + DBUG((" Handling a B_STOP event\n")); + mRunning = false; + EventQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, + BTimedEventQueue::B_HANDLE_BUFFER ); + break; + + case BTimedEventQueue::B_HANDLE_BUFFER: + //DBUG((" Handling a B_HANDLE_BUFFER event\n")); + + /* make sure we're started and connected */ + if( RunState() != BMediaEventLooper::B_STARTED || + mOutput.destination == media_destination::null ) + break; + + BBuffer *buffer = FillNextBuffer(event->event_time); + + /* make sure we weren't aborted while this routine was running. + * this can happen in one of two ways: either the callback returned + * nonzero (in which case mAborted is set in FillNextBuffer() ) or + * the client called AbortStream */ + if( mAborted ) + { + if( buffer ) + buffer->Recycle(); + Stop(0, true); + break; + } + + if( buffer ) + { + err = SendBuffer(buffer, mOutput.destination); + if( err != B_OK ) + buffer->Recycle(); + } + + mSamplesSent += mOutput.format.u.raw_audio.buffer_size / mOutputSampleWidth; + + /* Now schedule the next buffer event, so we can send another + * buffer when this one runs out. We calculate when it should + * happen by calculating when the data we just sent will finish + * playing. + * + * NOTE, however, that the event will actually get generated + * earlier than we specify, to account for the latency it will + * take to produce the buffer. It uses the latency value we + * specified in SetEventLatency() to determine just how early + * to generate it. */ + + /* totalPerformanceTime includes the time represented by the buffer + * we just sent */ + bigtime_t totalPerformanceTime = (bigtime_t)((double)mSamplesSent / + (double)mOutput.format.u.raw_audio.channel_count / + (double)mOutput.format.u.raw_audio.frame_rate * 1000000.0); + + bigtime_t nextEventTime = mStartTime + totalPerformanceTime; + + media_timed_event nextBufferEvent(nextEventTime, + BTimedEventQueue::B_HANDLE_BUFFER); + EventQueue()->AddEvent(nextBufferEvent); + + break; + + } +} + + + + +/************************* + * + * BBufferProducer methods + * + */ + +status_t PaPlaybackNode::FormatSuggestionRequested( media_type type, + int32 /*quality*/, media_format* format ) +{ + /* the caller wants to know this node's preferred format and provides + * a suggestion, asking if we support it */ + DBUG(("FormatSuggestionRequested() called.\n")); + + if(!format) + return B_BAD_VALUE; + + *format = mPreferredFormat; + + /* we only support raw audio (a wildcard is okay too) */ + if ( type == B_MEDIA_UNKNOWN_TYPE || type == B_MEDIA_RAW_AUDIO ) + return B_OK; + else + return B_MEDIA_BAD_FORMAT; +} + + +status_t PaPlaybackNode::FormatProposal( const media_source& output, + media_format* format ) +{ + /* This is similar to FormatSuggestionRequested(), but it is actually part + * of the negotiation process. We're given the opportunity to specify any + * properties that are wildcards (ie. properties that the other node doesn't + * care one way or another about) */ + DBUG(("FormatProposal() called.\n")); + + /* Make sure this proposal really applies to our output */ + if( output != mOutput.source ) + return B_MEDIA_BAD_SOURCE; + + /* We return two things: whether we support the proposed format, and our own + * preferred format */ + *format = mPreferredFormat; + + if( format->type == B_MEDIA_UNKNOWN_TYPE || format->type == B_MEDIA_RAW_AUDIO ) + return B_OK; + else + return B_MEDIA_BAD_FORMAT; +} + + +status_t PaPlaybackNode::FormatChangeRequested( const media_source& source, + const media_destination& destination, media_format* io_format, int32* ) +{ + /* we refuse to change formats, supporting only 1 */ + DBUG(("FormatChangeRequested() called.\n")); + + return B_ERROR; +} + + +status_t PaPlaybackNode::GetNextOutput( int32* cookie, media_output* out_output ) +{ + /* this is where we allow other to enumerate our outputs -- the cookie is + * an integer we can use to keep track of where we are in enumeration. */ + DBUG(("GetNextOutput() called.\n")); + + if( *cookie == 0 ) + { + *out_output = mOutput; + *cookie = 1; + return B_OK; + } + + return B_BAD_INDEX; +} + + +status_t PaPlaybackNode::DisposeOutputCookie( int32 cookie ) +{ + DBUG(("DisposeOutputCookie() called.\n")); + return B_OK; +} + + +void PaPlaybackNode::LateNoticeReceived( const media_source& what, + bigtime_t how_much, bigtime_t performance_time ) +{ + /* This function is called as notification that a buffer we sent wasn't + * received by the time we stamped it with -- it got there late. Basically, + * it means we underestimated our own latency, so we should increase it */ + DBUG(("LateNoticeReceived() called.\n")); + + if( what != mOutput.source ) + return; + + if( RunMode() == B_INCREASE_LATENCY ) + { + mInternalLatency += how_much; + SetEventLatency( mDownstreamLatency + mInternalLatency ); + DBUG(("Increasing latency to %Ld\n", mDownstreamLatency + mInternalLatency)); + } + else + DBUG(("I don't know what to do with this notice!")); +} + + +void PaPlaybackNode::EnableOutput( const media_source& what, bool enabled, + int32* ) +{ + DBUG(("EnableOutput() called.\n")); + /* stub -- we don't support this yet */ +} + + +status_t PaPlaybackNode::PrepareToConnect( const media_source& what, + const media_destination& where, media_format* format, + media_source* out_source, char* out_name ) +{ + /* the final stage of format negotiations. here we _must_ make specific any + * remaining wildcards */ + DBUG(("PrepareToConnect() called.\n")); + + /* make sure this really refers to our source */ + if( what != mOutput.source ) + return B_MEDIA_BAD_SOURCE; + + /* make sure we're not already connected */ + if( mOutput.destination != media_destination::null ) + return B_MEDIA_ALREADY_CONNECTED; + + if( format->type != B_MEDIA_RAW_AUDIO ) + return B_MEDIA_BAD_FORMAT; + + if( format->u.raw_audio.format != mPreferredFormat.u.raw_audio.format ) + return B_MEDIA_BAD_FORMAT; + + if( format->u.raw_audio.buffer_size == + media_raw_audio_format::wildcard.buffer_size ) + { + DBUG(("We were left to decide buffer size: choosing 2048")); + format->u.raw_audio.buffer_size = 2048; + } + else + DBUG(("Using consumer specified buffer size of %lu.\n", + format->u.raw_audio.buffer_size)); + + /* Reserve the connection, return the information */ + mOutput.destination = where; + mOutput.format = *format; + *out_source = mOutput.source; + strncpy( out_name, mOutput.name, B_MEDIA_NAME_LENGTH ); + + return B_OK; +} + + +void PaPlaybackNode::Connect(status_t error, const media_source& source, + const media_destination& destination, const media_format& format, char* io_name) +{ + DBUG(("Connect() called.\n")); + diff --git a/pa_beos/PlaybackNode.h b/pa_beos/PlaybackNode.h new file mode 100644 index 0000000..64ee5b3 --- /dev/null +++ b/pa_beos/PlaybackNode.h @@ -0,0 +1,108 @@ +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * BeOS Media Kit Implementation by Joshua Haberman + * + * Copyright (c) 2001 Joshua Haberman + * + * 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 +#include +#include + +#include "portaudio.h" + +class PaPlaybackNode : + public BBufferProducer, + public BMediaEventLooper +{ + +public: + PaPlaybackNode( uint32 channels, float frame_rate, uint32 frames_per_buffer, + PortAudioCallback *callback, void *user_data ); + ~PaPlaybackNode(); + + + /* Local methods ******************************************/ + + BBuffer *FillNextBuffer(bigtime_t time); + void SetSampleFormat(PaSampleFormat inFormat, PaSampleFormat outFormat); + bool IsRunning(); + PaTimestamp GetStreamTime(); + + /* BMediaNode methods *************************************/ + + BMediaAddOn* AddOn( int32 * ) const; + status_t HandleMessage( int32 message, const void *data, size_t size ); + + /* BMediaEventLooper methods ******************************/ + + void HandleEvent( const media_timed_event *event, bigtime_t lateness, + bool realTimeEvent ); + void NodeRegistered(); + + /* BBufferProducer methods ********************************/ + + status_t FormatSuggestionRequested( media_type type, int32 quality, + media_format* format ); + status_t FormatProposal( const media_source& output, media_format* format ); + status_t FormatChangeRequested( const media_source& source, + const media_destination& destination, media_format* io_format, int32* ); + + status_t GetNextOutput( int32* cookie, media_output* out_output ); + status_t DisposeOutputCookie( int32 cookie ); + + void LateNoticeReceived( const media_source& what, bigtime_t how_much, + bigtime_t performance_time ); + void EnableOutput( const media_source& what, bool enabled, int32* _deprecated_ ); + + status_t PrepareToConnect( const media_source& what, + const media_destination& where, media_format* format, + media_source* out_source, char* out_name ); + void Connect(status_t error, const media_source& source, + const media_destination& destination, const media_format& format, + char* io_name); + void Disconnect(const media_source& what, const media_destination& where); + + status_t SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup); + + bool mAborted; + +private: + media_output mOutput; + media_format mPreferredFormat; + uint32 mOutputSampleWidth, mFramesPerBuffer; + BBufferGroup *mBufferGroup; + bigtime_t mDownstreamLatency, mInternalLatency, mStartTime; + uint64 mSamplesSent; + PortAudioCallback *mCallback; + void *mUserData; + bool mRunning; + +}; + diff --git a/pa_beos/pa_beos_mk.cc b/pa_beos/pa_beos_mk.cc new file mode 100644 index 0000000..287ec55 --- /dev/null +++ b/pa_beos/pa_beos_mk.cc @@ -0,0 +1,441 @@ +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * BeOS Media Kit Implementation by Joshua Haberman + * + * Copyright (c) 2001 Joshua Haberman + * + * 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 +#include +#include +#include +#include + +#include +#include + +#include "portaudio.h" +#include "pa_host.h" + +#include "PlaybackNode.h" + +#define PRINT(x) { printf x; fflush(stdout); } + +#ifdef DEBUG +#define DBUG(x) PRINT(x) +#else +#define DBUG(x) +#endif + +typedef struct PaHostSoundControl +{ + /* These members are common to all modes of operation */ + media_node pahsc_TimeSource; /* the sound card's DAC. */ + media_format pahsc_Format; + + /* These methods are specific to playing mode */ + media_node pahsc_OutputNode; /* output to the mixer */ + media_node pahsc_InputNode; /* reads data from user callback -- PA specific */ + + media_input pahsc_MixerInput; /* input jack on the soundcard's mixer. */ + media_output pahsc_PaOutput; /* output jack from the PA node */ + + PaPlaybackNode *pahsc_InputNodeInstance; + +} +PaHostSoundControl; + +/*************************************************************************/ +PaDeviceID Pa_GetDefaultOutputDeviceID( void ) +{ + /* stub */ + return 0; +} + +/*************************************************************************/ +PaDeviceID Pa_GetDefaultInputDeviceID( void ) +{ + /* stub */ + return 0; +} + +/*************************************************************************/ +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) +{ + /* stub */ + return NULL; +} + +/*************************************************************************/ +int Pa_CountDevices() +{ + /* stub */ + return 1; +} + +/*************************************************************************/ +PaError PaHost_Init( void ) +{ + /* we have to create this in order to use BMediaRoster. I hope it doesn't + * cause problems */ + be_app = new BApplication("application/x-vnd.portaudio-app"); + + return paNoError; +} + +PaError PaHost_Term( void ) +{ + delete be_app; + return paNoError; +} + +/*************************************************************************/ +PaError PaHost_StreamActive( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; + DBUG(("IsRunning returning: %s\n", + pahsc->pahsc_InputNodeInstance->IsRunning() ? "true" : "false")); + + return (PaError)pahsc->pahsc_InputNodeInstance->IsRunning(); +} + +PaError PaHost_StartOutput( internalPortAudioStream *past ) +{ + return paNoError; +} + +/*************************************************************************/ +PaError PaHost_StartInput( internalPortAudioStream *past ) +{ + return paNoError; +} + +/*************************************************************************/ +PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) +{ + return paNoError; +} + +/*************************************************************************/ +PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) +{ + return paNoError; +} + + +/*************************************************************************/ +PaError PaHost_StartEngine( internalPortAudioStream *past ) +{ + bigtime_t very_soon, start_latency; + status_t err; + BMediaRoster *roster = BMediaRoster::Roster(&err); + PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; + + /* for some reason, err indicates an error (though nothing it wrong) + * when the DBUG macro in pa_lib.c is enabled. It's reproducably + * linked. Weird. */ + if( !roster /* || err != B_OK */ ) + { + DBUG(("No media server! err=%d, roster=%x\n", err, roster)); + return paHostError; + } + + /* tell the node when to start -- since there aren't any other nodes + * starting that we have to wait for, just tell it to start now + */ + + BTimeSource *timeSource = roster->MakeTimeSourceFor(pahsc->pahsc_TimeSource); + very_soon = timeSource->PerformanceTimeFor( BTimeSource::RealTime() ); + timeSource->Release(); + + /* Add the latency of starting the network of nodes */ + err = roster->GetStartLatencyFor( pahsc->pahsc_TimeSource, &start_latency ); + very_soon += start_latency; + + err = roster->StartNode( pahsc->pahsc_InputNode, very_soon ); + /* No need to start the mixer -- it's always running */ + + return paNoError; +} + + +/*************************************************************************/ +PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; + BMediaRoster *roster = BMediaRoster::Roster(); + + if( !roster ) + { + DBUG(("No media roster!\n")); + return paHostError; + } + + if( !pahsc ) + return paHostError; + + /* this crashes, and I don't know why yet */ + // if( abort ) + // pahsc->pahsc_InputNodeInstance->mAborted = true; + + roster->StopNode(pahsc->pahsc_InputNode, 0, /* immediate = */ true); + + return paNoError; +} + + +/*************************************************************************/ +PaError PaHost_OpenStream( internalPortAudioStream *past ) +{ + status_t err; + BMediaRoster *roster = BMediaRoster::Roster(&err); + PaHostSoundControl *pahsc; + + /* Allocate and initialize host data. */ + pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); + if( pahsc == NULL ) + { + goto error; + } + memset( pahsc, 0, sizeof(PaHostSoundControl) ); + past->past_DeviceData = (void *) pahsc; + + if( !roster /* || err != B_OK */ ) + { + /* no media server! */ + DBUG(("No media server.\n")); + goto error; + } + + if ( past->past_NumInputChannels > 0 && past->past_NumOutputChannels > 0 ) + { + /* filter -- not implemented yet */ + goto error; + } + else if ( past->past_NumInputChannels > 0 ) + { + /* recorder -- not implemented yet */ + goto error; + } + else + { + /* player ****************************************************************/ + + status_t err; + int32 num; + + /* First we need to create the three components (like components in a stereo + * system). The mixer component is our interface to the sound card, data + * we write there will get played. The BePA_InputNode component is the node + * which represents communication with the PA client (it is what calls the + * client's callbacks). The time source component is the sound card's DAC, + * which allows us to slave the other components to it instead of the system + * clock. */ + err = roster->GetAudioMixer( &pahsc->pahsc_OutputNode ); + if( err != B_OK ) + { + DBUG(("Couldn't get default mixer.\n")); + goto error; + } + + err = roster->GetTimeSource( &pahsc->pahsc_TimeSource ); + if( err != B_OK ) + { + DBUG(("Couldn't get time source.\n")); + goto error; + } + + pahsc->pahsc_InputNodeInstance = new PaPlaybackNode(2, 44100, + past->past_FramesPerUserBuffer, past->past_Callback, past->past_UserData ); + pahsc->pahsc_InputNodeInstance->SetSampleFormat(0, + past->past_OutputSampleFormat); + err = roster->RegisterNode( pahsc->pahsc_InputNodeInstance ); + if( err != B_OK ) + { + DBUG(("Unable to register node.\n")); + goto error; + } + + roster->GetNodeFor( pahsc->pahsc_InputNodeInstance->Node().node, + &pahsc->pahsc_InputNode ); + if( err != B_OK ) + { + DBUG(("Unable to get input node.\n")); + goto error; + } + + /* Now we have three components (nodes) sitting next to each other. The + * next step is to look at them and find their inputs and outputs so we can + * wire them together. */ + err = roster->GetFreeInputsFor( pahsc->pahsc_OutputNode, + &pahsc->pahsc_MixerInput, 1, &num, B_MEDIA_RAW_AUDIO ); + if( err != B_OK || num < 1 ) + { + DBUG(("Couldn't get the mixer input.\n")); + goto error; + } + + err = roster->GetFreeOutputsFor( pahsc->pahsc_InputNode, + &pahsc->pahsc_PaOutput, 1, &num, B_MEDIA_RAW_AUDIO ); + if( err != B_OK || num < 1 ) + { + DBUG(("Couldn't get PortAudio output.\n")); + goto error; + } + + + /* We've found the input and output -- the final step is to run a wire + * between them so they are connected. */ + + /* try to make the mixer input adapt to what PA sends it */ + pahsc->pahsc_Format = pahsc->pahsc_PaOutput.format; + roster->Connect( pahsc->pahsc_PaOutput.source, + pahsc->pahsc_MixerInput.destination, &pahsc->pahsc_Format, + &pahsc->pahsc_PaOutput, &pahsc->pahsc_MixerInput ); + + + /* Actually, there's one final step -- tell them all to sync to the + * sound card's DAC */ + roster->SetTimeSourceFor( pahsc->pahsc_InputNode.node, + pahsc->pahsc_TimeSource.node ); + roster->SetTimeSourceFor( pahsc->pahsc_OutputNode.node, + pahsc->pahsc_TimeSource.node ); + + } + + return paNoError; + +error: + PaHost_CloseStream( past ); + return paHostError; +} + +/*************************************************************************/ +PaError PaHost_CloseStream( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; + status_t err; + BMediaRoster *roster = BMediaRoster::Roster(&err); + + if( !roster ) + { + DBUG(("Couldn't get media roster\n")); + return paHostError; + } + + if( !pahsc ) + return paHostError; + + /* Disconnect all the connections we made when opening the stream */ + + roster->Disconnect(pahsc->pahsc_InputNode.node, pahsc->pahsc_PaOutput.source, + pahsc->pahsc_OutputNode.node, pahsc->pahsc_MixerInput.destination); + + DBUG(("Calling ReleaseNode()")); + roster->ReleaseNode(pahsc->pahsc_InputNode); + + /* deleting the node shouldn't be necessary -- it is reference counted, and will + * delete itself when its references drop to zero. the call to ReleaseNode() + * above should decrease its reference count */ + pahsc->pahsc_InputNodeInstance = NULL; + + return paNoError; +} + +/*************************************************************************/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + internalPortAudioStream *past = (internalPortAudioStream *) stream; + PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; + + return pahsc->pahsc_InputNodeInstance->GetStreamTime(); +} + +/*************************************************************************/ +void Pa_Sleep( long msec ) +{ + /* snooze() takes microseconds */ + snooze( msec * 1000 ); +} + +/************************************************************************* + * 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(). + * Memory will be set to zero. + */ +void *PaHost_AllocateFastMemory( long numBytes ) +{ + /* BeOS supports non-pagable memory through pools -- a pool is an area + * of physical memory that is locked. It would be best to pre-allocate + * that pool and then hand out memory from it, but we don't know in + * advance how much we'll need. So for now, we'll allocate a pool + * for every request we get, storing a pointer to the pool at the + * beginning of the allocated memory */ + rtm_pool *pool; + void *addr; + long size = numBytes + sizeof(rtm_pool *); + static int counter = 0; + char pool_name[100]; + + /* Every pool needs a unique name. */ + sprintf(pool_name, "PaPoolNumber%d", counter++); + + if( rtm_create_pool( &pool, size, pool_name ) != B_OK ) + return 0; + + addr = rtm_alloc( pool, size ); + if( addr == NULL ) + return 0; + + memset( addr, 0, numBytes ); + *((rtm_pool **)addr) = pool; // store the pointer to the pool + addr = (rtm_pool **)addr + 1; // and return the next location in memory + + 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 ) +{ + rtm_pool *pool; + + if( addr == NULL ) + return; + + addr = (rtm_pool **)addr - 1; + pool = *((rtm_pool **)addr); + + rtm_free( addr ); + rtm_delete_pool( pool ); +} diff --git a/pa_common/pa_host.h b/pa_common/pa_host.h new file mode 100644 index 0000000..9a35261 --- /dev/null +++ b/pa_common/pa_host.h @@ -0,0 +1,142 @@ +#ifndef PA_HOST_H +#define PA_HOST_H + +/* + * $Id$ + * Host dependant internal API for PortAudio + * + * Author: Phil Burk + * + * 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. + * + */ + +#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 + +#define PA_MAGIC (0x18273645) + +/************************************************************************************/ +/****************** Structures ******************************************************/ +/************************************************************************************/ + +typedef struct internalPortAudioStream +{ + uint32 past_Magic; /* ID for struct to catch bugs. */ + /* 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; + void *past_DeviceData; + PortAudioCallback *past_Callback; + void *past_UserData; + uint32 past_Flags; + /* 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; + 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; +} +internalPortAudioStream; + +/************************************************************************************/ +/****************** Prototypes ******************************************************/ +/************************************************************************************/ + +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 ); + +long Pa_CallConvertInt16( internalPortAudioStream *past, + short *nativeInputBuffer, + short *nativeOutputBuffer ); + +long Pa_CallConvertFloat32( internalPortAudioStream *past, + float *nativeInputBuffer, + float *nativeOutputBuffer ); + +void *PaHost_AllocateFastMemory( long numBytes ); +void PaHost_FreeFastMemory( void *addr, long numBytes ); + +PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate, + double *closestFrameRatePtr ); +int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, + int numRates, double frameRate ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_HOST_H */ diff --git a/pa_common/pa_lib.c b/pa_common/pa_lib.c new file mode 100644 index 0000000..f32c635 --- /dev/null +++ b/pa_common/pa_lib.c @@ -0,0 +1,836 @@ +/* + * $Id$ + * 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 +#include +#include +#include + +/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ +#ifdef _WIN32 +#ifndef __MWERKS__ +#include +#endif /* __MWERKS__ */ +#else /* !_WIN32 */ +#include +#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; inumSampleRates == -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() NMUST 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. */ + 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; +} + +/************************************************************* +** Calculate 2 LSB dither signal with a triangular distribution. +** Ranged properly for adding to a 32 bit integer prior to >>15. +*/ +#define DITHER_BITS (15) +#define DITHER_SCALE (1.0f / ((1<>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS)); + /* 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; + long bytesEmpty = 0; + long bytesFilled = 0; + 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; ipast_InputBuffer; + inputBuffer = past->past_InputBuffer; + for( i=0; ipast_InputBuffer; + inputBuffer = past->past_InputBuffer; + if( past->past_Flags & paDitherOff ) + { + for( i=0; i> 8); + } + } + else + { + for( i=0; i> 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> 8)) + 0x80; + } + } + else + { + /* If you dither then you have to clip because dithering could push the signal out of range! */ + for( i=0; i> 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) ? + 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 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 0x7FFF) ? 0x7FFF : temp)); + } + } + break; + } + + case paInt32: + { + int *outBufPtr = (int *) past->past_OutputBuffer; + if( past->past_Flags & paDitherOff ) + { + for( i=0; i> 16 ); + } + } + else + { + for( i=0; i> 1) + Pa_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; ipast_OutputBuffer; + for( i=0; ipast_NumInputChannels > 0) && (nativeInputBuffer != NULL) ) + { + inputBuffer = nativeInputBuffer; /* FIXME */ + } + + /* 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 == paFloat32) ? + 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. */ /* FIXME */ + 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; +} + +/*************************************************************************/ +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/pa_common/pa_trace.c b/pa_common/pa_trace.c new file mode 100644 index 0000000..08e68f5 --- /dev/null +++ b/pa_common/pa_trace.c @@ -0,0 +1,83 @@ +/* + * $Id$ + * 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 +#include +#include +#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; iV{oit8R;E*@}X#()!Rhna!MR#+}TBxv1M;-|u9#rL+*p zkaPPkXL1okH>0gP+tGy!ZREH`ADhkT>}T(^=gRP@x(mpji@Uw+ukuPbiHD4lA7y`q>E^cUhmO)S(cP( za4U;D09O>SYBC-uVX`k6BwO>hkw??RUw$=lQD{8et zNgaw12@N&H*F&fe7KJg9;l_F(*-6Z#__^lTXL3QC+w=SR^>tPE{Vs5V!IHB8wvisS zD-2rf2L=KOG^I$e98{$7B_KCaV;!eWeMvl|--6@0a2&nDNdr(3<5tg|`|NXELjYxc z?aI*eiugH4U4!h<<8OczN)~$HpF)W>;{}!5&_n;cok$fAAybCLdI2d?=(r6}u%aO! zGBwPOng|J?wN9%_sk^~F4F|PDw?9yu5aA!!E9;kH!Q4h{&<{~SKWgh_fOxFCp|y$( zH2|#0GBiMsL_Cx6_${1?QoKhC5V(?jTMrB&H@5KW9i?^3+@T^vjzpbJN#=@HuaHny z(UJHsUkw!SrV>vE5gueq2fQ+UqXzN-=EKb{-E4|BUSTOkU5qh-li!Bjj5g~~2A)G> zfzG%axC@39q!9Ub=9?HcB+(1s1y*m^kk{-DNedzRK42B3?aGHIOw@U|QkUY^a7$z| zRF-|yehol=sT3%{L8Y?olp2lXO)ocJ{qqM<>i5s!kzMFJ_F1*TK}+jxLN7`=R&;PO un(nK~{^b3H795@RxK>T@GkP~YsSd`~@!^!lCp0;%#uCxb|A`!`H@^T5#E2*W literal 0 HcmV?d00001 diff --git a/pa_dll_switch/loadPA_DLL.cpp b/pa_dll_switch/loadPA_DLL.cpp new file mode 100644 index 0000000..043eda8 --- /dev/null +++ b/pa_dll_switch/loadPA_DLL.cpp @@ -0,0 +1,203 @@ +////////////////////////////////////////////////////////////////////////// + + +HINSTANCE pPaDll; + +/* + the function pointers to the PortAudio DLLs +*/ + +PaError (__cdecl* Pa_Initialize)( void ); + + + +PaError (__cdecl* Pa_Terminate)( void ); + + +long (__cdecl* Pa_GetHostError)( void ); + + +const char* (__cdecl* Pa_GetErrorText)( PaError ); + + +int (__cdecl* Pa_CountDevices)(void); + +PaDeviceID (__cdecl* Pa_GetDefaultInputDeviceID)( void ); + +PaDeviceID (__cdecl* Pa_GetDefaultOutputDeviceID)( void ); + + +const PaDeviceInfo* (__cdecl* Pa_GetDeviceInfo)( PaDeviceID); + + + +PaError (__cdecl* Pa_OpenStream)( + PortAudioStream ** , + PaDeviceID , + int , + PaSampleFormat , + void *, + PaDeviceID , + int , + PaSampleFormat , + void *, + double , + unsigned long , + unsigned long , + unsigned long , + PortAudioCallback *, + void * ); + + + +PaError (__cdecl* Pa_OpenDefaultStream)( PortAudioStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PortAudioCallback *callback, + void *userData ); + + +PaError (__cdecl* Pa_CloseStream)( PortAudioStream* ); + + +PaError (__cdecl* Pa_StartStream)( PortAudioStream *stream ); + +PaError (__cdecl* Pa_StopStream)( PortAudioStream *stream ); + +PaError (__cdecl* Pa_AbortStream)( PortAudioStream *stream ); + +PaError (__cdecl* Pa_StreamActive)( PortAudioStream *stream ); + +PaTimestamp (__cdecl* Pa_StreamTime)( PortAudioStream *stream ); + +double (__cdecl* Pa_GetCPULoad)( PortAudioStream* stream ); + +int (__cdecl* Pa_GetMinNumBuffers)( int framesPerBuffer, double sampleRate ); + +void (__cdecl* Pa_Sleep)( long msec ); + +PaError (__cdecl* Pa_GetSampleSize)( PaSampleFormat format ); + + +////////////////////////////////////////////////////////////////////////// + +... + +ZERROR AudioEngine::DirectXSupport(ZBOOL bSupDX) +{ + if (bSupDX) + if (CheckForDirectXSupport()) + bSupportDirectX = _TRUE; + else + return _NO_SOUND; + else + bSupportDirectX = _FALSE; + return _NO_ERROR; +} + + + +ZBOOL AudioEngine::CheckForDirectXSupport() +{ + HMODULE pTestDXLib; + FARPROC pFunctionality; + + pTestDXLib=LoadLibrary("DSOUND"); + if (pTestDXLib!=NULL) // check if there is a DirectSound + { + pFunctionality = GetProcAddress(pTestDXLib, (char*) 7); + if (pFunctionality!=NULL) + { + FreeLibrary(pTestDXLib); + return _TRUE; + } + else + { + FreeLibrary(pTestDXLib); + return _FALSE; + } + } + else + return _FALSE; +} + + +ZERROR AudioEngine::LoadPALib() +{ +#ifdef _DEBUG + if (bSupportDirectX) + pPaDll = LoadLibrary("PA_DXD"); + else + pPaDll = LoadLibrary("PA_MMED"); +#else + if (bSupportDirectX) + pPaDll = LoadLibrary("PA_DX"); + else + pPaDll = LoadLibrary("PA_MME"); +#endif + if (pPaDll!=NULL) + { + + Pa_Initialize = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_Initialize"); + Pa_Terminate = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_Terminate"); + Pa_GetHostError = (long (__cdecl* )( void )) GetProcAddress(pPaDll,"Pa_GetHostError"); + Pa_GetErrorText = (const char* (__cdecl* )( PaError )) GetProcAddress(pPaDll,"Pa_GetErrorText"); + Pa_CountDevices = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_CountDevices"); + Pa_GetDefaultInputDeviceID = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_GetDefaultInputDeviceID"); + Pa_GetDefaultOutputDeviceID = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_GetDefaultOutputDeviceID"); + Pa_GetDeviceInfo = (const PaDeviceInfo* (__cdecl* )( PaDeviceID)) GetProcAddress(pPaDll,"Pa_GetDeviceInfo"); + Pa_OpenStream = ( PaError (__cdecl* )( + PortAudioStream ** , + PaDeviceID , + int , + PaSampleFormat , + void *, + PaDeviceID , + int , + PaSampleFormat , + void *, + double , + unsigned long , + unsigned long , + unsigned long , + PortAudioCallback *, + void * )) GetProcAddress(pPaDll,"Pa_OpenStream"); + + Pa_OpenDefaultStream = (PaError (__cdecl* )( PortAudioStream** , + int , + int , + PaSampleFormat , + double , + unsigned long , + unsigned long , + PortAudioCallback *, + void * )) GetProcAddress(pPaDll,"Pa_OpenDefaultStream"); + Pa_CloseStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_CloseStream"); + Pa_StartStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_StartStream"); + Pa_StopStream = (PaError (__cdecl* )( PortAudioStream* ))GetProcAddress(pPaDll,"Pa_StopStream"); + Pa_AbortStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_AbortStream"); + Pa_StreamActive = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_StreamActive"); + Pa_StreamTime = (PaTimestamp (__cdecl* )( PortAudioStream *))GetProcAddress(pPaDll,"Pa_StreamTime"); + Pa_GetCPULoad = (double (__cdecl* )( PortAudioStream* ))GetProcAddress(pPaDll,"Pa_GetCPULoad"); + Pa_GetMinNumBuffers = (int (__cdecl* )( int , double )) GetProcAddress(pPaDll,"Pa_GetMinNumBuffers"); + Pa_Sleep = (void (__cdecl* )( long )) GetProcAddress(pPaDll,"Pa_Sleep"); + Pa_GetSampleSize = (PaError (__cdecl* )( PaSampleFormat )) GetProcAddress(pPaDll,"Pa_GetSampleSize"); + + return _NO_ERROR; + } + else + return _DLL_NOT_FOUND; +} + +ZERROR AudioEngine::UnLoadPALib() +{ + if (pPaDll!=NULL) + FreeLibrary(pPaDll); + return _NO_ERROR; +} + +... diff --git a/pa_dll_switch/pa_lib.c b/pa_dll_switch/pa_lib.c new file mode 100644 index 0000000..8660159 --- /dev/null +++ b/pa_dll_switch/pa_lib.c @@ -0,0 +1,827 @@ +/* + * 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 +*/ + +#include +#include +#include +#include + +/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ +#ifdef _WIN32 +#ifndef __MWERKS__ +#include +#endif /* __MWERKS__ */ +#else /* !_WIN32 */ +#include +#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; inumSampleRates == -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; +} + +/*************************************************************************/ +DLL_API 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() NMUST 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. */ + 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; +} + + +/*************************************************************************/ +DLL_API 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 ); +} + +/*************************************************************************/ +DLL_API 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; +} + +/*************************************************************************/ +DLL_API 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; +} + +/*************************************************************************/ +DLL_API PaError Pa_StopStream( PortAudioStream *stream ) +{ + return Pa_KillStream( stream, 0 ); +} + +/*************************************************************************/ +DLL_API 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; +} + +/*************************************************************************/ +DLL_API PaError Pa_StreamActive( PortAudioStream *stream ) +{ + internalPortAudioStream *past; + if( stream == NULL ) return paBadStreamPtr; + past = (internalPortAudioStream *) stream; + return PaHost_StreamActive( past ); +} + +/*************************************************************************/ +DLL_API 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; + 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. +*/ +DLL_API double Pa_GetCPULoad( PortAudioStream* stream) +{ + internalPortAudioStream *past; + if( stream == NULL ) return (double) paBadStreamPtr; + past = (internalPortAudioStream *) stream; + return past->past_Usage; +} + +/************************************************************* +** Calculate 2 LSB dither signal with a triangular distribution. +** Ranged properly for adding to a 32 bit integer prior to >>15. +*/ +#define DITHER_BITS (15) +#define DITHER_SCALE (1.0f / ((1<>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS)); + /* 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; + long bytesEmpty = 0; + long bytesFilled = 0; + 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; ipast_InputBuffer; + inputBuffer = past->past_InputBuffer; + for( i=0; ipast_InputBuffer; + inputBuffer = past->past_InputBuffer; + if( past->past_Flags & paDitherOff ) + { + for( i=0; i> 8); + } + } + else + { + for( i=0; i> 7; + 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> 8)) + 0x80; + } + } + else + { + /* If you dither then you have to clip because dithering could push the signal out of range! */ + for( i=0; i> 7; + temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); + inBufPtr[i] = (unsigned char)(temp + 0x80); + } + } + 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) ? + 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 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 0x7FFF) ? 0x7FFF : temp)); + } + } + break; + } + + case paInt32: + { + int *outBufPtr = (int *) past->past_OutputBuffer; + if( past->past_Flags & paDitherOff ) + { + for( i=0; i> 16 ); + } + } + else + { + for( i=0; i> 1) + Pa_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; ipast_OutputBuffer; + for( i=0; ipast_NumInputChannels > 0) && (nativeInputBuffer != NULL) ) + { + inputBuffer = nativeInputBuffer; // FIXME + } + + /* 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 == paFloat32) ? + 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. */ // FIXME + return userResult; +} + +/*************************************************************************/ +DLL_API PaError Pa_Initialize( void ) +{ + if( gInitCount++ > 0 ) return paNoError; + ResetTraceMessages(); + return PaHost_Init(); +} + +DLL_API PaError Pa_Terminate( void ) +{ + PaError result = paNoError; + + if( gInitCount == 0 ) return paNoError; + else if( --gInitCount == 0 ) + { + result = PaHost_Term(); + DumpTraceMessages(); + } + return result; +} + +/*************************************************************************/ +DLL_API 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/pa_dll_switch/portaudio.h b/pa_dll_switch/portaudio.h new file mode 100644 index 0000000..9632521 --- /dev/null +++ b/pa_dll_switch/portaudio.h @@ -0,0 +1,439 @@ +#ifndef PORT_AUDIO_H +#define PORT_AUDIO_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * 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. + * + */ + +// added by zplane.developement in order to generate a DLL + +#if defined(PA_MME_EXPORTS) || defined(PA_DX_EXPORTS) +#define DLL_API __declspec( dllexport ) +#elif defined(_LIB) || defined(_STATIC_LINK) || defined(_STATIC_APP) +#define DLL_API +#else +#define DLL_API __declspec(dllexport) +#endif + + +typedef int PaError; +typedef enum { + paNoError = 0, + + paHostError = -10000, + paInvalidChannelCount, + paInvalidSampleRate, + paInvalidDeviceId, + paInvalidFlag, + paSampleFormatNotSupported, + paBadIODeviceCombination, + paInsufficientMemory, + paBufferTooBig, + paBufferTooSmall, + paNullCallback, + paBadStreamPtr, + paTimedOut, + paInternalError +} PaErrorNum; + +/* + Pa_Initialize() is the library initialisation function - call this before + using the library. +*/ + +DLL_API PaError Pa_Initialize( void ); + +/* + Pa_Terminate() is the library termination function - call this after + using the library. +*/ + +DLL_API PaError Pa_Terminate( void ); + +/* + Return host specific error. + This can be called after receiving a paHostError. +*/ +DLL_API long Pa_GetHostError( void ); + +/* + Translate the error number into a human readable message. +*/ +DLL_API 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 devices. + + The floating point representation uses +1.0 and -1.0 as the respective + maximum and minimum. + +*/ + +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)) /* unsigned 8 bit, 128 is "ground" */ +#define paCustomFormat ((PaSampleFormat) (1<<16)) + +/* + Device enumeration mechanism. + + Device ids range from 0 to Pa_CountDevices()-1. + + Devices may support input, output or both. Device 0 is always the "default" + device and should support at least stereo in and out if that is available + on the taget platform _even_ if this involves kludging an input/output + device on platforms that usually separate input from output. Other platform + specific devices are specified by positive device ids. +*/ + +typedef int PaDeviceID; +#define paNoDevice -1 + +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; + + +DLL_API int Pa_CountDevices(); +/* + Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() + + Return the default device ID or paNoDevice if there is no devices. + 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 ID by using + the supplied application "pa_devs". +*/ +DLL_API PaDeviceID Pa_GetDefaultInputDeviceID( void ); +DLL_API PaDeviceID Pa_GetDefaultOutputDeviceID( void ); + +/* + PaTimestamp is used to represent a continuous sample clock with arbitrary + start time useful for syncronisation. The type is used in the outTime + argument to the callback function and the result of Pa_StreamTime() +*/ + +typedef double PaTimestamp; + +/* + Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure + referring to the device specified by id. + If id is out of range the function returns NULL. + + The returned structure is owned by the PortAudio implementation and must + not be manipulated or freed. The pointer is guaranteed to be valid until + between calls to Pa_Initialize() and Pa_Terminate(). +*/ + +DLL_API const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ); + +/* + PortAudioCallback is implemented by clients of the portable audio api. + + 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 nonzero 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 + nonzero 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. + + [ suggestions? ] +*/ + +#define paNoFlag (0) +#define paClipOff (1<<0) /* disable defult 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 + device input record for the device specified in the inputDevice parameter. + If inputDevice is paNoDevice numInputChannels is ignored. + + inputSampleFormat is the 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 sound devices 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 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. 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 behavior 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: + Apon 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 nonzero error code is returned (see + PAError above) and the value of stream is invalid. + +*/ + +DLL_API 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 ouput 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 (same as passing paNoDevice in the device arguments to Pa_OpenStream() ) + + sampleFormat applies to both the input and output buffers. +*/ + +DLL_API 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. +*/ + +DLL_API PaError Pa_CloseStream( PortAudioStream* ); + +/* + Pa_StartStream() and Pa_StopStream() begin and terminate audio processing. + When Pa_StopStream() returns, all pending audio buffers have been played. + Pa_AbortStream() stops playing immediately without waiting for pending + buffers to complete. +*/ + +DLL_API PaError Pa_StartStream( PortAudioStream *stream ); + +DLL_API PaError Pa_StopStream( PortAudioStream *stream ); + +DLL_API PaError Pa_AbortStream( PortAudioStream *stream ); + +/* + Pa_StreamActive() returns one when the stream is playing audio, + zero 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. +*/ + +DLL_API PaError Pa_StreamActive( PortAudioStream *stream ); + +/* + Pa_StreamTime() returns the current output time for the stream in samples. + This time may be used as a time reference (for example syncronising audio to + MIDI). +*/ + +DLL_API PaTimestamp Pa_StreamTime( PortAudioStream *stream ); + +/* + The "CPU Load" is a fraction of total CPU time consumed by the + stream's audio processing. + 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. +*/ +DLL_API double Pa_GetCPULoad( PortAudioStream* stream ); + +/* + Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for + 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. +*/ + +DLL_API int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ); + +/* + Sleep for at least 'msec' milliseconds. + You may sleep longer than the requested time so don't rely + on this for accurate musical timing. +*/ +DLL_API void Pa_Sleep( long msec ); + +/* + Return size in bytes of a single sample in a given PaSampleFormat + or paSampleFormatNotSupported. +*/ +DLL_API PaError Pa_GetSampleSize( PaSampleFormat format ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PORT_AUDIO_H */ diff --git a/pa_mac/pa_mac.c b/pa_mac/pa_mac.c new file mode 100644 index 0000000..cde9a95 --- /dev/null +++ b/pa_mac/pa_mac.c @@ -0,0 +1,1567 @@ +/* + * $Id$ + * Portable Audio I/O Library for Macintosh + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2000 Phil Burk + * + * Special thanks to Chris Rolfe for his many helpful suggestions, bug fixes, + * and code contributions. + * Thanks also to Tue Haste Andersen, Alberto Ricci, Nico Wald, + * Roelf Toxopeus and Tom Erbe for testing the code and making + * numerous suggestions. + * + * 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 + PLB20010415 - ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID + PLB20010415 - Device Scan was crashing for anything other than siBadSoundInDevice, but some Macs may return other errors! + PLB20010420 - Fix TIMEOUT in record mode. + PLB20010420 - Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON + PLB20010907 - Pass unused event to WaitNextEvent to prevent Mac OSX crash. Thanks Dominic Mazzoni. + PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. + PLB20011009 - Use NewSndCallBackUPP() for CARBON +*/ +/* +COMPATIBILITY +This Macintosh implementation is designed for use with Mac OS 7, 8 and +9 on PowerMacs, and OS X if compiled with CARBON + +OUTPUT +A circular array of CmpSoundHeaders is used as a queue. For low latency situations +there will only be two small buffers used. For higher latency, more and larger buffers +may be used. +To play the sound we use SndDoCommand() with bufferCmd. Each buffer is followed +by a callbackCmd which informs us when the buffer has been processsed. + +INPUT +The SndInput Manager SPBRecord call is used for sound input. If only +input is used, then the PA user callback is called from the Input completion proc. +For full-duplex, or output only operation, the PA callback is called from the +HostBuffer output completion proc. In that case, input sound is passed to the +callback by a simple FIFO. + +TODO: +O- Add support for native sample data formats other than int16. +O- Review buffer sizing. Should it be based on result of siDeviceBufferInfo query? +O- Determine default devices somehow. +*/ +#include +#include +#include +#include +#include +/* Mac specific includes */ +#include "OSUtils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "portaudio.h" +#include "pa_host.h" +#include "pa_trace.h" + +#ifndef FALSE + #define FALSE (0) + #define TRUE (!FALSE) +#endif + +/* Debugging output macros. */ +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) /* PRINT(x) /**/ +#define DBUGX(x) /* PRINT(x) /**/ + +#define MAC_PHYSICAL_FRAMES_PER_BUFFER (512) /* Minimum number of stereo frames per SoundManager double buffer. */ +#define MAC_VIRTUAL_FRAMES_PER_BUFFER (4096) /* Need this many when using Virtual Memory for recording. */ +#define PA_MIN_NUM_HOST_BUFFERS (2) +#define PA_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */ +#define PA_MAX_DEVICE_INFO (32) + +/* Conversions for 16.16 fixed point code. */ +#define DoubleToUnsignedFixed(x) ((UnsignedFixed) ((x) * 65536.0)) +#define UnsignedFixedToDouble(fx) (((double)(fx)) * (1.0/(1<<16))) + +/************************************************************************************/ +/****************** Structures ******************************************************/ +/************************************************************************************/ +/* Use for passing buffers from input callback to output callback for processing. */ +typedef struct MultiBuffer +{ + char *buffers[PA_MAX_NUM_HOST_BUFFERS]; + int numBuffers; + int nextWrite; + int nextRead; +} +MultiBuffer; + +/* Define structure to contain all Macintosh specific data. */ +typedef struct PaHostSoundControl +{ + UInt64 pahsc_EntryCount; + UInt64 pahsc_LastExitCount; + /* Use char instead of Boolean for atomic operation. */ + volatile char pahsc_IsRecording; /* Recording in progress. Set by foreground. Cleared by background. */ + volatile char pahsc_StopRecording; /* Signal sent to background. */ + volatile char pahsc_IfInsideCallback; + /* Input */ + SPB pahsc_InputParams; + SICompletionUPP pahsc_InputCompletionProc; + MultiBuffer pahsc_InputMultiBuffer; + int32 pahsc_BytesPerInputHostBuffer; + int32 pahsc_InputRefNum; + /* Output */ + CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS]; + int32 pahsc_BytesPerOutputHostBuffer; + SndChannelPtr pahsc_Channel; + SndCallBackUPP pahsc_OutputCompletionProc; + int32 pahsc_NumOutsQueued; + int32 pahsc_NumOutsPlayed; + PaTimestamp pahsc_NumFramesDone; + /* Init Time -------------- */ + int32 pahsc_NumHostBuffers; + int32 pahsc_FramesPerHostBuffer; + int32 pahsc_UserBuffersPerHostBuffer; + int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */ +} +PaHostSoundControl; + +/* Mac specific device information. */ +typedef struct internalPortAudioDevice +{ + long pad_DeviceRefNum; + long pad_DeviceBufferSize; + Component pad_Identifier; + PaDeviceInfo pad_Info; +} +internalPortAudioDevice; + +/************************************************************************************/ +/****************** Data ************************************************************/ +/************************************************************************************/ +static int sNumDevices = 0; +static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 }; +static int32 sPaHostError = 0; +static int sDefaultOutputDeviceID; +static int sDefaultInputDeviceID; + +/************************************************************************************/ +/****************** Prototypes ******************************************************/ +/************************************************************************************/ +static PaError PaMac_TimeSlice( internalPortAudioStream *past, int16 *macOutputBufPtr ); +static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr ); +static PaError PaMac_RecordNext( internalPortAudioStream *past );static void StartLoadCalculation( internalPortAudioStream *past ); +static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate ); +static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h ); +static PaError PaMac_ScanInputDevices( void ); +static PaError PaMac_ScanOutputDevices( void ); +static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad ); +static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad ); +static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader ); +static void PaMac_EndLoadCalculation( internalPortAudioStream *past ); +static void PaMac_PlayNext ( internalPortAudioStream *past, int index ); +static long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index ); +static pascal void PaMac_InputCompletionProc(SPBPtr recParams); +static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCmd); +static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index ); +long PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); +static int Mac_IsVirtualMemoryOn( void ); +static void PToCString(unsigned char* inString, char* outString); +char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf ); +char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf ); +int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf ); +int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf ); +int MultiBuffer_IsWriteable( MultiBuffer *mbuf ); +int MultiBuffer_IsReadable( MultiBuffer *mbuf ); +void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf ); +void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf ); + +/************************************************************************* +** Simple FIFO index control for multiple buffers. +** Read and Write indices range from 0 to 2N-1. +** This allows us to distinguish between full and empty. +*/ +char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf ) +{ + return mbuf->buffers[mbuf->nextWrite % mbuf->numBuffers]; +} +char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf ) +{ + return mbuf->buffers[mbuf->nextRead % mbuf->numBuffers]; +} +int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf ) +{ + return mbuf->nextRead % mbuf->numBuffers; +} +int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf ) +{ + return mbuf->nextWrite % mbuf->numBuffers; +} + +int MultiBuffer_IsWriteable( MultiBuffer *mbuf ) +{ + int bufsFull = mbuf->nextWrite - mbuf->nextRead; + if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers); + return (bufsFull < mbuf->numBuffers); +} +int MultiBuffer_IsReadable( MultiBuffer *mbuf ) +{ + int bufsFull = mbuf->nextWrite - mbuf->nextRead; + if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers); + return (bufsFull > 0); +} +void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf ) +{ + int temp = mbuf->nextRead + 1; + mbuf->nextRead = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp; +} +void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf ) +{ + int temp = mbuf->nextWrite + 1; + mbuf->nextWrite = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp; +} + +/************************************************************************* +** String Utility by Chris Rolfe +*/ +static void PToCString(unsigned char* inString, char* outString) +{ + long i; + for(i=0; isampleRates; + if( (rates != NULL) ) free( rates ); /* MEM_011 */ + dev->sampleRates = NULL; + if( dev->name != NULL ) free( (void *) dev->name ); /* MEM_010 */ + dev->name = NULL; + } + sNumDevices = 0; + return paNoError; +} + +/************************************************************************* + PaHost_Init() is the library initialization function - call this before + using the library. +*/ +PaError PaHost_Init( void ) +{ + PaError err; + NumVersionVariant version; + + version.parts = SndSoundManagerVersion(); + DBUG(("SndSoundManagerVersion = 0x%x\n", version.whole)); + + /* Have we already initialized the device info? */ + err = (PaError) Pa_CountDevices(); + if( err < 0 ) return err; + else return paNoError; +} + +/************************************************************************* + PaMac_ScanOutputDevices() queries the properties of all output devices. +*/ +static PaError PaMac_ScanOutputDevices( void ) +{ + PaError err; + Component identifier=0; + ComponentDescription criteria = { kSoundOutputDeviceType, 0, 0, 0, 0 }; + long numComponents, i; + + /* Search the system linked list for output components */ + numComponents = CountComponents (&criteria); + identifier = 0; + sDefaultOutputDeviceID = sNumDevices; /* FIXME - query somehow */ + for (i = 0; i < numComponents; i++) + { + /* passing nil returns first matching component. */ + identifier = FindNextComponent( identifier, &criteria); + sDevices[sNumDevices].pad_Identifier = identifier; + + /* Set up for default OUTPUT devices. */ + err = PaMac_QueryOutputDeviceInfo( identifier, &sDevices[sNumDevices] ); + if( err < 0 ) return err; + else sNumDevices++; + + } + + return paNoError; +} + +/************************************************************************* + PaMac_ScanInputDevices() queries the properties of all input devices. +*/ +static PaError PaMac_ScanInputDevices( void ) +{ + Str255 deviceName; + int count; + Handle iconHandle; + PaError err; + OSErr oserr; + count = 1; + sDefaultInputDeviceID = sNumDevices; /* FIXME - query somehow */ /* PLB20010415 - was setting sDefaultOutputDeviceID */ + while(true) + { + /* Thanks Chris Rolfe and Alberto Ricci for this trick. */ + oserr = SPBGetIndexedDevice(count++, deviceName, &iconHandle); + DBUG(("PaMac_ScanInputDevices: SPBGetIndexedDevice returned %d\n", oserr )); +#if 1 + /* PLB20010415 - was giving error for anything other than siBadSoundInDevice, but some Macs may return other errors! */ + if(oserr != noErr) break; /* Some type of error is expected when count > devices */ +#else + if(oserr == siBadSoundInDevice) + { /* it's expected when count > devices */ + oserr = noErr; + break; + } + if(oserr != noErr) + { + ERR_RPT(("ERROR: SPBGetIndexedDevice(%d,,) returned %d\n", count-1, oserr )); + sPaHostError = oserr; + return paHostError; + } +#endif + DisposeHandle(iconHandle); /* Don't need the icon */ + + err = PaMac_QueryInputDeviceInfo( deviceName, &sDevices[sNumDevices] ); + DBUG(("PaMac_ScanInputDevices: PaMac_QueryInputDeviceInfo returned %d\n", err )); + if( err < 0 ) return err; + else if( err == 1 ) sNumDevices++; + } + + return paNoError; +} + +/* Sample rate info returned by using siSampleRateAvailable selector in SPBGetDeviceInfo() */ +/* Thanks to Chris Rolfe for help with this query. */ +#pragma options align=mac68k +typedef struct +{ + int16 numRates; + UnsignedFixed (**rates)[]; /* Handle created by SPBGetDeviceInfo */ +} +SRateInfo; +#pragma options align=reset + +/************************************************************************* +** PaMac_QueryOutputDeviceInfo() +** Query information about a named output device. +** Clears contents of ipad and writes info based on queries. +** Return one if OK, +** zero if device cannot be used, +** or negative error. +*/ +static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad ) +{ + int len; + OSErr err; + PaDeviceInfo *dev = &ipad->pad_Info; + SRateInfo srinfo = {0}; + int numRates; + ComponentDescription tempD; + Handle nameH=nil, infoH=nil, iconH=nil; + + memset( ipad, 0, sizeof(internalPortAudioDevice) ); + + dev->structVersion = 1; + dev->maxInputChannels = 0; + dev->maxOutputChannels = 2; + dev->nativeSampleFormats = paInt16; /* FIXME - query to see if 24 or 32 bit data can be handled. */ + + /* Get sample rates supported. */ + err = GetSoundOutputInfo(identifier, siSampleRateAvailable, (Ptr) &srinfo); + if(err != noErr) + { + ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetSoundOutputInfo siSampleRateAvailable returned %d\n", err )); + goto error; + } + numRates = srinfo.numRates; + DBUG(("PaMac_QueryOutputDeviceInfo: srinfo.numRates = 0x%x\n", srinfo.numRates )); + if( numRates == 0 ) + { + dev->numSampleRates = -1; + numRates = 2; + } + else + { + dev->numSampleRates = numRates; + } + dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates ); + /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */ + DisposeHandle((Handle) srinfo.rates); + + /* Device name */ + /* we pass an existing handle for the component name; + we don't care about the info (type, subtype, etc.) or icon, so set them to nil */ + infoH = nil; + iconH = nil; + nameH = NewHandle(0); + if(nameH == nil) return paInsufficientMemory; + err = GetComponentInfo(identifier, &tempD, nameH, infoH, iconH); + if (err) + { + ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetComponentInfo returned %d\n", err )); + goto error; + } + len = (*nameH)[0] + 1; + dev->name = (char *) malloc(len); /* MEM_010 */ + if( dev->name == NULL ) + { + DisposeHandle(nameH); + return paInsufficientMemory; + } + else + { + PToCString((unsigned char *)(*nameH), (char *) dev->name); + DisposeHandle(nameH); + } + + DBUG(("PaMac_QueryOutputDeviceInfo: dev->name = %s\n", dev->name )); + return paNoError; + +error: + sPaHostError = err; + return paHostError; + +} + +/************************************************************************* +** PaMac_QueryInputDeviceInfo() +** Query information about a named input device. +** Clears contents of ipad and writes info based on queries. +** Return one if OK, +** zero if device cannot be used, +** or negative error. +*/ +static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad ) +{ + PaError result = paNoError; + int len; + OSErr err; + long mRefNum = 0; + long tempL; + int16 tempS; + Fixed tempF; + PaDeviceInfo *dev = &ipad->pad_Info; + SRateInfo srinfo = {0}; + int numRates; + + memset( ipad, 0, sizeof(internalPortAudioDevice) ); + dev->maxOutputChannels = 0; + + /* Open device based on name. If device is in use, it may not be able to open in write mode. */ + err = SPBOpenDevice( deviceName, siWritePermission, &mRefNum); + if (err) + { + /* If device is in use, it may not be able to open in write mode so try read mode. */ + err = SPBOpenDevice( deviceName, siReadPermission, &mRefNum); + if (err) + { + ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBOpenDevice returned %d\n", err )); + sPaHostError = err; + return paHostError; + } + } + + /* Define macros for printing out device info. */ +#define PrintDeviceInfo(selector,var) \ + err = SPBGetDeviceInfo(mRefNum, selector, (Ptr) &var); \ + if (err) { \ + DBUG(("query %s failed\n", #selector )); \ + }\ + else { \ + DBUG(("query %s = 0x%x\n", #selector, var )); \ + } + + PrintDeviceInfo( siContinuous, tempS ); + PrintDeviceInfo( siAsync, tempS ); + PrintDeviceInfo( siNumberChannels, tempS ); + PrintDeviceInfo( siSampleSize, tempS ); + PrintDeviceInfo( siSampleRate, tempF ); + PrintDeviceInfo( siChannelAvailable, tempS ); + PrintDeviceInfo( siActiveChannels, tempL ); + PrintDeviceInfo( siDeviceBufferInfo, tempL ); + + err = SPBGetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL); + if (err == 0) DBUG(("%s = 0x%x\n", "siActiveChannels", tempL )); + /* Can we use this device? */ + err = SPBGetDeviceInfo(mRefNum, siAsync, (Ptr) &tempS); + if (err) + { + ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siAsync returned %d\n", err )); + goto error; + } + if( tempS == 0 ) goto useless; /* Does not support async recording so forget about it. */ + + err = SPBGetDeviceInfo(mRefNum, siChannelAvailable, (Ptr) &tempS); + if (err) + { + ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siChannelAvailable returned %d\n", err )); + goto error; + } + dev->maxInputChannels = tempS; + + /* Get sample rates supported. */ + err = SPBGetDeviceInfo(mRefNum, siSampleRateAvailable, (Ptr) &srinfo); + if (err) + { + ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleRateAvailable returned %d\n", err )); + goto error; + } + + numRates = srinfo.numRates; + DBUG(("numRates = 0x%x\n", numRates )); + if( numRates == 0 ) + { + dev->numSampleRates = -1; + numRates = 2; + } + else + { + dev->numSampleRates = numRates; + } + dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates ); + /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */ + DisposeHandle((Handle) srinfo.rates); + + /* Get size of device buffer. */ + err = SPBGetDeviceInfo(mRefNum, siDeviceBufferInfo, (Ptr) &tempL); + if (err) + { + ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siDeviceBufferInfo returned %d\n", err )); + goto error; + } + ipad->pad_DeviceBufferSize = tempL; + DBUG(("siDeviceBufferInfo = %d\n", tempL )); + + /* Set format based on sample size. */ + err = SPBGetDeviceInfo(mRefNum, siSampleSize, (Ptr) &tempS); + if (err) + { + ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleSize returned %d\n", err )); + goto error; + } + switch( tempS ) + { + case 0x0020: + dev->nativeSampleFormats = paInt32; /* FIXME - warning, code probably won't support this! */ + break; + case 0x0010: + default: /* FIXME - What about other formats? */ + dev->nativeSampleFormats = paInt16; + break; + } + DBUG(("nativeSampleFormats = %d\n", dev->nativeSampleFormats )); + + /* Device name */ + len = deviceName[0] + 1; /* Get length of Pascal string */ + dev->name = (char *) malloc(len); /* MEM_010 */ + if( dev->name == NULL ) + { + result = paInsufficientMemory; + goto cleanup; + } + PToCString(deviceName, (char *) dev->name); + DBUG(("deviceName = %s\n", dev->name )); + result = (PaError) 1; + /* All done so close up device. */ +cleanup: + if( mRefNum ) SPBCloseDevice(mRefNum); + return result; + +error: + if( mRefNum ) SPBCloseDevice(mRefNum); + sPaHostError = err; + return paHostError; + +useless: + if( mRefNum ) SPBCloseDevice(mRefNum); + return (PaError) 0; +} + +/************************************************************************* +** Allocate a double array and fill it with listed sample rates. +*/ +static double * PaMac_GetSampleRatesFromHandle ( int numRates, Handle h ) +{ + OSErr err = noErr; + SInt8 hState; + int i; + UnsignedFixed *fixedRates; + double *rates = (double *) malloc( numRates * sizeof(double) ); /* MEM_011 */ + if( rates == NULL ) return NULL; + /* Save and restore handle state as suggested by TechNote at: + http://developer.apple.com/technotes/tn/tn1122.html + */ + hState = HGetState (h); + if (!(err = MemError ())) + { + HLock (h); + if (!(err = MemError ( ))) + { + fixedRates = (UInt32 *) *h; + for( i=0; i= Pa_CountDevices()) ) return NULL; + return &sDevices[id].pad_Info; +} +/*************************************************************************/ +PaDeviceID Pa_GetDefaultInputDeviceID( void ) +{ + return sDefaultInputDeviceID; +} + +/*************************************************************************/ +PaDeviceID Pa_GetDefaultOutputDeviceID( void ) +{ + return sDefaultOutputDeviceID; +} + +/**************************************************************************/ +static void StartLoadCalculation( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + UnsignedWide widePad; + if( pahsc == NULL ) return; + /* Query system timer for usage analysis and to prevent overuse of CPU. */ + Microseconds( &widePad ); + pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad ); +} + +/**************************************************************************/ +static void PaMac_EndLoadCalculation( internalPortAudioStream *past ) +{ + UnsignedWide widePad; + UInt64 CurrentCount; + long InsideCount; + long TotalCount; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + /* Measure CPU utilization during this callback. Note that this calculation + ** assumes that we had the processor the whole time. + */ +#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) + Microseconds( &widePad ); + CurrentCount = UnsignedWideToUInt64( widePad ); + if( past->past_IfLastExitValid ) + { + InsideCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_EntryCount); + TotalCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_LastExitCount); + /* Low pass filter the result because sometimes we get called several times in a row. + * That can cause the TotalCount to be very low which can cause the usage to appear + * unnaturally high. So we must filter numerator and denominator separately!!! + */ + past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * InsideCount)); + past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * TotalCount)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + } + pahsc->pahsc_LastExitCount = CurrentCount; + past->past_IfLastExitValid = 1; +} + +/*********************************************************************** +** Called by Pa_StartStream() +*/ +PaError PaHost_StartInput( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + pahsc->pahsc_IsRecording = 0; + pahsc->pahsc_StopRecording = 0; + pahsc->pahsc_InputMultiBuffer.nextWrite = 0; + pahsc->pahsc_InputMultiBuffer.nextRead = 0; + return PaMac_RecordNext( past ); +} + +/*********************************************************************** +** Called by Pa_StopStream(). +** May be called during error recovery or cleanup code +** so protect against NULL pointers. +*/ +PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) +{ + int32 timeOutMsec; + PaError result = paNoError; + OSErr err = 0; + long mRefNum; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + + (void) abort; + + mRefNum = pahsc->pahsc_InputRefNum; + + DBUG(("PaHost_StopInput: mRefNum = %d\n", mRefNum )); + if( mRefNum ) + { + DBUG(("PaHost_StopInput: pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording )); + if( pahsc->pahsc_IsRecording ) + { + /* PLB20010420 - Fix TIMEOUT in record mode. */ + pahsc->pahsc_StopRecording = 1; /* Request that we stop recording. */ + err = SPBStopRecording(mRefNum); + DBUG(("PaHost_StopInput: then pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording )); + + /* Calculate timeOut longer than longest time it could take to play one buffer. */ + timeOutMsec = (int32) ((1500.0 * pahsc->pahsc_FramesPerHostBuffer) / past->past_SampleRate); + /* Keep querying sound channel until it is no longer busy playing. */ + while( !err && pahsc->pahsc_IsRecording && (timeOutMsec > 0)) + { + Pa_Sleep(20); + timeOutMsec -= 20; + } + if( timeOutMsec <= 0 ) + { + ERR_RPT(("PaHost_StopInput: timed out!\n")); + return paTimedOut; + } + } + } + if( err ) + { + sPaHostError = err; + result = paHostError; + } + + DBUG(("PaHost_StopInput: finished.\n", mRefNum )); + return result; +} + +/***********************************************************************/ +static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader ) +{ + sndHeader->numChannels = past->past_NumOutputChannels; + sndHeader->sampleRate = DoubleToUnsignedFixed(past->past_SampleRate); + sndHeader->loopStart = 0; + sndHeader->loopEnd = 0; + sndHeader->encode = cmpSH; + sndHeader->baseFrequency = kMiddleC; + sndHeader->markerChunk = nil; + sndHeader->futureUse2 = nil; + sndHeader->stateVars = nil; + sndHeader->leftOverSamples = nil; + sndHeader->compressionID = 0; + sndHeader->packetSize = 0; + sndHeader->snthID = 0; + sndHeader->sampleSize = 8 * sizeof(int16); // FIXME - might be 24 or 32 bits some day; + sndHeader->sampleArea[0] = 0; + sndHeader->format = kSoundNotCompressed; +} + +/***********************************************************************/ +PaError PaHost_StartOutput( internalPortAudioStream *past ) +{ + SndCommand pauseCommand; + SndCommand resumeCommand; + int i; + OSErr error; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paInternalError; + if( pahsc->pahsc_Channel == NULL ) return paInternalError; + + past->past_StopSoon = 0; + past->past_IsActive = 1; + pahsc->pahsc_NumOutsQueued = 0; + pahsc->pahsc_NumOutsPlayed = 0; + pahsc->pahsc_NumFramesDone = 0.0; + + /* Pause channel so it does not do back ground processing while we are still filling the queue. */ + pauseCommand.cmd = pauseCmd; + pauseCommand.param1 = pauseCommand.param2 = 0; + error = SndDoCommand (pahsc->pahsc_Channel, &pauseCommand, true); + if (noErr != error) goto exit; + + /* Queue all of the buffers so we start off full. */ + for (i = 0; ipahsc_NumHostBuffers; i++) + { + PaMac_PlayNext( past, i ); + } + + /* Resume channel now that the queue is full. */ + resumeCommand.cmd = resumeCmd; + resumeCommand.param1 = resumeCommand.param2 = 0; + error = SndDoImmediate( pahsc->pahsc_Channel, &resumeCommand ); + if (noErr != error) goto exit; + + return paNoError; +exit: + past->past_IsActive = 0; + sPaHostError = error; + ERR_RPT(("Error in PaHost_StartOutput: SndDoCommand returned %d\n", error )); + return paHostError; +} + +/*******************************************************************/ +long PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + return (long) (pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer); +} + +/*********************************************************************** +** Called by Pa_StopStream(). +** May be called during error recovery or cleanup code +** so protect against NULL pointers. +*/ +PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) +{ + int32 timeOutMsec; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + if( pahsc->pahsc_Channel == NULL ) return paNoError; + + DBUG(("PaHost_StopOutput()\n")); + if( past->past_IsActive == 0 ) return paNoError; + + /* Set flags for callback function to see. */ + if( abort ) past->past_StopNow = 1; + past->past_StopSoon = 1; + /* Calculate timeOut longer than longest time it could take to play all buffers. */ + timeOutMsec = (int32) ((1500.0 * PaHost_GetTotalBufferFrames( past )) / past->past_SampleRate); + /* Keep querying sound channel until it is no longer busy playing. */ + while( past->past_IsActive && (timeOutMsec > 0)) + { + Pa_Sleep(20); + timeOutMsec -= 20; + } + if( timeOutMsec <= 0 ) + { + ERR_RPT(("PaHost_StopOutput: timed out!\n")); + return paTimedOut; + } + else return paNoError; +} + +/***********************************************************************/ +PaError PaHost_StartEngine( internalPortAudioStream *past ) +{ + (void) past; /* Prevent unused variable warnings. */ + return paNoError; +} + +/***********************************************************************/ +PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) +{ + (void) past; /* Prevent unused variable warnings. */ + (void) abort; /* Prevent unused variable warnings. */ + return paNoError; +} +/***********************************************************************/ +PaError PaHost_StreamActive( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + return (PaError) ( past->past_IsActive + pahsc->pahsc_IsRecording ); +} +int Mac_IsVirtualMemoryOn( void ) +{ + long attr; + OSErr result = Gestalt( gestaltVMAttr, &attr ); + DBUG(("gestaltVMAttr : 0x%x\n", attr )); + return ((attr >> gestaltVMHasPagingControl ) & 1); +} + +/******************************************************************* +* Determine number of WAVE Buffers +* and how many User Buffers we can put into each WAVE buffer. +*/ +static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + int32 minNumBuffers; + int32 minFramesPerHostBuffer; + int32 minTotalFrames; + int32 userBuffersPerHostBuffer; + int32 framesPerHostBuffer; + int32 numHostBuffers; + /* Calculate minimum and maximum sizes based on timing and sample rate. */ + minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer; + minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); + /* Determine number of user buffers based on minimum latency. */ + minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); + past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; + DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); + minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; + /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ + if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) + { + userBuffersPerHostBuffer = + (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / + past->past_FramesPerUserBuffer; + } + else + { + userBuffersPerHostBuffer = 1; + } + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + /* Make sure we have anough WAVE buffers. */ + if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) + { + numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; + } + else + { + /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ + while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) + { + userBuffersPerHostBuffer += 1; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + } + } + + pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; + pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; + pahsc->pahsc_NumHostBuffers = numHostBuffers; + DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); +} + +/*******************************************************************/ +PaError PaHost_OpenStream( internalPortAudioStream *past ) +{ + OSErr err; + PaError result = paHostError; + PaHostSoundControl *pahsc; + int i; + /* Allocate and initialize host data. */ + pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); + if( pahsc == NULL ) + { + return paInsufficientMemory; + } + past->past_DeviceData = (void *) pahsc; + + /* If recording, and virtual memory is turned on, then use bigger buffers to prevent glitches. */ + if( (past->past_NumInputChannels > 0) && Mac_IsVirtualMemoryOn() ) + { + pahsc->pahsc_MinFramesPerHostBuffer = MAC_VIRTUAL_FRAMES_PER_BUFFER; + } + else + { + pahsc->pahsc_MinFramesPerHostBuffer = MAC_PHYSICAL_FRAMES_PER_BUFFER; + } + + PaHost_CalcNumHostBuffers( past ); + + /* ------------------ OUTPUT */ + if( past->past_NumOutputChannels > 0 ) + { + /* Create sound channel to which we can send commands. */ + pahsc->pahsc_Channel = 0L; + err = SndNewChannel(&pahsc->pahsc_Channel, sampledSynth, 0, nil); /* FIXME - use kUseOptionalOutputDevice if not default. */ + if(err != 0) + { + ERR_RPT(("Error in PaHost_OpenStream: SndNewChannel returned 0x%x\n", err )); + goto error; + } + + /* Install our callback function pointer straight into the sound channel structure */ + /* Use new CARBON name for callback procedure. */ +#if TARGET_API_MAC_CARBON + pahsc->pahsc_OutputCompletionProc = NewSndCallBackUPP(PaMac_OutputCompletionProc); +#else + pahsc->pahsc_OutputCompletionProc = NewSndCallBackProc(PaMac_OutputCompletionProc); +#endif + + pahsc->pahsc_Channel->callBack = pahsc->pahsc_OutputCompletionProc; + + pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumOutputChannels * sizeof(int16); + for (i = 0; ipahsc_NumHostBuffers; i++) + { + char *buf = (char *)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer); + if (buf == NULL) + { + ERR_RPT(("Error in PaHost_OpenStream: could not allocate output buffer. Size = \n", pahsc->pahsc_BytesPerOutputHostBuffer )); + goto memerror; + } + + PaMac_InitSoundHeader( past, &pahsc->pahsc_SoundHeaders[i] ); + pahsc->pahsc_SoundHeaders[i].samplePtr = buf; + pahsc->pahsc_SoundHeaders[i].numFrames = (unsigned long) pahsc->pahsc_FramesPerHostBuffer; + + } + } +#ifdef SUPPORT_AUDIO_CAPTURE + /* ------------------ INPUT */ + /* Use double buffer scheme that matches output. */ + if( past->past_NumInputChannels > 0 ) + { + int16 tempS; + long tempL; + Fixed tempF; + long mRefNum; + unsigned char noname = 0; /* FIXME - use real device names. */ +#if TARGET_API_MAC_CARBON + pahsc->pahsc_InputCompletionProc = NewSICompletionUPP((SICompletionProcPtr)PaMac_InputCompletionProc); +#else + pahsc->pahsc_InputCompletionProc = NewSICompletionProc((ProcPtr)PaMac_InputCompletionProc); +#endif + pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumInputChannels * sizeof(int16); + for (i = 0; ipahsc_NumHostBuffers; i++) + { + char *buf = (char *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer); + if ( buf == NULL ) + { + ERR_RPT(("PaHost_OpenStream: could not allocate input buffer. Size = \n", pahsc->pahsc_BytesPerInputHostBuffer )); + goto memerror; + } + pahsc->pahsc_InputMultiBuffer.buffers[i] = buf; + } + pahsc->pahsc_InputMultiBuffer.numBuffers = pahsc->pahsc_NumHostBuffers; + + err = SPBOpenDevice( (const unsigned char *) &noname, siWritePermission, &mRefNum); /* FIXME - use name so we get selected device */ + // FIXME err = SPBOpenDevice( (const unsigned char *) sDevices[past->past_InputDeviceID].pad_Info.name, siWritePermission, &mRefNum); + if (err) goto error; + pahsc->pahsc_InputRefNum = mRefNum; + DBUG(("PaHost_OpenStream: mRefNum = %d\n", mRefNum )); + + /* Set input device characteristics. */ + tempS = 1; + err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS); + if (err) + { + ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siContinuous returned %d\n", err )); + goto error; + } + + tempL = 0x03; + err = SPBSetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL); + if (err) + { + DBUG(("PaHost_OpenStream: setting siActiveChannels returned 0x%x. Error ignored.\n", err )); + } + + /* PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. */ + tempS = past->past_NumInputChannels; + err = SPBSetDeviceInfo(mRefNum, siNumberChannels, (Ptr) &tempS); + if (err) + { + ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siNumberChannels returned %d\n", err )); + goto error; + } + + tempF = ((unsigned long)past->past_SampleRate) << 16; + err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF); + if (err) + { + ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siSampleRate returned %d\n", err )); + goto error; + } + + /* Setup record-parameter block */ + pahsc->pahsc_InputParams.inRefNum = mRefNum; + pahsc->pahsc_InputParams.milliseconds = 0; // not used + pahsc->pahsc_InputParams.completionRoutine = pahsc->pahsc_InputCompletionProc; + pahsc->pahsc_InputParams.interruptRoutine = 0; + pahsc->pahsc_InputParams.userLong = (long) past; + pahsc->pahsc_InputParams.unused1 = 0; + } +#endif /* SUPPORT_AUDIO_CAPTURE */ + DBUG(("PaHost_OpenStream: complete.\n")); + return paNoError; + +error: + PaHost_CloseStream( past ); + ERR_RPT(("PaHost_OpenStream: sPaHostError = 0x%x.\n", err )); + sPaHostError = err; + return paHostError; + +memerror: + PaHost_CloseStream( past ); + return paInsufficientMemory; +} + +/*********************************************************************** +** Called by Pa_CloseStream(). +** May be called during error recovery or cleanup code +** so protect against NULL pointers. +*/ +PaError PaHost_CloseStream( internalPortAudioStream *past ) +{ + PaError result = paNoError; + OSErr err = 0; + int i; + PaHostSoundControl *pahsc; + + DBUG(("PaHost_CloseStream( 0x%x )\n", past )); + + if( past == NULL ) return paBadStreamPtr; + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + + if( past->past_NumOutputChannels > 0 ) + { + /* TRUE means flush now instead of waiting for quietCmd to be processed. */ + if( pahsc->pahsc_Channel != NULL ) SndDisposeChannel(pahsc->pahsc_Channel, TRUE); + { + for (i = 0; ipahsc_NumHostBuffers; i++) + { + Ptr p = (Ptr) pahsc->pahsc_SoundHeaders[i].samplePtr; + if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerOutputHostBuffer ); + } + } + } + + if( past->past_NumInputChannels > 0 ) + { + if( pahsc->pahsc_InputRefNum ) + { + err = SPBCloseDevice(pahsc->pahsc_InputRefNum); + pahsc->pahsc_InputRefNum = 0; + if( err ) + { + sPaHostError = err; + result = paHostError; + } + } + { + for (i = 0; ipahsc_InputMultiBuffer.numBuffers; i++) + { + Ptr p = (Ptr) pahsc->pahsc_InputMultiBuffer.buffers[i]; + if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerInputHostBuffer ); + } + } + } + + past->past_DeviceData = NULL; + PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); + + DBUG(("PaHost_CloseStream: complete.\n", past )); + return result; +} +/*************************************************************************/ +int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) +{ + return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate ); +} +/*************************************************************************/ +static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerUserBuffer, double sampleRate ) +{ + int minUserPerHost = ( minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer; + int numBufs = PA_MIN_NUM_HOST_BUFFERS * minUserPerHost; + if( numBufs < PA_MIN_NUM_HOST_BUFFERS ) numBufs = PA_MIN_NUM_HOST_BUFFERS; + (void) sampleRate; + return numBufs; +} + +/*************************************************************************/ +void Pa_Sleep( int32 msec ) +{ + EventRecord event; + int32 sleepTime, endTime; + /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */ + sleepTime = ((msec * 60) + 999) / 1000; + if( sleepTime < 1 ) sleepTime = 1; + endTime = TickCount() + sleepTime; + do + { + DBUGX(("Sleep for %d ticks.\n", sleepTime )); + /* Use WaitNextEvent() to sleep without getting events. */ + /* PLB20010907 - Pass unused event to WaitNextEvent instead of NULL to prevent + * Mac OSX crash. Thanks Dominic Mazzoni. */ + WaitNextEvent( 0, &event, sleepTime, NULL ); + sleepTime = endTime - TickCount(); + } + while( sleepTime > 0 ); +} +/*************************************************************************/ +int32 Pa_GetHostError( void ) +{ + int32 err = sPaHostError; + sPaHostError = 0; + return err; +} + +/************************************************************************* + * 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 = NewPtrClear( numBytes ); + if( (addr == NULL) || (MemError () != 0) ) return NULL; + +#if (TARGET_API_MAC_CARBON == 0) + if( HoldMemory( addr, numBytes ) != noErr ) + { + DisposePtr( (Ptr) addr ); + return NULL; + } +#endif + 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 ) +{ + if( addr == NULL ) return; +#if TARGET_API_MAC_CARBON + (void) numBytes; +#else + UnholdMemory( addr, numBytes ); +#endif + DisposePtr( (Ptr) addr ); +} + +/*************************************************************************/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + PaHostSoundControl *pahsc; + internalPortAudioStream *past = (internalPortAudioStream *) stream; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + return pahsc->pahsc_NumFramesDone; +} + +/************************************************************************** +** Callback for Input, SPBRecord() +*/ +int gRecordCounter = 0; +int gPlayCounter = 0; +pascal void PaMac_InputCompletionProc(SPBPtr recParams) +{ + PaError result = paNoError; + int finished = 1; + internalPortAudioStream *past; + PaHostSoundControl *pahsc; + + gRecordCounter += 1; /* debug hack to see if engine running */ + + /* Get our PA data from Mac structure. */ + past = (internalPortAudioStream *) recParams->userLong; + if( past == NULL ) return; + + if( past->past_Magic != PA_MAGIC ) + { + AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, past", (long) past ); + AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, magic", (long) past->past_Magic ); + goto error; + } + pahsc = (PaHostSoundControl *) past->past_DeviceData; + past->past_NumCallbacks += 1; + + /* Have we been asked to stop recording? */ + if( (recParams->error == abortErr) || pahsc->pahsc_StopRecording ) goto error; + + /* If there are no output channels, then we need to call the user callback function from here. + * Otherwise we will call the user code during the output completion routine. + */ + if(past->past_NumOutputChannels == 0) + { + pahsc->pahsc_NumFramesDone += pahsc->pahsc_FramesPerHostBuffer; // Advance for recording + result = PaMac_CallUserLoop( past, NULL ); + } + + /* Did user code ask us to stop? If not, issue another recording request. */ + if( (result == paNoError) && (pahsc->pahsc_StopRecording == 0) ) + { + result = PaMac_RecordNext( past ); + if( result != paNoError ) pahsc->pahsc_IsRecording = 0; + } + else goto error; + + return; + +error: + pahsc->pahsc_IsRecording = 0; + pahsc->pahsc_StopRecording = 0; + return; +} + +/*********************************************************************** +** Called by either input or output completion proc. +** Grabs input data if any present, and calls PA conversion code, +** that in turn calls user code. +*/ +static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + int16 *inPtr = NULL; + int i; + + /* Advance read index for sound input FIFO here, independantly of record/write process. */ + if(past->past_NumInputChannels > 0) + { + if( MultiBuffer_IsReadable( &pahsc->pahsc_InputMultiBuffer ) ) + { + inPtr = (int16 *) MultiBuffer_GetNextReadBuffer( &pahsc->pahsc_InputMultiBuffer ); + MultiBuffer_AdvanceReadIndex( &pahsc->pahsc_InputMultiBuffer ); + } + } + + /* Call user code enough times to fill buffer. */ + if( (inPtr != NULL) || (outPtr != NULL) ) + { + StartLoadCalculation( past ); /* CPU usage */ + + for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) + { + result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr ); + if( result != 0) + { + /* Recording might be in another process, so tell it to stop with a flag. */ + pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording; + break; + } + /* Advance sample pointers. */ + if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels; + if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels; + } + + PaMac_EndLoadCalculation( past ); + } + return result; +} + +/*********************************************************************** +** Setup next recording buffer in FIFO and issue recording request to Snd Input Manager. +*/ +static PaError PaMac_RecordNext( internalPortAudioStream *past ) +{ + PaError result = paNoError; + OSErr err; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + /* Get pointer to next buffer to record into. */ + pahsc->pahsc_InputParams.bufferPtr = MultiBuffer_GetNextWriteBuffer( &pahsc->pahsc_InputMultiBuffer ); + + /* Advance write index if there is room. Otherwise keep writing same buffer. */ + if( MultiBuffer_IsWriteable( &pahsc->pahsc_InputMultiBuffer ) ) + { + MultiBuffer_AdvanceWriteIndex( &pahsc->pahsc_InputMultiBuffer ); + } + + AddTraceMessage("PaMac_RecordNext: bufferPtr", (long) pahsc->pahsc_InputParams.bufferPtr ); + AddTraceMessage("PaMac_RecordNext: nextWrite", pahsc->pahsc_InputMultiBuffer.nextWrite ); + + /* Setup parameters and issue an asynchronous recording request. */ + pahsc->pahsc_InputParams.bufferLength = pahsc->pahsc_BytesPerInputHostBuffer; + pahsc->pahsc_InputParams.count = pahsc->pahsc_BytesPerInputHostBuffer; + err = SPBRecord(&pahsc->pahsc_InputParams, true); + if( err ) + { + AddTraceMessage("PaMac_RecordNext: SPBRecord error ", err ); + sPaHostError = err; + result = paHostError; + } + else + { + pahsc->pahsc_IsRecording = 1; + } + return result; +} + +/************************************************************************** +** Callback for Output Playback() +** Return negative error, 0 to continue, 1 to stop. +*/ +long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index ) +{ + PaHostSoundControl *pahsc; + long result = 0; + int finished = 1; + char *outPtr; + + gPlayCounter += 1; /* debug hack */ + + past->past_NumCallbacks += 1; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return -1; + /* Are we nested?! */ + if( pahsc->pahsc_IfInsideCallback ) return 0; + pahsc->pahsc_IfInsideCallback = 1; + /* Get pointer to buffer to fill. */ + outPtr = pahsc->pahsc_SoundHeaders[index].samplePtr; + /* Combine with any sound input, and call user callback. */ + result = PaMac_CallUserLoop( past, (int16 *) outPtr ); + + pahsc->pahsc_IfInsideCallback = 0; + return result; +} + +/************************************************************************************* +** Called by SoundManager when ready for another buffer. +*/ +static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd) +{ + internalPortAudioStream *past; + PaHostSoundControl *pahsc; + (void) theChannel; + (void) theCallBackCmd; + + /* Get our data from Mac structure. */ + past = (internalPortAudioStream *) theCallBackCmd->param2; + if( past == NULL ) return; + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + pahsc->pahsc_NumOutsPlayed += 1; + pahsc->pahsc_NumFramesDone += pahsc->pahsc_FramesPerHostBuffer; + + PaMac_BackgroundManager( past, theCallBackCmd->param1 ); +} + +/*******************************************************************/ +static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + /* Has someone asked us to abort by calling Pa_AbortStream()? */ + if( past->past_StopNow ) + { + SndCommand command; + /* Clear the queue of any pending commands. */ + command.cmd = flushCmd; + command.param1 = command.param2 = 0; + SndDoImmediate( pahsc->pahsc_Channel, &command ); + /* Then stop currently playing buffer, if any. */ + command.cmd = quietCmd; + SndDoImmediate( pahsc->pahsc_Channel, &command ); + past->past_IsActive = 0; + } + /* Has someone asked us to stop by calling Pa_StopStream() + * OR has a user callback returned '1' to indicate finished. + */ + else if( past->past_StopSoon ) + { + if( (pahsc->pahsc_NumOutsQueued - pahsc->pahsc_NumOutsPlayed) <= 0 ) + { + past->past_IsActive = 0; /* We're finally done. */ + } + } + else + { + PaMac_PlayNext( past, index ); + } + return result; +} + +/************************************************************************************* +** Fill next buffer with sound and queue it for playback. +*/ +static void PaMac_PlayNext ( internalPortAudioStream *past, int index ) +{ + OSErr error; + long result; + SndCommand playCmd; + SndCommand callbackCmd; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + + /* If this was the last buffer, or abort requested, then just be done. */ + if ( past->past_StopSoon ) goto done; + /* Load buffer with sound. */ + result = PaMac_FillNextOutputBuffer ( past, index ); + if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */ + else if( result < 0 ) goto done; + /* Play the next buffer. */ + playCmd.cmd = bufferCmd; + playCmd.param1 = 0; + playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ]; + error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true ); + if( error != noErr ) goto gotError; + /* Ask for a callback when it is done. */ + callbackCmd.cmd = callBackCmd; + callbackCmd.param1 = index; + callbackCmd.param2 = (long)past; + error = SndDoCommand (pahsc->pahsc_Channel, &callbackCmd, true ); + if( error != noErr ) goto gotError; + pahsc->pahsc_NumOutsQueued += 1; + + return; + +gotError: + sPaHostError = error; +done: + return; +} diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c new file mode 100644 index 0000000..3dc4d74 --- /dev/null +++ b/pa_mac_core/pa_mac_core.c @@ -0,0 +1,1159 @@ +/* + * $Id$ + * pa_mac_core.c + * Implementation of PortAudio for Mac OS X Core Audio + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Authors: Ross Bencina and Phil Burk + * 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. + * + * CHANGE HISTORY: + + 3.29.2001 - Phil Burk - First pass... converted from Window MME code with help from Darren. + 3.30.2001 - Darren Gibbs - Added more support for dynamically querying device info. + 12.7.2001 - Gord Peters - Tweaks to compile on PA V17 and OS X 10.1 + */ +#include +#include +#include +#include +#include "portaudio.h" +#include "pa_host.h" +#include "pa_trace.h" + +/************************************************* Constants ********/ +#define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ +#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ + +/* Switches for debugging. */ +#define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ + +/* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ +#define PA_TRACE_RUN (0) +#define PA_TRACE_START_STOP (1) + +#define PA_MIN_MSEC_PER_HOST_BUFFER (10) +#define PA_MAX_MSEC_PER_HOST_BUFFER (100) /* Do not exceed unless user buffer exceeds */ +#define PA_MIN_NUM_HOST_BUFFERS (3) +#define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ +#define PA_MIN_LATENCY_MSEC (200) + +#define MIN_TIMEOUT_MSEC (1000) + +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) /* PRINT(x) */ +#define DBUGX(x) /* PRINT(x) */ + +/************************************************* Definitions ********/ + +/************************************************************** + * Structure for internal host specific stream data. + * This is allocated on a per stream basis. + */ +typedef struct PaHostSoundControl +{ + /* Input -------------- */ + int pahsc_BytesPerHostInputBuffer; + int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */ + /* Output -------------- */ + AudioDeviceID pahsc_OutputAudioDeviceID; + int pahsc_BytesPerHostOutputBuffer; + int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */ + /* Run Time -------------- */ + PaTimestamp pahsc_FramesPlayed; + long pahsc_LastPosition; /* used to track frames played. */ + /* For measuring CPU utilization. */ + // LARGE_INTEGER pahsc_EntryCount; + // LARGE_INTEGER pahsc_LastExitCount; + /* Init Time -------------- */ + int pahsc_NumHostBuffers; + int pahsc_FramesPerHostBuffer; + int pahsc_UserBuffersPerHostBuffer; + + // CRITICAL_SECTION pahsc_StreamLock; /* Mutext to prevent threads from colliding. */ + int pahsc_StreamLockInited; + +} +PaHostSoundControl; + +/************************************************* Shared Data ********/ +/* FIXME - put Mutex around this shared data. */ +static int sNumDevices = 0; +static PaDeviceInfo **sDevicePtrs = NULL; +static int sDefaultInputDeviceID = paNoDevice; +static int sDefaultOutputDeviceID = paNoDevice; +static int sPaHostError = 0; +static AudioDeviceID *sDeviceIDList; // Array of AudioDeviceIDs + +static const char sMapperSuffixInput[] = " - Input"; +static const char sMapperSuffixOutput[] = " - Output"; + +/************************************************* Macros ********/ + +/* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ +#define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) + +/************************************************* Prototypes **********/ + +static PaError Pa_QueryDevices( void ); +PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); +/********************************* 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. */ + // QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); +} + +static void Pa_EndUsageCalculation( internalPortAudioStream *past ) +{ +#if 0 + // LARGE_INTEGER CurrentCount = { 0, 0 }; + // LONGLONG InsideCount; + // LONGLONG TotalCount; + /* + ** Measure CPU utilization during this callback. Note that this calculation + ** assumes that we had the processor the whole time. + */ +#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) + + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + + if( QueryPerformanceCounter( &CurrentCount ) ) + { + if( past->past_IfLastExitValid ) + { + InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; + TotalCount = CurrentCount.QuadPart - pahsc->pahsc_LastExitCount.QuadPart; + /* Low pass filter the result because sometimes we get called several times in a row. + * That can cause the TotalCount to be very low which can cause the usage to appear + * unnaturally high. So we must filter numerator and denominator separately!!! + */ + past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * InsideCount)); + past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * TotalCount)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + } + pahsc->pahsc_LastExitCount = CurrentCount; + past->past_IfLastExitValid = 1; + } +#endif +} + +static PaDeviceID Pa_QueryDefaultDevice( int deviceEnum ) +{ + OSStatus err = noErr; + UInt32 count; + int i; + AudioDeviceID tempDevice = kAudioDeviceUnknown; + PaDeviceID defaultDeviceID; + + // get the default output device for the HAL + // it is required to pass the size of the data to be returned + count = sizeof(AudioDeviceID); + err = AudioHardwareGetProperty( deviceEnum, &count, (void *) &tempDevice); + if (err != noErr) goto Bail; + // find index of default device + defaultDeviceID = paNoDevice; + for( i=0; i= sNumDevices ) + return NULL; + + if( sDevicePtrs[ id ] != NULL ) + { + return sDevicePtrs[ id ]; + } + + deviceInfo = PaHost_AllocateFastMemory( sizeof(PaDeviceInfo) ); + if( deviceInfo == NULL ) return NULL; + + deviceInfo->structVersion = 1; + deviceInfo->maxInputChannels = 0; + deviceInfo->maxOutputChannels = 0; + deviceInfo->numSampleRates = -1; + + + // fill in format descriptor + if( id < sNumDevices ) + { + devID = sDeviceIDList[ id ]; + + // Get the device name + deviceInfo->name = deviceNameFromID( devID ); + + // Figure out supported sample rates + // Make room in case device supports all rates. + sampleRates = (double*)PaHost_AllocateFastMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); + deviceInfo->sampleRates = sampleRates; + deviceInfo->numSampleRates = 0; + + // Loop through the possible sampling rates and check each to see if the device supports it. + for (index = 0; index < MAX_NUMSAMPLINGRATES; index ++) + { + memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); + formatDesc.mSampleRate = possibleSampleRates[index]; + result = deviceDoesSupportFormat( devID, &formatDesc ); + + if (result == true) + { + deviceInfo->numSampleRates += 1; + *sampleRates = possibleSampleRates[index]; + sampleRates++; + } + } + + // Get data format info from the device. + deviceDataFormatFromID(devID, &formatDesc); + + deviceInfo->maxInputChannels = 0; // FIXME - Input and Output are separate devices! + deviceInfo->maxOutputChannels = formatDesc.mChannelsPerFrame; + + // FIXME - where to put current sample rate?: formatDesc.mSampleRate + + // Right now the Core Audio headers only define one formatID: LinearPCM + // Apparently LinearPCM must be Float32 for now. + // FIXME - + switch (formatDesc.mFormatID) + { + case kAudioFormatLinearPCM: + deviceInfo->nativeSampleFormats = paFloat32; + + // FIXME - details about the format are in these flags. + // formatDesc.mFormatFlags + + // here are the possibilities + // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer + // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little + // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer, + // only valid if kLinearPCMFormatFlagIsFloat is clear + // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible, + // clear if they are high or low aligned within the channel + // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed + + break; + default: + deviceInfo->nativeSampleFormats = paFloat32; // FIXME + break; + } + + } + + sDevicePtrs[ id ] = deviceInfo; + return deviceInfo; + + /* FIXME + error: + free( sampleRates ); + free( deviceInfo ); + */ + + return NULL; +} + +/************************************************************************* +** Returns recommended device ID. +** On the PC, the recommended device can be specified by the user 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 ID by using +** the supplied application "pa_devs". +*/ +#define PA_ENV_BUF_SIZE (32) +#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE") +#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE") + +static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) +{ +#if 0 + UInt32 hresult; + char envbuf[PA_ENV_BUF_SIZE]; + PaDeviceID recommendedID = paNoDevice; + + /* Let user determine default device by setting environment variable. */ + hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); + if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) + { + recommendedID = atoi( envbuf ); + } + + return recommendedID; +#endif + return paNoDevice; +} + +static PaError Pa_MaybeQueryDevices( void ) +{ + if( sNumDevices == 0 ) + { + return Pa_QueryDevices(); + } + return 0; +} + +/********************************************************************** +** Check for environment variable, else query devices and use result. +*/ +PaDeviceID Pa_GetDefaultInputDeviceID( void ) +{ + PaError result; + result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); + if( result < 0 ) + { + result = Pa_MaybeQueryDevices(); + if( result < 0 ) return result; + result = sDefaultInputDeviceID; + } + return result; +} + +PaDeviceID Pa_GetDefaultOutputDeviceID( void ) +{ + PaError result; + result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); + if( result < 0 ) + { + result = Pa_MaybeQueryDevices(); + if( result < 0 ) return result; + result = sDefaultOutputDeviceID; + } + return result; +} + +/********************************************************************** +** Initialize Host dependant part of API. +*/ + +PaError PaHost_Init( void ) +{ +#if PA_SIMULATE_UNDERFLOW + PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); +#endif + return Pa_MaybeQueryDevices(); +} + +/********************************************************************** +** Fill any available output buffers and use any available +** input buffers by calling user callback. +*/ +static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferList* inInputData, + AudioBufferList* outOutputData ) +{ + PaError result = 0; + char *inBufPtr; + char *outBufPtr; + int gotInput = 0; + int gotOutput = 0; + int i; + int buffersProcessed = 0; + int done = 0; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paInternalError; + + past->past_NumCallbacks += 1; + +#if PA_SIMULATE_UNDERFLOW + if(gUnderCallbackCounter++ == UNDER_SLEEP_AT) + { + Sleep(UNDER_SLEEP_FOR); + } +#endif + +#if PA_TRACE_RUN + AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks ); +#endif + + Pa_StartUsageCalculation( past ); + + /* If we are using output, then we need an empty output buffer. */ + gotOutput = 0; + if( past->past_NumOutputChannels > 0 ) + { + outBufPtr = outOutputData->mBuffers[0].mData, + gotOutput = 1; + } + + /* If we are using input, then we need a full input buffer. */ + gotInput = 0; + inBufPtr = NULL; + if( past->past_NumInputChannels > 0 ) + { + inBufPtr = inInputData->mBuffers[0].mData, + gotInput = 1; + } + + buffersProcessed += 1; + + /* Each host buffer contains multiple user buffers so do them all now. */ + for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) + { + if( done ) + { + if( gotOutput ) + { + /* Clear remainder of wave buffer if we are waiting for stop. */ + AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); + memset( outBufPtr, 0, pahsc->pahsc_BytesPerUserOutputBuffer ); + } + } + else + { + /* Convert 16 bit native data to user data and call user routine. */ + result = Pa_CallConvertFloat32( past, (float *) inBufPtr, (float *) outBufPtr ); + if( result != 0) done = 1; + } + if( gotInput ) inBufPtr += pahsc->pahsc_BytesPerUserInputBuffer; + if( gotOutput) outBufPtr += pahsc->pahsc_BytesPerUserOutputBuffer; + } + + Pa_EndUsageCalculation( past ); + +#if PA_TRACE_RUN + AddTraceMessage("Pa_TimeSlice: buffersProcessed ", buffersProcessed ); +#endif + + return (result != 0) ? result : done; +} + +OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* contextPtr) +{ + + PaError result = 0; + internalPortAudioStream *past; + PaHostSoundControl *pahsc; + past = (internalPortAudioStream *) contextPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + // Just Curious: printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers); + + /* Has someone asked us to abort by calling Pa_AbortStream()? */ + if( past->past_StopNow ) + { + past->past_IsActive = 0; /* Will cause thread to return. */ + } + /* Has someone asked us to stop by calling Pa_StopStream() + * OR has a user callback returned '1' to indicate finished. + */ + else if( past->past_StopSoon ) + { + // FIXME - pretend all done + past->past_IsActive = 0; /* Will cause thread to return. */ + } + else + { + /* Process full input buffer and fill up empty output buffers. */ + if( (result = Pa_TimeSlice( past, inInputData, outOutputData )) != 0) + { + /* User callback has asked us to stop. */ +#if PA_TRACE_START_STOP + AddTraceMessage( "Pa_OutputThreadProc: TimeSlice() returned ", result ); +#endif + past->past_StopSoon = 1; /* Request that audio play out then stop. */ + result = paNoError; + } + } + + // FIXME PaHost_UpdateStreamTime( pahsc ); + + return result; +} + +static int PaHost_CalcTimeOut( internalPortAudioStream *past ) +{ + /* Calculate timeOut longer than longest time it could take to play all buffers. */ + int timeOut = (UInt32) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate); + if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; + return timeOut; +} + +/*******************************************************************/ +PaError PaHost_OpenInputStream( internalPortAudioStream *past ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc; + int bytesPerInputFrame; + const PaDeviceInfo *pad; + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID)); + pad = Pa_GetDeviceInfo( past->past_InputDeviceID ); + if( pad == NULL ) return paInternalError; + + bytesPerInputFrame = Pa_GetSampleSize(pad->nativeSampleFormats) * past->past_NumInputChannels; + pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame; + pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer; + // FIXME + return result; +} + +/*******************************************************************/ +PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc; + const PaDeviceInfo *pad; + UInt32 bytesPerHostBuffer; + UInt32 dataSize; + UInt32 hardwareLatency = -1; + Boolean writeable = false; + OSStatus err = noErr; + int bytesPerOutputFrame; + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); + pad = Pa_GetDeviceInfo( past->past_OutputDeviceID ); + if( pad == NULL ) return paInternalError; + + pahsc->pahsc_OutputAudioDeviceID = sDeviceIDList[past->past_OutputDeviceID]; + + bytesPerOutputFrame = Pa_GetSampleSize(pad->nativeSampleFormats) * past->past_NumOutputChannels; + pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame; + pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer; + + // FIXME - force host buffer to user size + + // change the bufferSize of the device + bytesPerHostBuffer = past->past_OutputBufferSize; // FIXME + dataSize = sizeof(UInt32); + err = AudioDeviceSetProperty( pahsc->pahsc_OutputAudioDeviceID, 0, 0, false, + kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); + if( err != noErr ) + { + ERR_RPT(("Could not force buffer size!")); + result = paHostError; + goto error; + } + + // FIXME -- this isn't working for some reason. I can't figure out what the error code is. + dataSize = sizeof(UInt32); + err = AudioDeviceGetProperty(pahsc->pahsc_OutputAudioDeviceID, 0, false, kAudioDevicePropertyLatency, &dataSize, &writeable); + if( err != noErr ) + { + PRINT(("A CoreAudio error occurred: %s.\n", coreAudioErrorString( err ) )); + } + + err = AudioDeviceGetProperty(pahsc->pahsc_OutputAudioDeviceID, 0, false, kAudioDevicePropertyLatency, &dataSize, (void *)&hardwareLatency); + if ( err != noErr ) + { + PRINT(("A CoreAudio error occurred: %s.\n", coreAudioErrorString( err ) )); + } + else + { + PRINT(("Output Stream Hardware Latency = %d frames.\n", hardwareLatency )); + } + + return result; + +error: + return result; +} + +/*******************************************************************/ +PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer; +} + + +/******************************************************************* +* Determine number of WAVE Buffers +* and how many User Buffers we can put into each WAVE buffer. +*/ +void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = past->past_DeviceData; + unsigned int minNumBuffers; + int minFramesPerHostBuffer; + int maxFramesPerHostBuffer; + int minTotalFrames; + int userBuffersPerHostBuffer; + int framesPerHostBuffer; + int numHostBuffers; + + /* Calculate minimum and maximum sizes based on timing and sample rate. */ + minFramesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); + minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); + + maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); + maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer )); + + /* Determine number of user buffers based on minimum latency. */ + minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); + past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; + DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); + + minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; + + /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ + if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) + { + userBuffersPerHostBuffer = + (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / + past->past_FramesPerUserBuffer; + } + else + { + userBuffersPerHostBuffer = 1; + } + + + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + + /* Make sure we have anough WAVE buffers. */ + if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) + { + numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; + } + else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) && + ((int) past->past_FramesPerUserBuffer < (maxFramesPerHostBuffer/2) ) ) + { + /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ + while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) + { + userBuffersPerHostBuffer += 1; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + /* If we have gone too far, back up one. */ + if( (framesPerHostBuffer > maxFramesPerHostBuffer) || + (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) ) + { + userBuffersPerHostBuffer -= 1; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + break; + } + } + } + + pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; + pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; + pahsc->pahsc_NumHostBuffers = numHostBuffers; + + DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); +} + +/*******************************************************************/ +PaError PaHost_OpenStream( internalPortAudioStream *past ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc; + + /* 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; + + /* Figure out how user buffers fit into WAVE buffers. */ + // FIXME - just force for now + + pahsc->pahsc_UserBuffersPerHostBuffer = 1; + pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer; + pahsc->pahsc_NumHostBuffers = 2; // FIXME - dunno?! + + { + int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate); + PRINT(("PortAudio on OSX - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); + } + + /* ------------------ OUTPUT */ + if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) + { + result = PaHost_OpenOutputStream( past ); + if( result < 0 ) goto error; + } + + /* ------------------ INPUT */ + if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) ) + { + result = PaHost_OpenInputStream( past ); + if( result < 0 ) goto error; + } + + return result; + +error: + PaHost_CloseStream( past ); + return result; +} + +/*************************************************************************/ +PaError PaHost_StartOutput( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc; + PaError result = paNoError; + OSStatus err = noErr; + + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + if( past->past_OutputDeviceID != paNoDevice ) + { + // Associate an IO proc with the device and pass a pointer to the audio data context + err = AudioDeviceAddIOProc(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc, past); + if (err != noErr) goto error; + + // start playing sound through the device + err = AudioDeviceStart(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto error; + } + +error: + return result; +} + +/*************************************************************************/ +PaError PaHost_StartInput( internalPortAudioStream *past ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + if( past->past_InputDeviceID != paNoDevice ) + { + // FIXME + } + return result; +} + +/*************************************************************************/ +PaError PaHost_StartEngine( internalPortAudioStream *past ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + +#if PA_USE_TIMER_CALLBACK + int resolution; + int bufsPerTimerCallback; + int msecPerBuffer; +#endif /* PA_USE_TIMER_CALLBACK */ + + past->past_StopSoon = 0; + past->past_StopNow = 0; + past->past_IsActive = 1; + pahsc->pahsc_FramesPlayed = 0.0; + pahsc->pahsc_LastPosition = 0; + +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result ); +#endif + return result; +} + +/*************************************************************************/ +PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) +{ + int timeOut; + 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; + + timeOut = PaHost_CalcTimeOut( past ); + past->past_IsActive = 0; + + return paNoError; +} + +/*************************************************************************/ +PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; + + // FIXME + return paNoError; +} + +/*************************************************************************/ +PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) +{ + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; + +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); +#endif + + // FIXME if( pahsc->pahsc_OutputAudioDeviceID != ??? ) + { + OSStatus err = noErr; + + err = AudioDeviceStop(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto Bail; + + err = AudioDeviceRemoveIOProc(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto Bail; + } +Bail: + 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 PA_TRACE_START_STOP + AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); +#endif + /* Free data and device for output. */ + + /* Free data and device for input. */ + + free( pahsc ); + past->past_DeviceData = NULL; + + return paNoError; +} + +/************************************************************************* +** 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 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. +*/ +#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") + +int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) +{ + int minLatencyMsec = 0; + double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; + int minBuffers; + + /* Let user determine minimal latency by setting environment variable. */ + { + minLatencyMsec = PA_MIN_LATENCY_MSEC; + } + + DBUG(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); + minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); + if( minBuffers < 2 ) minBuffers = 2; + + return minBuffers; +} + +/************************************************************************* +** Cleanup device info. +*/ +PaError PaHost_Term( void ) +{ + int i; + + if( sNumDevices > 0 ) + { + + if( sDevicePtrs != NULL ) + { + + for( i=0; iname ); + free( (void*)sDevicePtrs[i]->sampleRates ); + free( sDevicePtrs[i] ); + } + } + + free( sDevicePtrs ); + sDevicePtrs = NULL; + } + + sNumDevices = 0; + } + return paNoError; +} + +/*************************************************************************/ +void Pa_Sleep( long msec ) +{ + /* struct timeval timeout; + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + select( 0, NULL, NULL, NULL, &timeout ); + */ + usleep( msec * 1000 ); +} + +/************************************************************************* + * 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 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 ) +{ + 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; +} + +/*************************************************************************/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + PaHostSoundControl *pahsc; + internalPortAudioStream *past = (internalPortAudioStream *) stream; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + // FIXME PaHost_UpdateStreamTime( pahsc ); + return pahsc->pahsc_FramesPlayed; +} diff --git a/pa_sgi/Makefile b/pa_sgi/Makefile new file mode 100644 index 0000000..c631c9b --- /dev/null +++ b/pa_sgi/Makefile @@ -0,0 +1,52 @@ +# Make PortAudio for Silicon Graphics IRIX (6.2) +# Pieter suurmond, august 17, 2001. (v15 pa_sgi sub-version #0.04) + +# Instead of "-lpthread", as with linux, +# just the audio- and math-library for SGI: +LIBS = -laudio -lm + +CDEFINES = -I../pa_common + +# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64, +# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging. +# And use for example -O2 or -O3 for better optimization: +CFLAGS = -O2 +PASRC = ../pa_common/pa_lib.c pa_sgi.c +PAINC = ../pa_common/portaudio.h + +# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). +#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK +TESTC = $(PASRC) ../pa_tests/patest_record.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches. +#TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?). +#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK +#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. + +# Tests that do not yet work. +#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default +#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default +#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-( + # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH. + # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON??? + # HMMM I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS! +TESTH = $(PAINC) + +all: patest + +#(cc may be changed to gcc) +patest: $(TESTC) $(TESTH) Makefile + cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest + +run: patest + ./patest + diff --git a/pa_sgi/pa_sgi.c b/pa_sgi/pa_sgi.c new file mode 100644 index 0000000..094cb4d --- /dev/null +++ b/pa_sgi/pa_sgi.c @@ -0,0 +1,991 @@ +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * SGI IRIX implementation by Pieter Suurmond, aug 17, 2001. + * + * 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. + */ +/* +Modfication History: + 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. + 8/17/2001 - (v15 pa_sgi sub-version #0.04), wow, much is working now! Send this to Phil & Ross. + ID-stuff is nicer here now than in the linux_oss-alpha-version, v15. Was able to get + rid of a number of globals (like "sNumDevices" for instance). +TODO: + - Test under IRIX 6.5. + - Maybe use pthread instead of (platform-specific) poll/select/pollfd-calls. + (As Gary Scavone more or less suggested(?)... But can I get enough process-control then?) + - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), + and maybe also the other natively supported formats? (might increase performance) + - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet, + seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?) + - Make sure that the fuzz-test doesn't let all IRIX crash (especially with higher buff-sizes). + - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4. +REFERENCES: + - IRIX 6.2 man pages regarding SGI AL library. + - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and + may not be publically available on the internet). +*/ + +#include /* Standard libraries. */ +#include +#include +#include +#include + +#include "portaudio.h" /* Portaudio headers. */ +#include "pa_host.h" +#include "pa_trace.h" + +#include /* System specific (IRIX 6.2). */ +#include +#include +#include +#include /* fcntl.h needed. */ +#include /* For streams, ioctl(), etc. */ +#include +#include +#include +#include +#include + +/*--------------------------------------------*/ +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) PRINT(x) +#define DBUGX(x) /* PRINT(x) */ + +#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */ +#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */ + +typedef struct internalPortAudioDevice /* IRIX specific device info: */ +{ + PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ + long pad_ALdevice; /* SGI-number! */ + double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ + char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ + PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ + /* int structVersion; */ + /* const char* name; */ + /* int maxInputChannels, maxOutputChannels; */ + /* int numSampleRates; Num rates, or -1 if range supprtd. */ + /* const double* sampleRates; Array of supported sample rates, */ + /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ + struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ +} +internalPortAudioDevice; + +typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */ +{ + ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ + pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ + int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ + short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ + *pahsc_NativeOutputBuffer; + unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ + pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ + unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ + pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ + struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ + pahsc_LastExitTime; + long pahsc_InsideCountSum, + pahsc_TotalCountSum; +} +PaHostSoundControl; + +/*----------------------------- Shared Data ------------------------------------------------------*/ +static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ +static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ + +/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ +/* (copied from source pa_linux_oss/pa_linux_oss.c) */ +static void Pa_StartUsageCalculation( internalPortAudioStream *past ) +{ + struct itimerval itimer; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + /* Query system timer for usage analysis and to prevent overuse of CPU. */ + getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); +} + +static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) +{ + long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; + long usecs = secs * 1000000; + usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); + return usecs; +} + +static void Pa_EndUsageCalculation( internalPortAudioStream *past ) +{ + struct itimerval currentTime; + long insideCount; + long totalCount; /* Measure CPU utilization during this callback. */ + +#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 (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) + { + if (past->past_IfLastExitValid) + { + insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); + pahsc->pahsc_InsideCountSum += insideCount; + totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); + pahsc->pahsc_TotalCountSum += totalCount; + /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ + /* Low pass filter the result because sometimes we get called several times in a row. */ + /* That can cause the TotalCount to be very low which can cause the usage to appear */ + /* unnaturally high. So we must filter numerator and denominator separately!!! */ + if (pahsc->pahsc_InsideCountSum > 0) + { + past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); + past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + pahsc->pahsc_InsideCountSum = 0; + pahsc->pahsc_TotalCountSum = 0; + } + } + past->past_IfLastExitValid = 1; + } + pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; + pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; + setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); + past->past_IfLastExitValid = 1; +} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ + + +/*--------------------------------------------------------------------------------------*/ +PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */ +{ /* call to report via ERR_RPT(), yields a PaError-num. */ + const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ + switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ + { + case AL_BAD_OUT_OF_MEM: + ERR_RPT(("%sout of memory.\n", a)); + return paInsufficientMemory; /* Known PaError. */ + case AL_BAD_CONFIG: + ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_CHANNELS: + ERR_RPT(("%schannels not 1,2 or 4.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_NO_PORTS: + ERR_RPT(("%sout of audio ports.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DEVICE: + ERR_RPT(("%swrong device number.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DEVICE_ACCESS: + ERR_RPT(("%swrong device access.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DIRECTION: + ERR_RPT(("%sinvalid direction.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_SAMPFMT: + ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_FLOATMAX: + ERR_RPT(("%smax float value is zero.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_WIDTH: + ERR_RPT(("%sunsupported samplewidth.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_QSIZE: + ERR_RPT(("%sinvalid queue size.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_PVBUFFER: + ERR_RPT(("%sPVbuffer null.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_BUFFERLENGTH_NEG: + ERR_RPT(("%snegative bufferlength.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_BUFFERLENGTH_ODD: + ERR_RPT(("%sodd bufferlength.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_PARAM: + ERR_RPT(("%sparameter not valid for device.\n", a)); + return paHostError; /* Generic PaError. */ + default: + ERR_RPT(("%sunknown error.\n", a)); + return paHostError; /* Generic PaError. */ + } +} + +/*------------------------------------------------------------------------------------------*/ +/* Tries to set various rates and formats and fill in the device info structure. */ +static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */ + PaDeviceID id, /* (DefaultI|ODeviceID()) */ + char* name, /* (for example "SGI AL") */ + internalPortAudioDevice* pad) /* Result written to pad. */ +{ + int format; + long min, max; /* To catch hardware characteristics. */ + ALseterrorhandler(0); /* 0 = turn off the default error handler. */ + /*--------------------------------------------------------------------------------------*/ + pad->pad_ALdevice = ALdev; /* Set the AL device number. */ + pad->pad_DeviceID = id; /* Set the PA device number. */ + if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ + { + ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); + return paHostError; + } + strcpy(pad->pad_DeviceName, name); /* Write name-string. */ + pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ + /*--------------------------------- natively supported sample formats: -----------------*/ + pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ + /* Then also choose other CallConvertXX()! */ + /*--------------------------------- number of available i/o channels: ------------------*/ + if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) + return translateSGIerror(); + pad->pad_Info.maxInputChannels = max; + DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) + if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) + return translateSGIerror(); + pad->pad_Info.maxOutputChannels = max; + DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) + /*--------------------------------- supported samplerates: ----------------------*/ + pad->pad_Info.numSampleRates = 7; + pad->pad_Info.sampleRates = pad->pad_SampleRates; + pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ + pad->pad_SampleRates[1] = (double)AL_RATE_11025; + pad->pad_SampleRates[2] = (double)AL_RATE_16000; + pad->pad_SampleRates[3] = (double)AL_RATE_22050; + pad->pad_SampleRates[4] = (double)AL_RATE_32000; + pad->pad_SampleRates[5] = (double)AL_RATE_44100; + pad->pad_SampleRates[6] = (double)AL_RATE_48000; + if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */ + return translateSGIerror(); /* double -> long. */ + if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */ + goto weird; + if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ + return translateSGIerror(); + if (max != (long)(0.5 + pad->pad_SampleRates[6])) + { +weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); + return paHostError; /* Or make it a warning and just carry on... */ + } + /*-------------------------------------------------------------------------------*/ + return paNoError; +} + + +/*--------------------------------------------------------------------------------*/ +int Pa_CountDevices() /* Name of this function suggests it only counts and */ +{ /* is NOT destructive, it however resets whole PA ! */ + int numDevices = 0; /* Let 's not do that here. */ + internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ +#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ + if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */ + Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ +#endif /* friendly to clients that forgot to initialize PA. */ + while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ + { + numDevices++; + currentDevice = currentDevice->pad_Next; + } + return numDevices; +} + + + +/*-------------------------------------------------------------------------------*/ +static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) +{ + int numDevices = 0; + internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; + internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ + while (pad) /* pad may be NULL, that's ok, return 0. */ + { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ + if (pad->pad_DeviceID == id) /* This the device we were looking for? */ + res = pad; /* But keep on(!) counting so we don't */ + numDevices++; /* have to call Pa_CountDevices() later. */ + pad = pad->pad_Next; /* Advance to the next device or NULL. */ + } /* No assumptions about order of ID's in */ + if (!res) /* the list. */ + ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); + if ((id < 0) || (id >= numDevices)) + { + ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); +#if 1 /* Be strict, even when found, */ + res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ +#endif + + } + return res; +} + +/*----------------------------------------------------------------------*/ +const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) +{ + PaDeviceInfo* res = (PaDeviceInfo*)NULL; + internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ + if (pad) + res = &pad->pad_Info; /* Not finding the specified ID is not */ + if (!res) /* the same as &pad->pad_Info == NULL. */ + ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); + return res; /* So (maybe) a second/third ERR_RPT(). */ +} + +/*------------------------------------------------*/ +PaDeviceID Pa_GetDefaultInputDeviceID(void) +{ + return 0; /* 0 is the default device ID. */ +} +/*------------------------------------------------*/ +PaDeviceID Pa_GetDefaultOutputDeviceID(void) +{ + return 0; +} + +/*--------------------------------------------------------------------------------------*/ +/* Build linked list with all available audio devices on this SGI machine. */ +PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ +{ + internalPortAudioDevice* pad; + PaError r = paNoError; + int audioLibFileID; + + if (sDeviceList) /* Allow re-init, only warn, no err. */ + { + ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); + return r; + } + /*------------- ADD THE SGI DEFAULT DEVICES TO THE LIST: --------------------------------------*/ + audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ + if (audioLibFileID < 0) /* IO port. On failure, machine */ + { /* has no audio ability. */ + ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); + return paHostError; + } + close(audioLibFileID); /* Allocate fast mem to hold device info. */ + pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); + if (pad == NULL) + return paInsufficientMemory; + memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ + r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ + Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ + "AL default", /* A suitable name. */ + pad); /* Write args and queried info into pad. */ + if (r != paNoError) + { + ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); + PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ + } + else + sDeviceList = pad; /* First element in linked list (pad->pad_Next is already NULL). */ + /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LIST: --------------*/ + /*---------------------------------------------------------------------------------*/ + return r; +} + +/*------------------------------------------------------------------*/ +usema_t *SendSema, /* These variables are shared between the audio */ +*RcvSema; /* handling process and the main process. */ + +/*--------------------------------------------------------------------------------------------*/ +#define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */ +#define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */ +#define kPollOUT 1 /* numbers. */ +#define kPollIN 2 +void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */ +{ /* as a separate thread. (Argument must be void*). */ + short evtLoop=1; /* Reset by parent indirectly, or at local errors. */ + PaError result; + struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */ + internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument.*/ + PaHostSoundControl *pahsc = (PaHostSoundControl*)past->past_DeviceData; + if (pahsc == NULL) + { + sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */ + goto skipALL; /* Sproc-ed threads MAY NOT RETURN paInternalError. */ + } + past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ + DBUG(("entering thread.\n")); + PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */ + PollFD[kPollIN].events = POLLOUT; /* such as ALport not there. */ + /* .events = POLLOUT ??? ok? */ + PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT); + PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */ + schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */ + PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */ + PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */ + uspsema(SendSema); /* Blocks until the next (first)signal is received???? */ + do + { + /*---------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ----------*/ + if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */ + /* For input port, fill point is number of locations in the sample queue that must be */ + /* filled in order to trigger a return from select(). (or poll()) */ + /* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/ + if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputBuffer)) + { /* Same amount as transferred per time. */ + ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n")); + sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ + goto skipIO; + } + if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */ + /* For output port, fill point is number of locations that must be free in order to */ + /* wake up from select(). (or poll()) */ + if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputBuffer)) + { + ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n")); + sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ + goto skipIO; + } /* poll() with timeout=-1 makes it block until a requested */ + poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */ + /* array <0, events is ignored and revents is set to 0. */ + /*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/ + if (PollFD[kPollSEMA].revents & POLLIN) + { + if (past->past_StopNow || past->past_StopSoon) + evtLoop = 0; + uspsema(SendSema); /* Decrements count of previously allocated semaphore SendSema. If count */ + /* is then negative, semaphore will logically block calling process until */ + /* count is incremented due to an usvsema call made by another process. */ + usvsema(RcvSema); /* Increments the count associated with RcvSema. If there are any */ + /* processes queued waiting for the semaphore the first one is awakened. */ + /* Here usvsema sends an acknowledgement to the "SendAudioCommand()". */ + if (past->past_StopNow) + goto skipIO; /* Else go on for a little while... */ + } + /*------------------------------------- FREE-EVENT FROM INPUT BUFFER: ----------------------------*/ + if (PollFD[kPollIN].revents & POLLOUT) /* Don't need to check (pahsc->pahsc_NativeInputBuffer): */ + { /* if buffer was not there, ALport not there, no events! */ + if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer, + pahsc->pahsc_SamplesPerInputBuffer)) + { /* Here again: number of samples instead of number of frames. */ + ERR_RPT(("ALreadsamps() failed.\n")); + sPaHostError = paInternalError; + goto skipIO; /* (Using exit(-1) would be a bit rude.) */ + } + } + /*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/ + if ((PollFD[kPollIN].revents & POLLOUT) || (PollFD[kPollOUT].revents & POLLOUT)) + { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */ + /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */ + Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ + result = Pa_CallConvertInt16(past, /* user data and call user routine. */ + pahsc->pahsc_NativeInputBuffer, + pahsc->pahsc_NativeOutputBuffer); + Pa_EndUsageCalculation(past); + if (result) + { + DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); + goto skipIO; /* But it is apparently NOT an error! */ + } /* Just letting the userCallBack stop us. */ + } + /*------------------------------------- FILLED-EVENT FROM OUTPUT BUFFER: -------------------------*/ + if (PollFD[kPollOUT].revents & POLLOUT) /* Don't need to check (pahsc->pahsc_NativeOutputBuffer) */ + { /* because if filedescriptor not there, no event for it. */ + if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer, + pahsc->pahsc_SamplesPerOutputBuffer)) + { + ERR_RPT(("ALwritesamps() failed.\n")); + sPaHostError = paInternalError; /* Better use SEMAS also for messaging back to parent! */ + goto skipIO; + } + } + /*------------------------------------------------------------------------------------------------*/ + } + while (evtLoop); /* Set at init-time, only reset indirectly via semaphore, */ +skipIO: /* or in case of error, only within this loop. */ + DBUG(("leaving thread.\n")); /* Don't we need to cleanup semaphore-stuff / thread itself? */ +skipALL: /* (make threadPID in the struct -1 again, for instance?) */ + past->past_IsActive = 0; + pahsc->pahsc_threadPID == -1; /* Signal back, so StopEngine() for example won't call KILL().... hmmm doesn't work yet! */ + /* SHIT: when this process ends, it also KILLS of the parent!!! because sigint = kill?? */ + exit(0); /* Unix process. SIGCLD is sent to parent (if prctl wa called with 0 by parent). */ +} /* if prctl was called with 9 by parent, then when this process ends, it also */ +/* KILLS off the parent!!! */ + +/*--------------------------------------------------------------------------------------*/ +PaError PaHost_OpenStream(internalPortAudioStream *past) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc; + unsigned int minNumBuffers; + internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ + ALconfig sgiALconfig = NULL; /* IRIX-datatype. */ + long pvbuf[8]; /* To get/set hardware configs. */ + long sr, ALqsize; + DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ + if (!past) + { + ERR_RPT(("Streampointer NULL!\n")); + result = paBadStreamPtr; goto done; + } + pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); + if (pahsc == NULL) + { + ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ + result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ + } + memset(pahsc, 0, sizeof(PaHostSoundControl)); /* Hmmm, not too elegant, besides, the */ + pahsc->pahsc_threadPID = -1; /* pahsc_threadPID must be inited to */ + past->past_DeviceData = (void*)pahsc; /* -1 instead of 0! ?? */ + /*--------------------------------------------------- Allocate native buffers: --------*/ + pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumInputChannels; /* audio-thread. */ + pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); + if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */ + { + pahsc->pahsc_NativeInputBuffer = (short *) malloc(pahsc->pahsc_BytesPerInputBuffer); + if( pahsc->pahsc_NativeInputBuffer == NULL ) + { + ERR_RPT(("(normal yet) Memory allocation failed.\n")); + result = paInsufficientMemory; + goto done; + } + } + pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumOutputChannels; /* audio-thread. */ + pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); + if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */ + { + pahsc->pahsc_NativeOutputBuffer = (short *) malloc(pahsc->pahsc_BytesPerOutputBuffer); + if (pahsc->pahsc_NativeOutputBuffer == NULL) + { + ERR_RPT(("(normal yet) Memory allocation failed.\n")); + result = paInsufficientMemory; goto done; + } + } + /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ + ALseterrorhandler(0); /* 0 = turn off the default error handler. */ + pvbuf[0] = AL_INPUT_RATE; + pvbuf[2] = AL_INPUT_COUNT; + pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ + pvbuf[6] = AL_OUTPUT_COUNT; + sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */ + if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ + { /* sponding native AL-number(s). */ + padIN = Pa_GetInternalDevice(past->past_InputDeviceID); + if (!padIN) + { + ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); + result = paHostError; goto done; + } + if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ + goto sgiError; /* the same AL-device, the AL-library might */ + if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ + { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ + if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ + { + ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ + another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); + result = paHostError; goto done; + } + pvbuf[1] = sr; /* Then set input-rate. */ + if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) + goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ + } + } + if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels<=0! */ + { /* We use padOUT/IN later on, or at least 1 of both. */ + padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); + if (!padOUT) + { + ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); + result = paHostError; goto done; + } + if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) + goto sgiError; + if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr)) + { /* Output needed and rate different from current harware-rate. */ + if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ + { + ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ + another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); + result = paHostError; goto done; /* Will free again the inputbuffer */ + } /* that was just created above. */ + pvbuf[5] = sr; /* Then set output-rate. */ + if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) + goto sgiError; + } + } + /*------------------------------------------ Construct an audio-port-configuration ----------*/ + sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */ + if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */ + goto sgiError; /* See that sgiALconfig is NOT released! */ + if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ + goto sgiError; + if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */ + goto sgiError; /* config is set to two's complement format. */ + /************************ Future versions might (dynamically) switch to 32-bit floats? ******* + if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) + goto sgiError; + if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config + goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ + /*---------- ?? --------------------*/ + /* 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; + /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/ + if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer) + ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer; + else /* Take the largest of the two amounts. */ + ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer; + ALqsize *= 4; /* 4 times as large as amount per transfer! */ + if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */ + goto sgiError; /* Using 2 times may give glitches... */ + /* Have to work on ALsetqueuesize() above, fillpoints in the thread are ok now. */ + + /* Do ALsetchannels() later, apart per input and/or output. */ + /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/ + if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */ + { + if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) + { + DBUG(("PaHost_OpenStream: opening both input and output channels.\n")); + /*------------------------- open output port: ----------------------------------*/ + if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); + if (pahsc->pahsc_ALportOUT == (ALport)0) + goto sgiError; + /*------------------------- open input port: -----------------------------------*/ + if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); + if (pahsc->pahsc_ALportIN == (ALport)0) + goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */ + } /* Probably due to too small buffersizes?.... */ + else + { + ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); + result = paHostError; + goto done; + } + } + else /* (OutputDeviceID != InputDeviceID) */ + { + if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */ + { + /*------------------------- open output port: ----------------------------------*/ + DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n", + past->past_NumOutputChannels, padOUT->pad_DeviceName)); + if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); + if (pahsc->pahsc_ALportOUT == (ALport)0) + goto sgiError; + } + if (past->past_NumInputChannels > 0) /* READ-ONLY: */ + { + /*------------------------- open input port: -----------------------------------*/ + DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n", + past->past_NumInputChannels, padIN->pad_DeviceName)); + if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); + if (pahsc->pahsc_ALportIN == (ALport)0) + goto sgiError; + } + } + DBUG(("PaHost_OpenStream() succeeded.\n")); + goto done; /* (no errors occured) */ +sgiError: + result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ +done: + if (sgiALconfig) + ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */ + if (result != paNoError) + PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ + return result; +} + +/*-----------------------------------------------------*/ +PaError PaHost_StartOutput(internalPortAudioStream *past) +{ + return paNoError; /* Hmm, not implemented yet? */ +} +PaError PaHost_StartInput(internalPortAudioStream *past) +{ + return paNoError; +} + +/*------------------------------------------------------------------------------*/ +PaError PaHost_StartEngine(internalPortAudioStream *past) +{ + PaHostSoundControl *pahsc; + usptr_t *arena; + if (!past) /* Test argument. */ + { + ERR_RPT(("PaHost_StartEngine(NULL)!\n")); + return paBadStreamPtr; + } + pahsc = (PaHostSoundControl*)past->past_DeviceData; + if (!pahsc) + { + ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n")); + return paHostError; + } + past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ + past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */ + past->past_IsActive = 1; + + /* Although the pthread_create() function, as well as , may be */ + /* available in IRIX, use sproc() on SGI to create audio-background-thread. */ + /* (Linux/oss uses pthread_create() instead of __clone() because: */ + /* - pthread_create also works for other UNIX systems like Solaris, */ + /* - Java HotSpot VM crashes in pthread_setcanceltype() using __clone().) */ + + usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* (From SGI-AL-examples, file */ + arena = usinit(tmpnam(0)); /* motifexample.c, function */ + SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */ + RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process + will be permitted through a semaphore at a time. Values > 1 + imply that up to val resources may be simultaneously used, but requests + for more than val resources cause the calling process to block until a + resource comes free (by a process holding a resource performing a + usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */ + prctl(PR_SETEXITSIG, 0);/* No not (void*)9, but 0, which doesn't kill the parent! */ + /* PR_SETEXITSIG controls whether all members of a share group will be + signaled if any one of them leaves the share group + (either via exit() or exec()). If second + argument, interpreted as an int is 0, then normal IRIX + process termination rules apply, namely that the parent + is sent a SIGCLD upon death of child, but no indication + of death of parent is given. If the second argument is + a valid signal number then if any member + of a share group leaves the share group, a signal is + sent to ALL surviving members of the share group. */ + /* SPAWN AUDIO-CHILD: */ + pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */ + PR_SALL, /* new process, or -1. */ + (void*)past); /* Pass past as optional */ + if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ + { + ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); + sPaHostError = oserror(); /* Pass native error-number to shared area. */ + return paHostError; /* But return the generic error-number. */ + } + return paNoError; /* Hmmm, errno may come from other threads in same group! */ +} /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */ + +/*------------------------------------------------------------------------------*/ +PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) +{ + int hres; + long timeOut; + PaError result = paNoError; + PaHostSoundControl *pahsc = (PaHostSoundControl*)past->past_DeviceData; + + if (pahsc == NULL) + return result; /* paNoError */ + past->past_StopSoon = 1; /* Tell background thread to stop generating */ + if (abort) /* more and to let current data play out. If */ + past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ + + /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/ + usvsema(SendSema); /* Increments count associated with SendSema. */ + /* Wait for the response. */ + uspsema(RcvSema); /* Decrements count of previously allocated */ + /* semaphore specified by RcvSema. */ + /* Must be sure sub-process is really there,... otherwise above semas block?! */ + if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */ + { + /* How to JOIN a "sproc"-thread to recover memory resources????? */ + /* hres = pthread_join( pahsc->pahsc_ThreadPID, NULL ); */ + DBUG(("PaHost_StopEngine() is about to KILL(SIGKILL) audio-thread.\n")); + if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */ + { /* Returns -1 in case of error. */ + result = paHostError; + sPaHostError = oserror(); /* Hmmm, other threads may also write here! */ + ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n")); + } + else + pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */ + } + past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */ + return result; +} + +/*---------------------------------------------------------------*/ +PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) +{ + return paNoError; /* Not implemented yet? */ +} +PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) +{ + return paNoError; +} + +/*******************************************************************/ +PaError PaHost_CloseStream(internalPortAudioStream *past) +{ + PaHostSoundControl *pahsc; + PaError result = paNoError; + + if (past == NULL) + return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ + return result; /* This test prevents from freeing NULL-pointers. */ + + if (pahsc->pahsc_ALportIN) + { + if (ALcloseport(pahsc->pahsc_ALportIN)) + result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ + else /* But go on anyway... to release other stuff... */ + pahsc->pahsc_ALportIN = (ALport)0; + } + if (pahsc->pahsc_ALportOUT) + { + if (ALcloseport(pahsc->pahsc_ALportOUT)) + result = translateSGIerror(); + else + pahsc->pahsc_ALportOUT = (ALport)0; + } + if (pahsc->pahsc_NativeInputBuffer) + { + free(pahsc->pahsc_NativeInputBuffer); + pahsc->pahsc_NativeInputBuffer = NULL; + } + if (pahsc->pahsc_NativeOutputBuffer) + { + free(pahsc->pahsc_NativeOutputBuffer); + pahsc->pahsc_NativeOutputBuffer = NULL; + } + PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); /* Not just free(pahsc) because */ + past->past_DeviceData = NULL; /* PaHost_OpenStream(); allocated FAST (thus mpinned?) MEM. */ + 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 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. +*/ +#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") + +int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) +{ + return 2; +} +/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */ +/* Do we HAVE to do it this way under IRIX???.... */ +/*--------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------*/ +PaError PaHost_Term(void) /* Frees all of the linked devices. */ +{ /* Called by Pa_Terminate() from pa_lib.c. */ + internalPortAudioDevice *pad = sDeviceList, + *nxt; + while (pad) + { + DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); + nxt = pad->pad_Next; + PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); + pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ + } + sDeviceList = (internalPortAudioDevice*)NULL; + return 0; /* Got rid of sNumDevices=0; */ +} + +/***********************************************************************/ +void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ +{ +#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 physi- */ +/* cal 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); /* mpin() reads into memory all pages over the given */ + if (addr) /* range and locks the pages into memory. A counter */ + { /* is incremented each time the page is locked. The */ + if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */ + { /* others are limited to the configurable PLOCK_MA. */ + ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n")); +#if 1 + free(addr); /* You MAY cut out these 2 lines to be less strict, */ + addr = NULL; /* you then only get the warning but PA goes on... */ +#endif /* Only problem then may be corresponding munpin() */ + } /* call at PaHost_FreeFastMemory(), below. */ + memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */ + } /* a child process after a fork. Furthermore, IRIX- */ + return addr; /* man-pages warn against mixing both mpin and mlock */ +} /* in 1 piece of code, so stick to mpin()/munpin() ! */ + + +/*---------------------------------------------------------------------------------------*/ +/* 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) +{ + if (addr) + { + if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */ + ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n")); + free(addr); /* But go on, try to release it, just warn... */ + } +} + +/*----------------------------------------------------------*/ +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); +} + +/*-------------------------------------------------------------------*/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + internalPortAudioStream *past = (internalPortAudioStream *) stream; + /* FIXME - return actual frames played, not frames generated. + ** Need to query the output device somehow. + */ + return past->past_FrameCount; +} diff --git a/pa_tests/debug_dual.c b/pa_tests/debug_dual.c new file mode 100644 index 0000000..35ba032 --- /dev/null +++ b/pa_tests/debug_dual.c @@ -0,0 +1,183 @@ +/* + * $Id$ + * debug_dual.c + * Try to open TWO streams on separate cards. + * Play a sine sweep using the Portable Audio api for several seconds. + * Hacked test for debugging PA. + * + * Author: Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define DEV_ID_1 (13) +#define DEV_ID_2 (15) +#define NUM_SECONDS (8) +#define SLEEP_DUR (800) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#if 0 +#define MIN_LATENCY_MSEC (200) +#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) +#else +#define NUM_BUFFERS (0) +#endif +#define MIN_FREQ (100.0f) +#define MAX_FREQ (4000.0f) +#define FREQ_SCALAR (1.00002f) +#define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (400) +typedef struct +{ + float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation + float phase_increment; + float left_phase; + float right_phase; +} +paTestData; +/* Convert phase between and 1.0 to sine value + * using linear interpolation. + */ +float LookupSine( paTestData *data, float phase ); +float LookupSine( paTestData *data, float phase ) +{ + float fIndex = phase*TABLE_SIZE; + int index = (int) fIndex; + float fract = fIndex - index; + float lo = data->sine[index]; + float hi = data->sine[index+1]; + float val = lo + fract*(hi-lo); + return val; +} +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + + for( i=0; ileft_phase); /* left */ + *out++ = LookupSine(data, data->right_phase); /* right */ + data->left_phase += data->phase_increment; + if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f; + data->right_phase += (data->phase_increment * 1.5f); /* fifth above */ + if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f; + /* sweep frequency then start over. */ + data->phase_increment *= FREQ_SCALAR; + if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ); + } + return 0; +} + +PaError TestStart( PortAudioStream **streamPtr, PaDeviceID devID, + paTestData *data ); +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream1, *stream2; + PaError err; + paTestData DATA1, DATA2; + printf("PortAudio Test: DUAL sine sweep. ask for %d buffers\n", NUM_BUFFERS ); + err = Pa_Initialize(); + if( err != paNoError ) goto error; + err = TestStart( &stream1, DEV_ID_1, &DATA1 ); + if( err != paNoError ) goto error; + err = TestStart( &stream2, DEV_ID_2, &DATA2 ); + if( err != paNoError ) goto error; + printf("Hit ENTER\n"); + getchar(); + err = Pa_StopStream( stream1 ); + if( err != paNoError ) goto error; + err = Pa_StopStream( stream2 ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} +PaError TestStart( PortAudioStream **streamPtr, PaDeviceID devID, paTestData *data ) +{ + PortAudioStream *stream; + PaError err; + int i; + /* initialise sinusoidal wavetable */ + for( i=0; isine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); + } + data->sine[TABLE_SIZE] = data->sine[0]; // set guard point + data->left_phase = data->right_phase = 0.0; + data->phase_increment = CalcPhaseIncrement(MIN_FREQ); + printf("PortAudio Test: output device = %d\n", devID ); + err = Pa_OpenStream( + &stream, + paNoDevice, + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + devID, + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + NUM_BUFFERS, /* number of buffers, if zero then use default minimum */ + paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + *streamPtr = stream; + return 0; +error: + return err; +} diff --git a/pa_tests/debug_multi_in.c b/pa_tests/debug_multi_in.c new file mode 100644 index 0000000..def729c --- /dev/null +++ b/pa_tests/debug_multi_in.c @@ -0,0 +1,179 @@ +/* + * $Id$ + * debug_multi_in.c + * Pass output from each of multiple channels + * to a stereo output using the Portable Audio api. + * Hacked test for debugging PA. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include +#include "portaudio.h" +//#define INPUT_DEVICE_NAME ("EWS88 MT Interleaved Rec") +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +//#define OUTPUT_DEVICE (18) +#define SAMPLE_RATE (22050) +#define FRAMES_PER_BUFFER (256) +#define MIN_LATENCY_MSEC (400) +#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +typedef struct +{ + int liveChannel; + int numChannels; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + float *in = (float*)inputBuffer; + int i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + if( in == NULL ) return 0; + for( i=0; i<(int)framesPerBuffer; i++ ) + { + /* Copy one channel of input to output. */ + *out++ = in[data->liveChannel]; + *out++ = in[data->liveChannel]; + in += data->numChannels; + } + return 0; +} +/*******************************************************************/ +int PaFindDeviceByName( const char *name ) +{ + int i; + int numDevices; + const PaDeviceInfo *pdi; + int len = strlen( name ); + PaDeviceID result = paNoDevice; + numDevices = Pa_CountDevices(); + for( i=0; iname, len ) == 0 ) + { + result = i; + break; + } + } + return result; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + PaDeviceID inputDevice; + const PaDeviceInfo *pdi; + printf("PortAudio Test: input signal from each channel. %d buffers\n", NUM_BUFFERS ); + data.liveChannel = 0; + err = Pa_Initialize(); + if( err != paNoError ) goto error; +#ifdef INPUT_DEVICE_NAME + printf("Try to use device: %s\n", INPUT_DEVICE_NAME ); + inputDevice = PaFindDeviceByName(INPUT_DEVICE_NAME); + if( inputDevice == paNoDevice ) + { + printf("Could not find %s. Using default instead.\n", INPUT_DEVICE_NAME ); + inputDevice = Pa_GetDefaultInputDeviceID(); + } +#else + printf("Using default input device.\n"); + inputDevice = Pa_GetDefaultInputDeviceID(); +#endif + pdi = Pa_GetDeviceInfo( inputDevice ); + if( pdi == NULL ) + { + printf("Could not get device info!\n"); + goto error; + } + data.numChannels = pdi->maxInputChannels; + printf("Input Device name is %s\n", pdi->name ); + printf("Input Device has %d channels.\n", pdi->maxInputChannels); + err = Pa_OpenStream( + &stream, + inputDevice, + pdi->maxInputChannels, + paFloat32, /* 32 bit floating point input */ + NULL, + OUTPUT_DEVICE, + 2, + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + NUM_BUFFERS, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + data.liveChannel = 0; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + for( i=0; i +#include +#include "portaudio.h" +#define NUM_CHANNELS (8) +// #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +#define OUTPUT_DEVICE (18) +#define NUM_SECONDS (NUM_CHANNELS*4) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_CHANNEL (SAMPLE_RATE/2) +#define FRAMES_PER_BUFFER (256) +#define MIN_LATENCY_MSEC (400) +#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (800) +typedef struct +{ + float sine[TABLE_SIZE]; + int phase; + int liveChannel; + int count; + unsigned int sampsToGo; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + int i, j; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + if( data->sampsToGo < framesPerBuffer ) + { + finished = 1; + } + else + { + for( i=0; i<(int)framesPerBuffer; i++ ) + { + for( j=0; jliveChannel) ? data->sine[data->phase] : 0.0f; + /* Play each channel at a higher frequency. */ + data->phase += 1 + data->liveChannel; + if( data->phase >= TABLE_SIZE ) data->phase -= TABLE_SIZE; + } + /* Switch channels every so often. */ + if( --data->count <= 0 ) + { + data->count = FRAMES_PER_CHANNEL; + data->liveChannel += 1; + if( data->liveChannel >= NUM_CHANNELS ) data->liveChannel = 0; + } + } + data->sampsToGo -= framesPerBuffer; + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int totalSamps; + printf("PortAudio Test: output sine wave. %d buffers\n", NUM_BUFFERS ); + /* initialise sinusoidal wavetable */ + for( i=0; i +#include +#include +#include "portaudio.h" +#define SAMPLE_RATE (22050) +#define NUM_SECONDS (10) +#define SLEEP_DUR_MSEC (200) +#define REC_BUF_FRAMES (1<<10) +#define NUM_REC_BUFS (0) +#if 0 +#define PA_SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#else +#define PA_SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#endif +typedef struct +{ + long frameIndex; /* Index into sample array. */ + long maxFrameIndex; + long samplesPerFrame; + SAMPLE *recordedSamples; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int recordCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE *rptr = (SAMPLE*)inputBuffer; + SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; + long framesToCalc; + unsigned long i; + int finished; + unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; + + (void) outputBuffer; /* Prevent unused variable warnings. */ + (void) outTime; + + if( framesLeft < framesPerBuffer ) + { + framesToCalc = framesLeft; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + finished = 0; + } + if( inputBuffer == NULL ) + { + for( i=0; iframeIndex += framesToCalc; + return finished; +} +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int playCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; + SAMPLE *wptr = (SAMPLE*)outputBuffer; + unsigned long i; + int finished; + unsigned int framesLeft = data->maxFrameIndex - data->frameIndex; + if( outputBuffer == NULL ) return 0; + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) outTime; + + if( framesLeft < framesPerBuffer ) + { + /* final buffer... */ + for( i=0; iframeIndex += framesLeft; + finished = 1; + } + else + { + for( i=0; iframeIndex += framesPerBuffer; + finished = 0; + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + long totalFrames; + long numSamples; + long numBytes; + long i; + printf("patest_record.c\n"); fflush(stdout); + + data.frameIndex = 0; + data.samplesPerFrame = 2; + data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE; + + printf("totalFrames = %d\n", totalFrames ); fflush(stdout); + numSamples = totalFrames * data.samplesPerFrame; + numBytes = numSamples * sizeof(SAMPLE); + data.recordedSamples = (SAMPLE *) malloc( numBytes ); + if( data.recordedSamples == NULL ) + { + printf("Could not allocate record array.\n"); + exit(1); + } + for( i=0; i max ) max = posVal; + } + printf("Largest recorded sample = %d\n", max ); + } + /* Write recorded data to a file. */ +#if 0 + { + FILE *fid; + fid = fopen("recorded.raw", "wb"); + if( fid == NULL ) + { + printf("Could not open file."); + } + else + { + fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid ); + fclose( fid ); + printf("Wrote data to 'recorded.raw'\n"); + } + } +#endif + free( data.recordedSamples ); + Pa_Terminate(); + return 0; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + if( err == paHostError ) + { + fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() ); + } + return -1; +} diff --git a/pa_tests/debug_sine.c b/pa_tests/debug_sine.c new file mode 100644 index 0000000..b79405d --- /dev/null +++ b/pa_tests/debug_sine.c @@ -0,0 +1,192 @@ +/* + * $Id$ + * debug_sine.c + * Play a sine sweep using the Portable Audio api for several seconds. + * Hacked test for debugging PA. + * + * Author: Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +//#define OUTPUT_DEVICE (11) +#define NUM_SECONDS (8) +#define SLEEP_DUR (800) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#if 1 +#define MIN_LATENCY_MSEC (200) +#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) +#else +#define NUM_BUFFERS (0) +#endif +#define MIN_FREQ (100.0f) +#define MAX_FREQ (4000.0f) +#define FREQ_SCALAR (1.00002f) +#define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (400) +typedef struct +{ + float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation + float phase_increment; + float left_phase; + float right_phase; + unsigned int framesToGo; +} +paTestData; +/* Convert phase between and 1.0 to sine value + * using linear interpolation. + */ +float LookupSine( paTestData *data, float phase ); +float LookupSine( paTestData *data, float phase ) +{ + float fIndex = phase*TABLE_SIZE; + int index = (int) fIndex; + float fract = fIndex - index; + float lo = data->sine[index]; + float hi = data->sine[index+1]; + float val = lo + fract*(hi-lo); + return val; +} +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + int framesToCalc; + int i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + if( data->framesToGo < framesPerBuffer ) + { + framesToCalc = data->framesToGo; + data->framesToGo = 0; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + data->framesToGo -= framesPerBuffer; + } + + for( i=0; ileft_phase); /* left */ + *out++ = LookupSine(data, data->right_phase); /* right */ + data->left_phase += data->phase_increment; + if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f; + data->right_phase += (data->phase_increment * 1.5f); /* fifth above */ + if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f; + /* sweep frequency then start over. */ + data->phase_increment *= FREQ_SCALAR; + if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ); + } + /* zero remainder of final buffer */ + for( ; i<(int)framesPerBuffer; i++ ) + { + *out++ = 0; /* left */ + *out++ = 0; /* right */ + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int totalSamps; + printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS ); + /* initialise sinusoidal wavetable */ + for( i=0; i + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (20) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) +#define NUM_BUFFERS (16) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; i + Modifications: + April 5th, 2001 - PLB - Check for NULL inputBuffer. +*/ +#include +#include +#include "portaudio.h" +#ifndef M_PI +#define M_PI (3.14159265) +#endif +typedef struct +{ + float sine[100]; + int phase; + int sampsToGo; +} +patest1data; +static int patest1Callback( void *inputBuffer, void *outputBuffer, + unsigned long bufferFrames, + PaTimestamp outTime, void *userData ) +{ + patest1data *data = (patest1data*)userData; + float *in = (float*)inputBuffer; + float *out = (float*)outputBuffer; + int framesToCalc = bufferFrames; + unsigned long i; + int finished = 0; + if(inputBuffer == NULL) return 0; + if( data->sampsToGo < bufferFrames ) + { + finished = 1; + } + for( i=0; iphase >= 100 ) + data->phase = 0; + } + data->sampsToGo -= bufferFrames; + /* zero remainder of final buffer if not already done */ + for( ; i +#include +#include "portaudio.h" +/*******************************************************************/ +int main(void); +int main(void) +{ + int i,j; + int numDevices; + const PaDeviceInfo *pdi; + PaError err; + Pa_Initialize(); + numDevices = Pa_CountDevices(); + if( numDevices < 0 ) + { + printf("ERROR: Pa_CountDevices returned 0x%x\n", numDevices ); + err = numDevices; + goto error; + } + printf("Number of devices = %d\n", numDevices ); + for( i=0; iname ); + printf("Max Inputs = %d", pdi->maxInputChannels ); + printf(", Max Outputs = %d\n", pdi->maxOutputChannels ); + if( pdi->numSampleRates == -1 ) + { + printf("Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] ); + } + else + { + printf("Sample Rates ="); + for( j=0; jnumSampleRates; j++ ) + { + printf(" %8.2f,", pdi->sampleRates[j] ); + } + printf("\n"); + } + printf("Native Sample Formats = "); + if( pdi->nativeSampleFormats & paInt8 ) printf("paInt8, "); + if( pdi->nativeSampleFormats & paUInt8 ) printf("paUInt8, "); + if( pdi->nativeSampleFormats & paInt16 ) printf("paInt16, "); + if( pdi->nativeSampleFormats & paInt32 ) printf("paInt32, "); + if( pdi->nativeSampleFormats & paFloat32 ) printf("paFloat32, "); + if( pdi->nativeSampleFormats & paInt24 ) printf("paInt24, "); + if( pdi->nativeSampleFormats & paPackedInt24 ) printf("paPackedInt24, "); + printf("\n"); + } + Pa_Terminate(); + + printf("----------------------------------------------\n"); + return 0; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/pa_tests/pa_fuzz.c b/pa_tests/pa_fuzz.c new file mode 100644 index 0000000..3161c74 --- /dev/null +++ b/pa_tests/pa_fuzz.c @@ -0,0 +1,155 @@ +/* + * $Id$ + * pa_fuzz.c + * Distort input like a fuzz boz. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +/* +** Note that many of the older ISA sound cards on PCs do NOT support +** full duplex audio (simultaneous record and playback). +** And some only support full duplex at lower sample rates. +*/ +#define SAMPLE_RATE (44100) +#define PA_SAMPLE_TYPE paFloat32 +#define FRAMES_PER_BUFFER (64) + +typedef float SAMPLE; + +float CubicAmplifier( float input ); +static int fuzzCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); + +/* Non-linear amplifier with soft distortion curve. */ +float CubicAmplifier( float input ) +{ + float output, temp; + if( input < 0.0 ) + { + temp = input + 1.0f; + output = (temp * temp * temp) - 1.0f; + } + else + { + temp = input - 1.0f; + output = (temp * temp * temp) + 1.0f; + } + + return output; +} +#define FUZZ(x) CubicAmplifier(CubicAmplifier(CubicAmplifier(CubicAmplifier(x)))) + +static int gNumNoInputs = 0; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int fuzzCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + SAMPLE *out = (SAMPLE*)outputBuffer; + SAMPLE *in = (SAMPLE*)inputBuffer; + unsigned int i; + (void) outTime; /* Prevent unused variable warnings. */ + (void) userData; + + if( inputBuffer == NULL ) + { + for( i=0; i +#include +#include +#include "portaudio.h" +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define DEFAULT_BUFFER_SIZE (128) +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; +/* Very simple synthesis routine to generate two sine waves. */ +static int paminlatCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return 0; +} +void main( int argc, char **argv ); +void main( int argc, char **argv ) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int go; + int numBuffers = 0; + int minBuffers = 0; + int framesPerBuffer; + double sampleRate = 44100.0; + char str[256]; + printf("paminlat - Determine minimum latency for your computer.\n"); + printf(" usage: paminlat {framesPerBuffer}\n"); + printf(" for example: paminlat 256\n"); + printf("Adjust your stereo until you hear a smooth tone in each speaker.\n"); + printf("Then try to find the smallest number of buffers that still sounds smooth.\n"); + printf("Note that the sound will stop momentarily when you change the number of buffers.\n"); + /* Get bufferSize from command line. */ + framesPerBuffer = ( argc > 1 ) ? atol( argv[1] ) : DEFAULT_BUFFER_SIZE; + printf("Frames per buffer = %d\n", framesPerBuffer ); + /* Initialise sinusoidal wavetable. */ + for( i=0; i +#include +#include "portaudio.h" +#include "pa_trace.h" +/****************************************** Definitions ***********/ +#define MODE_INPUT (0) +#define MODE_OUTPUT (1) +typedef struct PaQaData +{ + unsigned long framesLeft; + int numChannels; + int bytesPerSample; + int mode; + short sawPhase; + PaSampleFormat format; +} +PaQaData; +/****************************************** Prototypes ***********/ +static void TestDevices( int mode ); +static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate, + int numChannels ); +static int TestAdvance( int mode, PaDeviceID deviceID, double sampleRate, + int numChannels, PaSampleFormat format ); +static int QaCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); +/****************************************** Globals ***********/ +static int gNumPassed = 0; +static int gNumFailed = 0; +/****************************************** Macros ***********/ +/* Print ERROR if it fails. Tally success or failure. */ +/* Odd do-while wrapper seems to be needed for some compilers. */ +#define EXPECT(_exp) \ + do \ + { \ + if ((_exp)) {\ + /* printf("SUCCESS for %s\n", #_exp ); */ \ + gNumPassed++; \ + } \ + else { \ + printf("ERROR - 0x%x - %s for %s\n", result, \ + ((result == 0) ? "-" : Pa_GetErrorText(result)), \ + #_exp ); \ + gNumFailed++; \ + goto error; \ + } \ + } while(0) +/*******************************************************************/ +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int QaCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + unsigned long i; + short phase; + PaQaData *data = (PaQaData *) userData; + (void) inputBuffer; + (void) outTime; + + /* Play simle sawtooth wave. */ + if( data->mode == MODE_OUTPUT ) + { + phase = data->sawPhase; + switch( data->format ) + { + case paFloat32: + { + float *out = (float *) outputBuffer; + for( i=0; inumChannels == 2 ) + { + *out++ = (float) (phase * (1.0 / 32768.0)); + } + } + } + break; + + case paInt32: + { + int *out = (int *) outputBuffer; + for( i=0; inumChannels == 2 ) + { + *out++ = ((int) phase ) << 16; + } + } + } + break; + case paInt16: + { + short *out = (short *) outputBuffer; + for( i=0; inumChannels == 2 ) + { + *out++ = phase; + } + } + } + break; + + default: + { + unsigned char *out = (unsigned char *) outputBuffer; + unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; + for( i=0; isawPhase = phase; + } + /* Are we through yet? */ + if( data->framesLeft > framesPerBuffer ) + { + AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft ); + data->framesLeft -= framesPerBuffer; + return 0; + } + else + { + AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft ); + data->framesLeft = 0; + return 1; + } +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError result; + EXPECT( ((result=Pa_Initialize()) == 0) ); + printf("Test OUTPUT ---------------\n"); + TestDevices( MODE_OUTPUT ); + printf("Test INPUT ---------------\n"); + TestDevices( MODE_INPUT ); +error: + Pa_Terminate(); + printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed ); +} +/******************************************************************* +* Try each output device, through its full range of capabilities. */ +static void TestDevices( int mode ) +{ + int id,jc,kr; + int maxChannels; + const PaDeviceInfo *pdi; + int numDevices = Pa_CountDevices(); + /* Iterate through all devices. */ + for( id=0; idmaxInputChannels : pdi->maxOutputChannels; + for( jc=1; jc<=maxChannels; jc++ ) + { + printf("Name = %s\n", pdi->name ); + /* Try each legal sample rate. */ + if( pdi->numSampleRates == -1 ) + { + double low, high; + low = pdi->sampleRates[0]; + high = pdi->sampleRates[1]; + if( low < 8000.0 ) low = 8000.0; + TestFormats( mode, id, low, jc ); +#define TESTSR(sr) {if(((sr)>=low) && ((sr)<=high)) TestFormats( mode, id, (sr), jc ); } + + TESTSR(11025.0); + TESTSR(22050.0); + TESTSR(44100.0); + TestFormats( mode, id, high, jc ); + } + else + { + for( kr=0; krnumSampleRates; kr++ ) + { + TestFormats( mode, id, pdi->sampleRates[kr], jc ); + } + } + } + } +} +/*******************************************************************/ +static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate, + int numChannels ) +{ + TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); /* */ + TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); /* */ + TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); /* */ + /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */ +} +/*******************************************************************/ +static int TestAdvance( int mode, PaDeviceID deviceID, double sampleRate, + int numChannels, PaSampleFormat format ) +{ + PortAudioStream *stream = NULL; + PaError result; + PaQaData myData; +#define FRAMES_PER_BUFFER (64) + printf("------ TestAdvance: %s, device = %d, rate = %g, numChannels = %d, format = %d -------\n", + ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT", + deviceID, sampleRate, numChannels, format); + /* Setup data for synthesis thread. */ + myData.framesLeft = (unsigned long) (sampleRate * 100); /* 100 seconds */ + myData.numChannels = numChannels; + myData.mode = mode; + myData.format = format; + switch( format ) + { + case paFloat32: + case paInt32: + case paInt24: + myData.bytesPerSample = 4; + break; + case paPackedInt24: + myData.bytesPerSample = 3; + break; + default: + myData.bytesPerSample = 2; + break; + } + EXPECT( ((result = Pa_OpenStream( + &stream, + ( mode == MODE_INPUT ) ? deviceID : paNoDevice, + ( mode == MODE_INPUT ) ? numChannels : 0, + format, + NULL, + ( mode == MODE_OUTPUT ) ? deviceID : paNoDevice, + ( mode == MODE_OUTPUT ) ? numChannels : 0, + format, + NULL, + sampleRate, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + QaCallback, + &myData ) + ) == 0) ); + if( stream ) + { + PaTimestamp oldStamp, newStamp; + unsigned long oldFrames; + int minDelay = ( mode == MODE_INPUT ) ? 1000 : 400; + int minNumBuffers = Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); + int msec = (int) ((minNumBuffers * 3 * 1000.0 * FRAMES_PER_BUFFER) / sampleRate); + if( msec < minDelay ) msec = minDelay; + printf("msec = %d\n", msec); /**/ + EXPECT( ((result=Pa_StartStream( stream )) == 0) ); + /* Check to make sure PortAudio is advancing timeStamp. */ + result = paNoError; + oldStamp = Pa_StreamTime(stream); + Pa_Sleep(msec); + newStamp = Pa_StreamTime(stream); + printf("oldStamp = %g,newStamp = %g\n", oldStamp, newStamp ); /**/ + EXPECT( (oldStamp < newStamp) ); + /* Check to make sure callback is decrementing framesLeft. */ + oldFrames = myData.framesLeft; + Pa_Sleep(msec); + printf("oldFrames = %d, myData.framesLeft = %d\n", oldFrames, myData.framesLeft ); /**/ + EXPECT( (oldFrames > myData.framesLeft) ); + EXPECT( ((result=Pa_CloseStream( stream )) == 0) ); + stream = NULL; + } +error: + if( stream != NULL ) Pa_CloseStream( stream ); + return result; +} diff --git a/pa_tests/paqa_errs.c b/pa_tests/paqa_errs.c new file mode 100644 index 0000000..37e75d7 --- /dev/null +++ b/pa_tests/paqa_errs.c @@ -0,0 +1,305 @@ +/* + * $Id$ + * paqa_devs.c + * Self Testing Quality Assurance app for PortAudio + * Do lots of bad things to test error reporting. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +/****************************************** Definitions ***********/ +#define MODE_INPUT (0) +#define MODE_OUTPUT (1) +#define FRAMES_PER_BUFFER (64) +#define SAMPLE_RATE (44100.0) +#define NUM_BUFFERS (0) +typedef struct PaQaData +{ + unsigned long framesLeft; + int numChannels; + int bytesPerSample; + int mode; +} +PaQaData; +/****************************************** Prototypes ***********/ +static void TestDevices( int mode ); +static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate, + int numChannels ); +static int TestBadOpens( void ); +static int TestBadActions( void ); +static int QaCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); +/****************************************** Globals ***********/ +static int gNumPassed = 0; +static int gNumFailed = 0; +/****************************************** Macros ***********/ +/* Print ERROR if it fails. Tally success or failure. */ +/* Odd do-while wrapper seems to be needed for some compilers. */ +#define EXPECT(_exp) \ + do \ + { \ + if ((_exp)) {\ + gNumPassed++; \ + } \ + else { \ + printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \ + gNumFailed++; \ + goto error; \ + } \ + } while(0) +#define HOPEFOR(_exp) \ + do \ + { \ + if ((_exp)) {\ + gNumPassed++; \ + } \ + else { \ + printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \ + gNumFailed++; \ + } \ + } while(0) +/*******************************************************************/ +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int QaCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + unsigned long i; + unsigned char *out = (unsigned char *) outputBuffer; + PaQaData *data = (PaQaData *) userData; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + (void) outTime; + + /* Zero out buffer so we don't hear terrible noise. */ + if( data->mode == MODE_OUTPUT ) + { + unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; + for( i=0; iframesLeft > framesPerBuffer ) + { + data->framesLeft -= framesPerBuffer; + return 0; + } + else + { + data->framesLeft = 0; + return 1; + } +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError result; + EXPECT( ((result=Pa_Initialize()) == 0) ); + TestBadOpens(); + TestBadActions(); +error: + Pa_Terminate(); + printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed ); + return 0; +} +/*******************************************************************/ +static int TestBadOpens( void ) +{ + PortAudioStream *stream = NULL; + PaError result; + PaQaData myData; + /* Setup data for synthesis thread. */ + myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */ + myData.numChannels = 1; + myData.mode = MODE_OUTPUT; + HOPEFOR( (/* No devices specified. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + paNoDevice, 0, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidDeviceId) ); + HOPEFOR( ( /* Out of range input device specified. */ + (result = Pa_OpenStream( + &stream, + Pa_CountDevices(), 0, paFloat32, NULL, + paNoDevice, 0, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidDeviceId) ); + + HOPEFOR( ( /* Out of range output device specified. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + Pa_CountDevices(), 0, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidDeviceId) ); + HOPEFOR( ( /* Zero input channels. */ + (result = Pa_OpenStream( + &stream, + Pa_GetDefaultInputDeviceID(), 0, paFloat32, NULL, + paNoDevice, 0, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidChannelCount) ); + HOPEFOR( ( /* Zero output channels. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + Pa_GetDefaultOutputDeviceID(), 0, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidChannelCount) ); + HOPEFOR( ( /* Nonzero input channels but no device. */ + (result = Pa_OpenStream( + &stream, + Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL, + paNoDevice, 2, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidChannelCount) ); + + HOPEFOR( ( /* Nonzero output channels but no device. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 2, paFloat32, NULL, + Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidChannelCount) ); + HOPEFOR( ( /* NULL stream pointer. */ + (result = Pa_OpenStream( + NULL, + paNoDevice, 0, paFloat32, NULL, + Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paBadStreamPtr) ); + HOPEFOR( ( /* Low sample rate. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, + 1.0, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidSampleRate) ); + HOPEFOR( ( /* High sample rate. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, + 10000000.0, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidSampleRate) ); + HOPEFOR( ( /* NULL callback. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + NULL, + &myData ) + ) == paNullCallback) ); + HOPEFOR( ( /* Bad flag. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + (1<<3), + QaCallback, + &myData ) + ) == paInvalidFlag) ); + if( stream != NULL ) Pa_CloseStream( stream ); + return result; +} +/*******************************************************************/ +static int TestBadActions( void ) +{ + PortAudioStream *stream = NULL; + PaError result; + PaQaData myData; + /* Setup data for synthesis thread. */ + myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */ + myData.numChannels = 1; + myData.mode = MODE_OUTPUT; + /* Default output. */ + EXPECT( ((result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == 0) ); + HOPEFOR( ((result = Pa_StartStream( NULL )) == paBadStreamPtr) ); + HOPEFOR( ((result = Pa_StopStream( NULL )) == paBadStreamPtr) ); + HOPEFOR( ((result = Pa_StreamActive( NULL )) == paBadStreamPtr) ); + HOPEFOR( ((result = Pa_CloseStream( NULL )) == paBadStreamPtr) ); + HOPEFOR( ((result = (PaError)Pa_StreamTime( NULL )) != 0) ); + HOPEFOR( ((result = (PaError)Pa_GetCPULoad( NULL )) != 0) ); +error: + if( stream != NULL ) Pa_CloseStream( stream ); + return result; +} diff --git a/pa_tests/patest1.c b/pa_tests/patest1.c new file mode 100644 index 0000000..5fddd51 --- /dev/null +++ b/pa_tests/patest1.c @@ -0,0 +1,114 @@ +/* + $Id$ + patest1.c + Ring modulate the audio input with a sine wave for 20 seconds + using the Portable Audio api + Author: Ross Bencina + Modifications: + April 5th, 2001 - PLB - Check for NULL inputBuffer. +*/ +#include +#include +#include "portaudio.h" +#ifndef M_PI +#define M_PI (3.14159265) +#endif +typedef struct +{ + float sine[100]; + int phase; + int sampsToGo; +} +patest1data; +static int patest1Callback( void *inputBuffer, void *outputBuffer, + unsigned long bufferFrames, + PaTimestamp outTime, void *userData ) +{ + patest1data *data = (patest1data*)userData; + float *in = (float*)inputBuffer; + float *out = (float*)outputBuffer; + int framesToCalc = bufferFrames; + unsigned long i; + int finished = 0; + /* Check to see if any input data is available. */ + if(inputBuffer == NULL) return 0; + if( data->sampsToGo < bufferFrames ) + { + framesToCalc = data->sampsToGo; + finished = 1; + } + for( i=0; isine[data->phase]; /* left */ + *out++ = *in++ * data->sine[data->phase++]; /* right */ + if( data->phase >= 100 ) + data->phase = 0; + } + data->sampsToGo -= framesToCalc; + /* zero remainder of final buffer if not already done */ + for( ; i +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (1) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) + +#define BUFFER_TABLE 9 +long buffer_table[] = {200,256,500,512,600, 723, 1000, 1024, 2345}; + +typedef struct +{ + short sine[TABLE_SIZE]; + int left_phase; + int right_phase; + unsigned int sampsToGo; +} +paTestData; +PaError TestOnce( int buffersize ); + +static int patest1Callback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patest1Callback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *out = (short*)outputBuffer; + unsigned int i; + int finished = 0; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + (void) outTime; + + if( data->sampsToGo < framesPerBuffer ) + { + /* final buffer... */ + + for( i=0; isampsToGo; i++ ) + { + *out++ = data->sine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + /* zero remainder of final buffer */ + for( ; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + data->sampsToGo -= framesPerBuffer; + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + int i; + PaError err; + printf("Test opening streams with different buffer sizes\n\n"); + + for (i = 0 ; i < BUFFER_TABLE; i++) + { + printf("Buffer size %d\n", buffer_table[i]); + err = TestOnce(buffer_table[i]); + if( err < 0 ) return 0; + + } +} + + +PaError TestOnce( int buffersize ) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int totalSamps; + /* initialise sinusoidal wavetable */ + for( i=0; i +#include +#include "portaudio.h" +#define NUM_SECONDS (4) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +typedef struct paTestData +{ + float sine[TABLE_SIZE]; + float amplitude; + int left_phase; + int right_phase; +} +paTestData; +PaError PlaySine( paTestData *data, unsigned long flags, float amplitude ); +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int sineCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + float amplitude = data->amplitude; + unsigned int i; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + (void) outTime; + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = amplitude * data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return 0; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err; + paTestData DATA; + int i; + printf("PortAudio Test: output sine wave with and without clipping.\n"); + /* initialise sinusoidal wavetable */ + for( i=0; ileft_phase = data->right_phase = 0; + data->amplitude = amplitude; + err = Pa_Initialize(); + if( err != paNoError ) goto error; + err = Pa_OpenStream( + &stream, + paNoDevice,/* default input device */ + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + Pa_GetDefaultOutputDeviceID(), /* default output device */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + 1024, + 0, /* number of buffers, if zero then use default minimum */ + flags, /* we won't output out of range samples so don't bother clipping them */ + sineCallback, + data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + Pa_Sleep( NUM_SECONDS * 1000 ); + printf("CPULoad = %8.6f\n", Pa_GetCPULoad( stream ) ); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + return paNoError; +error: + return err; +} diff --git a/pa_tests/patest_dither.c b/pa_tests/patest_dither.c new file mode 100644 index 0000000..8878161 --- /dev/null +++ b/pa_tests/patest_dither.c @@ -0,0 +1,151 @@ +/* + * $Id$ + * patest_dither.c + * Attempt to hear difference between dithered and non-dithered signal. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (4) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +typedef struct paTestData +{ + float sine[TABLE_SIZE]; + float amplitude; + int left_phase; + int right_phase; +} +paTestData; +PaError PlaySine( paTestData *data, PaStreamFlags flags, float amplitude ); +static int sineCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int sineCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + float amplitude = data->amplitude; + unsigned int i; + (void) outTime; + (void) inputBuffer; + for( i=0; isine[data->left_phase]; /* left */ + *out++ = amplitude * data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return 0; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err; + paTestData DATA; + int i; + float amplitude = 32.0 / (1<<15); + printf("PortAudio Test: output EXTREMELY QUIET sine wave with and without dithering.\n"); + /* initialise sinusoidal wavetable */ + for( i=0; ileft_phase = data->right_phase = 0; + data->amplitude = amplitude; + err = Pa_Initialize(); + if( err != paNoError ) goto error; + err = Pa_OpenStream( + &stream, + paNoDevice,/* default input device */ + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + Pa_GetDefaultOutputDeviceID(), /* default output device */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + 1024, + 0, /* number of buffers, if zero then use default minimum */ + flags, /* we won't output out of range samples so don't bother clipping them */ + sineCallback, + (void *)data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + Pa_Sleep( NUM_SECONDS * 1000 ); + printf("CPULoad = %8.6f\n", Pa_GetCPULoad( stream ) ); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + return paNoError; +error: + return err; +} diff --git a/pa_tests/patest_latency.c b/pa_tests/patest_latency.c new file mode 100644 index 0000000..2daf431 --- /dev/null +++ b/pa_tests/patest_latency.c @@ -0,0 +1,171 @@ +/* + * $Id$ + * Hear the latency caused by bug buffers. + * Play a sine wave and change frequency based on letter input. + * + * Author: Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#if 1 +#define MIN_LATENCY_MSEC (2000) +#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) +#else +#define NUM_BUFFERS (0) +#endif +#define MIN_FREQ (100.0f) +#define CalcPhaseIncrement(freq) ((freq)/SAMPLE_RATE) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (400) +typedef struct +{ + float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation + float phase_increment; + float left_phase; + float right_phase; +} +paTestData; +float LookupSine( paTestData *data, float phase ); +/* Convert phase between and 1.0 to sine value + * using linear interpolation. + */ +float LookupSine( paTestData *data, float phase ) +{ + float fIndex = phase*TABLE_SIZE; + int index = (int) fIndex; + float fract = fIndex - index; + float lo = data->sine[index]; + float hi = data->sine[index+1]; + float val = lo + fract*(hi-lo); + return val; +} +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + int i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( i=0; ileft_phase); /* left */ + *out++ = LookupSine(data, data->right_phase); /* right */ + data->left_phase += data->phase_increment; + if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f; + data->right_phase += (data->phase_increment * 1.5f); /* fifth above */ + if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f; + } + return 0; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int done = 0; + printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS ); + /* initialise sinusoidal wavetable */ + for( i=0; i + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (8) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + int toggle; + int countDown; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( i=0; itoggle ) + { + *out++ = data->sine[data->left_phase]; /* left */ + *out++ = 0; /* right */ + } + else + { + *out++ = 0; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + } + + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + if( data->countDown < 0 ) + { + data->countDown = SAMPLE_RATE; + data->toggle = !data->toggle; + } + data->countDown -= framesPerBuffer; + + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int timeout; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; i 0 ) + { + printf("Countdown = %d, Toggle = %d\n", data.countDown, data.toggle ); + fflush( stdout ); + Pa_Sleep( 1000/4 ); + timeout -= 1; + } + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/pa_tests/patest_longsine.c b/pa_tests/patest_longsine.c new file mode 100644 index 0000000..3d8bd4c --- /dev/null +++ b/pa_tests/patest_longsine.c @@ -0,0 +1,124 @@ +/* + * $Id$ + * patest_longsine.c + * Play a sine wave using the Portable Audio api forever. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return 0; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + printf("PortAudio Test: output sine wave.\n"); + /* initialise sinusoidal wavetable */ + for( i=0; i +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (1) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +typedef struct +{ + short sine[TABLE_SIZE]; + int left_phase; + int right_phase; + unsigned int sampsToGo; +} +paTestData; +PaError TestOnce( void ); +static int patest1Callback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patest1Callback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *out = (short*)outputBuffer; + unsigned int i; + int finished = 0; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + (void) outTime; + + if( data->sampsToGo < framesPerBuffer ) + { + /* final buffer... */ + + for( i=0; isampsToGo; i++ ) + { + *out++ = data->sine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + /* zero remainder of final buffer */ + for( ; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + data->sampsToGo -= framesPerBuffer; + } + return finished; +} +/*******************************************************************/ +#ifdef MACINTOSH +int main(void); +int main(void) +{ + int i; + PaError err; + int numLoops = 10; + printf("Loop %d times.\n", numLoops ); + for( i=0; i 1 ) + { + numLoops = atoi(argv[1]); + } + for( i=0; i + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" + +#define MAX_SINES (500) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +typedef struct paTestData +{ + int numSines; + double phases[MAX_SINES]; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int j; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( i=0; inumSines; j++ ) + { + /* Advance phase of next oscillator. */ + phase = data->phases[j]; + phase += phaseInc; + if( phase > TWOPI ) phase -= TWOPI; + + phaseInc *= 1.02; + if( phaseInc > 0.5 ) phaseInc *= 0.5; + + /* This is not a very efficient way to calc sines. */ + output += (float) sin( phase ); + data->phases[j] = phase; + } + + + *out++ = (float) (output / data->numSines); + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data = {0}; + double load; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + err = Pa_OpenStream( + &stream, + paNoDevice,/* default input device */ + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + Pa_GetDefaultOutputDeviceID(), /* default output device */ + 1, /* mono output */ + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + do + { + data.numSines++; + Pa_Sleep( 200 ); + + load = Pa_GetCPULoad( stream ); + printf("numSines = %d, CPU load = %f\n", data.numSines, load ); + } + while( load < 0.8 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/pa_tests/patest_pink.c b/pa_tests/patest_pink.c new file mode 100644 index 0000000..c1fdece --- /dev/null +++ b/pa_tests/patest_pink.c @@ -0,0 +1,245 @@ +/* + * $Id$ + patest_pink.c + Generate Pink Noise using Gardner method. + Optimization suggested by James McCartney uses a tree + to select which random value to replace. + x x x x x x x x x x x x x x x x + x x x x x x x x + x x x x + x x + x + Tree is generated by counting trailing zeros in an increasing index. + When the index is zero, no random number is selected. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define PINK_MAX_RANDOM_ROWS (30) +#define PINK_RANDOM_BITS (24) +#define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS) +typedef struct +{ + long pink_Rows[PINK_MAX_RANDOM_ROWS]; + long pink_RunningSum; /* Used to optimize summing of generators. */ + int pink_Index; /* Incremented each sample. */ + int pink_IndexMask; /* Index wrapped by ANDing with this mask. */ + float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */ +} +PinkNoise; +/* Prototypes */ +static unsigned long GenerateRandomNumber( void ); +void InitializePinkNoise( PinkNoise *pink, int numRows ); +float GeneratePinkNoise( PinkNoise *pink ); +/************************************************************/ +/* Calculate pseudo-random 32 bit number based on linear congruential method. */ +static unsigned long GenerateRandomNumber( void ) +{ + /* Change this seed for different random sequences. */ + static unsigned long randSeed = 22222; + randSeed = (randSeed * 196314165) + 907633515; + return randSeed; +} +/************************************************************/ +/* Setup PinkNoise structure for N rows of generators. */ +void InitializePinkNoise( PinkNoise *pink, int numRows ) +{ + int i; + long pmax; + pink->pink_Index = 0; + pink->pink_IndexMask = (1<pink_Scalar = 1.0f / pmax; + /* Initialize rows. */ + for( i=0; ipink_Rows[i] = 0; + pink->pink_RunningSum = 0; +} +#define PINK_MEASURE +#ifdef PINK_MEASURE +float pinkMax = -999.0; +float pinkMin = 999.0; +#endif +/* Generate Pink noise values between -1.0 and +1.0 */ +float GeneratePinkNoise( PinkNoise *pink ) +{ + long newRandom; + long sum; + float output; + /* Increment and mask index. */ + pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask; + /* If index is zero, don't update any random values. */ + if( pink->pink_Index != 0 ) + { + /* Determine how many trailing zeros in PinkIndex. */ + /* This algorithm will hang if n==0 so test first. */ + int numZeros = 0; + int n = pink->pink_Index; + while( (n & 1) == 0 ) + { + n = n >> 1; + numZeros++; + } + /* Replace the indexed ROWS random value. + * Subtract and add back to RunningSum instead of adding all the random + * values together. Only one changes each time. + */ + pink->pink_RunningSum -= pink->pink_Rows[numZeros]; + newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; + pink->pink_RunningSum += newRandom; + pink->pink_Rows[numZeros] = newRandom; + } + + /* Add extra white noise value. */ + newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; + sum = pink->pink_RunningSum + newRandom; + /* Scale to range of -1.0 to 0.9999. */ + output = pink->pink_Scalar * sum; +#ifdef PINK_MEASURE + /* Check Min/Max */ + if( output > pinkMax ) pinkMax = output; + else if( output < pinkMin ) pinkMin = output; +#endif + return output; +} +/*******************************************************************/ +#define PINK_TEST +#ifdef PINK_TEST +/* Context for callback routine. */ +typedef struct +{ + PinkNoise leftPink; + PinkNoise rightPink; + unsigned int sampsToGo; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + int finished; + int i; + int numFrames; + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + (void) outTime; + + /* Are we almost at end. */ + if( data->sampsToGo < framesPerBuffer ) + { + numFrames = data->sampsToGo; + finished = 1; + } + else + { + numFrames = framesPerBuffer; + finished = 0; + } + for( i=0; ileftPink ); + *out++ = GeneratePinkNoise( &data->rightPink ); + } + data->sampsToGo -= numFrames; + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int totalSamps; + /* Initialize two pink noise signals with different numbers of rows. */ + InitializePinkNoise( &data.leftPink, 12 ); + InitializePinkNoise( &data.rightPink, 16 ); + /* Look at a few values. */ + { + int i; + float pink; + for( i=0; i<20; i++ ) + { + pink = GeneratePinkNoise( &data.leftPink ); + printf("Pink = %f\n", pink ); + } + } + data.sampsToGo = totalSamps = 8*44100; /* Play for a few seconds. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + /* Open a stereo PortAudio stream so we can hear the result. */ + err = Pa_OpenStream( + &stream, + paNoDevice, + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + Pa_GetDefaultOutputDeviceID(), /* default output device */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + NULL, + 44100., + 2048, /* 46 msec buffers */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Waiting for sound to finish.\n"); + while( Pa_StreamActive( stream ) ) + { + Pa_Sleep(100); /* SPIN! */ + } + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; +#ifdef PINK_MEASURE + printf("Pink min = %f, max = %f\n", pinkMin, pinkMax ); +#endif + Pa_Terminate(); + return 0; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return 0; +} +#endif /* PINK_TEST */ diff --git a/pa_tests/patest_record.c b/pa_tests/patest_record.c new file mode 100644 index 0000000..47ccec1 --- /dev/null +++ b/pa_tests/patest_record.c @@ -0,0 +1,303 @@ +/* + * $Id$ + * patest_record.c + * Record input into an array. + * Save array to a file. + * Playback recorded data. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" + +/* #define SAMPLE_RATE (17932) /* Test failure to open with this value. */ +#define SAMPLE_RATE (44100) +#define NUM_SECONDS (5) + +/* Select sample format. */ +#if 0 +#define PA_SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#elif 0 +#define PA_SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#else +#define PA_SAMPLE_TYPE paUInt8 +typedef unsigned char SAMPLE; +#endif + +typedef struct +{ + int frameIndex; /* Index into sample array. */ + int maxFrameIndex; + int samplesPerFrame; + SAMPLE *recordedSamples; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int recordCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE *rptr = (SAMPLE*)inputBuffer; + SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; + long framesToCalc; + long i; + int finished; + unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; + + (void) outputBuffer; /* Prevent unused variable warnings. */ + (void) outTime; + + if( framesLeft < framesPerBuffer ) + { + framesToCalc = framesLeft; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + finished = 0; + } + if( inputBuffer == NULL ) + { + for( i=0; iframeIndex += framesToCalc; + return finished; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int playCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; + SAMPLE *wptr = (SAMPLE*)outputBuffer; + unsigned int i; + int finished; + unsigned int framesLeft = data->maxFrameIndex - data->frameIndex; + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) outTime; + + if( framesLeft < framesPerBuffer ) + { + /* final buffer... */ + for( i=0; iframeIndex += framesLeft; + finished = 1; + } + else + { + for( i=0; iframeIndex += framesPerBuffer; + finished = 0; + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int totalFrames; + int numSamples; + int numBytes; + SAMPLE max, average, val; + printf("patest_record.c\n"); fflush(stdout); + + data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */ + data.frameIndex = 0; + data.samplesPerFrame = 2; + numSamples = totalFrames * data.samplesPerFrame; + + numBytes = numSamples * sizeof(SAMPLE); + data.recordedSamples = (SAMPLE *) malloc( numBytes ); + if( data.recordedSamples == NULL ) + { + printf("Could not allocate record array.\n"); + exit(1); + } + for( i=0; i max ) + { + max = val; + } + average += val; + } + printf("sample max amplitude = %d\n", max ); + average = average / numSamples; + printf("sample average = %d\n", average ); + + /* Write recorded data to a file. */ +#if 0 + { + FILE *fid; + fid = fopen("recorded.raw", "wb"); + if( fid == NULL ) + { + printf("Could not open file."); + } + else + { + fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid ); + fclose( fid ); + printf("Wrote data to 'recorded.raw'\n"); + } + } +#endif + + /* Playback recorded data. -------------------------------------------- */ + data.frameIndex = 0; + printf("Begin playback.\n"); fflush(stdout); + err = Pa_OpenStream( + &stream, + paNoDevice, + 0, /* NO input */ + PA_SAMPLE_TYPE, + NULL, + Pa_GetDefaultOutputDeviceID(), + data.samplesPerFrame, /* stereo output */ + PA_SAMPLE_TYPE, + NULL, + SAMPLE_RATE, + 1024, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + playCallback, + &data ); + if( err != paNoError ) goto error; + + if( stream ) + { + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Waiting for playback to finish.\n"); fflush(stdout); + + while( Pa_StreamActive( stream ) ) Pa_Sleep(100); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + printf("Done.\n"); fflush(stdout); + } + free( data.recordedSamples ); + + Pa_Terminate(); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} diff --git a/pa_tests/patest_ringmix.c b/pa_tests/patest_ringmix.c new file mode 100644 index 0000000..0bae220 --- /dev/null +++ b/pa_tests/patest_ringmix.c @@ -0,0 +1,41 @@ +/* $Id$ */ + +#include "stdio.h" +#include "portaudio.h" +/* This will be called asynchronously by the PortAudio engine. */ +static int myCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) +{ + float *out = (float *) outputBuffer; + float *in = (float *) inputBuffer; + float leftInput, rightInput; + unsigned int i; + if( inputBuffer == NULL ) return 0; + /* Read input buffer, process data, and fill output buffer. */ + for( i=0; i +#include +#include "portaudio.h" +#define NUM_SECONDS (4) +#define SAMPLE_RATE (44100) +typedef struct +{ + float left_phase; + float right_phase; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + /* Cast data passed through stream to our structure. */ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( i=0; ileft_phase; /* left */ + *out++ = data->right_phase; /* right */ + /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */ + data->left_phase += 0.01f; + /* When signal reaches top, drop back down. */ + if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f; + /* higher pitch so we can distinguish left and right. */ + data->right_phase += 0.03f; + if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f; + } + return 0; +} +/*******************************************************************/ +static paTestData data; +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + printf("PortAudio Test: output sawtooth wave.\n"); + /* Initialize our data for use by callback. */ + data.left_phase = data.right_phase = 0.0; + /* Initialize library before making any other calls. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + /* Open an audio I/O stream. */ + err = Pa_OpenDefaultStream( + &stream, + 0, /* no input channels */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + SAMPLE_RATE, + 256, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + /* Sleep for several seconds. */ + Pa_Sleep(NUM_SECONDS*1000); + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/pa_tests/patest_sine.c b/pa_tests/patest_sine.c new file mode 100644 index 0000000..f6d8f6a --- /dev/null +++ b/pa_tests/patest_sine.c @@ -0,0 +1,138 @@ +/* + * $Id$ + * $Id$ + * patest_sine.c + * Play a sine wave using the Portable Audio api for several seconds. + * + * Authors: + * Ross Bencina + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; i + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (8) +#define SAMPLE_RATE (44100) +#define TEST_UNSIGNED (1) +#if TEST_UNSIGNED +#define TEST_FORMAT paUInt8 +#else +#define TEST_FORMAT paInt8 +#endif +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +typedef struct +{ +#if TEST_UNSIGNED + unsigned char sine[TABLE_SIZE]; +#else + char sine[TABLE_SIZE]; +#endif + int left_phase; + int right_phase; + unsigned int framesToGo; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + char *out = (char*)outputBuffer; + int i; + int framesToCalc; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + if( data->framesToGo < framesPerBuffer ) + { + framesToCalc = data->framesToGo; + data->framesToGo = 0; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + data->framesToGo -= framesPerBuffer; + } + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + /* zero remainder of final buffer */ + for( ; i<(int)framesPerBuffer; i++ ) + { +#if TEST_UNSIGNED + *out++ = (unsigned char) 0x80; /* left */ + *out++ = (unsigned char) 0x80; /* right */ +#else + *out++ = 0; /* left */ + *out++ = 0; /* right */ +#endif + + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int totalSamps; +#if TEST_UNSIGNED + printf("PortAudio Test: output UNsigned 8 bit sine wave.\n"); +#else + printf("PortAudio Test: output signed 8 bit sine wave.\n"); +#endif + /* initialise sinusoidal wavetable */ + for( i=0; i +#include +#include "portaudio.h" + +#define NUM_SECONDS (20) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#define LEFT_FREQ (SAMPLE_RATE/256.0) /* So we hit 1.0 */ +#define RIGHT_FREQ (500.0) +#define AMPLITUDE (1.0) + +/* Select ONE format for testing. */ +#define TEST_UINT8 (0) +#define TEST_INT8 (0) +#define TEST_INT16 (1) +#define TEST_FLOAT32 (0) + +#if TEST_UINT8 +#define TEST_FORMAT paUInt8 +typedef unsigned char SAMPLE_t; +#define SAMPLE_ZERO (0x80) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) +#define FORMAT_NAME "Unsigned 8 Bit" +#endif + +#if TEST_INT8 +#define TEST_FORMAT paInt8 +typedef char SAMPLE_t; +#define SAMPLE_ZERO (0) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) +#define FORMAT_NAME "Signed 8 Bit" +#endif + +#if TEST_INT16 +#define TEST_FORMAT paInt16 +typedef short SAMPLE_t; +#define SAMPLE_ZERO (0) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767.0 * (x))) +#define FORMAT_NAME "Signed 16 Bit" +#endif + +#if TEST_FLOAT32 +#define TEST_FORMAT paFloat32 +typedef float SAMPLE_t; +#define SAMPLE_ZERO (0.0) +#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x)) +#define FORMAT_NAME "Float 32 Bit" +#endif + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + + +typedef struct +{ + double left_phase; + double right_phase; + unsigned int framesToGo; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE_t *out = (SAMPLE_t *)outputBuffer; + int i; + int framesToCalc; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + if( data->framesToGo < framesPerBuffer ) + { + framesToCalc = data->framesToGo; + data->framesToGo = 0; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + data->framesToGo -= framesPerBuffer; + } + + for( i=0; ileft_phase += (LEFT_FREQ / SAMPLE_RATE); + if( data->left_phase > 1.0) data->left_phase -= 1.0; + *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); + + data->right_phase += (RIGHT_FREQ / SAMPLE_RATE); + if( data->right_phase > 1.0) data->right_phase -= 1.0; + *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); + } + /* zero remainder of final buffer */ + for( ; i<(int)framesPerBuffer; i++ ) + { + *out++ = SAMPLE_ZERO; /* left */ + *out++ = SAMPLE_ZERO; /* right */ + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int totalSamps; + + printf("PortAudio Test: output " FORMAT_NAME "\n"); + + + data.left_phase = data.right_phase = 0.0; + data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + err = Pa_OpenStream( + &stream, + paNoDevice,/* default input device */ + 0, /* no input */ + TEST_FORMAT, + NULL, + Pa_GetDefaultOutputDeviceID(), /* default output device */ + 2, /* stereo output */ + TEST_FORMAT, + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS ); + while( Pa_StreamActive( stream ) ) Pa_Sleep(10); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + + printf("PortAudio Test Finished: " FORMAT_NAME "\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/pa_tests/patest_sine_time.c b/pa_tests/patest_sine_time.c new file mode 100644 index 0000000..9b9cf3b --- /dev/null +++ b/pa_tests/patest_sine_time.c @@ -0,0 +1,165 @@ +/* + * $Id$ + * patest_sine_time.c + * Play a sine wave using the Portable Audio api for several seconds. + * Pausing in the middle. + * use the Pa_StreamTime() and Pa_StreamActive() calls. + * + * Authors: + * Ross Bencina + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (8) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + int framesToGo; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + int i; + int framesToCalc; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + if( data->framesToGo < framesPerBuffer ) + { + framesToCalc = data->framesToGo; + data->framesToGo = 0; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + data->framesToGo -= framesPerBuffer; + } + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + /* zero remainder of final buffer */ + for( ; i<(int)framesPerBuffer; i++ ) + { + *out++ = 0; /* left */ + *out++ = 0; /* right */ + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + int totalSamps; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; i + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +#define SLEEP_DUR (200) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#define LATENCY_MSEC (3000) +#define NUM_BUFFERS ((LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) +#define FRAMES_PER_NOTE (SAMPLE_RATE/2) +#define MAX_REPEATS (2) +#define FUNDAMENTAL (400.0f / SAMPLE_RATE) +#define NOTE_0 (FUNDAMENTAL * 1.0f / 1.0f) +#define NOTE_1 (FUNDAMENTAL * 5.0f / 4.0f) +#define NOTE_2 (FUNDAMENTAL * 4.0f / 3.0f) +#define NOTE_3 (FUNDAMENTAL * 3.0f / 2.0f) +#define NOTE_4 (FUNDAMENTAL * 2.0f / 1.0f) +#define MODE_FINISH (0) +#define MODE_STOP (1) +#define MODE_ABORT (2) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (400) +typedef struct +{ + float waveform[TABLE_SIZE + 1]; // add one for guard point for interpolation + float phase_increment; + float phase; + float *tune; + int notesPerTune; + int frameCounter; + int noteCounter; + int repeatCounter; + PaTimestamp outTime; + int stopMode; + int done; +} +paTestData; +/************* Prototypes *****************************/ +int TestStopMode( paTestData *data ); +float LookupWaveform( paTestData *data, float phase ); +/****************************************************** + * Convert phase between 0.0 and 1.0 to waveform value + * using linear interpolation. + */ +float LookupWaveform( paTestData *data, float phase ) +{ + float fIndex = phase*TABLE_SIZE; + int index = (int) fIndex; + float fract = fIndex - index; + float lo = data->waveform[index]; + float hi = data->waveform[index+1]; + float val = lo + fract*(hi-lo); + return val; +} +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + float value; + unsigned int i = 0; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + data->outTime = outTime; + if( !data->done ) + { + for( i=0; iframeCounter >= FRAMES_PER_NOTE ) + { + data->noteCounter += 1; + data->frameCounter = 0; + /* Are we done with this tune? */ + if( data->noteCounter >= data->notesPerTune ) + { + data->noteCounter = 0; + data->repeatCounter += 1; + /* Are we totally done? */ + if( data->repeatCounter >= MAX_REPEATS ) + { + data->done = 1; + if( data->stopMode == MODE_FINISH ) + { + finished = 1; + break; + } + } + } + data->phase_increment = data->tune[data->noteCounter]; + } + value = LookupWaveform(data, data->phase); + *out++ = value; /* left */ + *out++ = value; /* right */ + data->phase += data->phase_increment; + if( data->phase >= 1.0f ) data->phase -= 1.0f; + + data->frameCounter += 1; + } + } + /* zero remainder of final buffer */ + for( ; idone = 0; + data->phase = 0.0; + data->frameCounter = 0; + data->noteCounter = 0; + data->repeatCounter = 0; + data->phase_increment = data->tune[data->noteCounter]; + err = Pa_Initialize(); + if( err != paNoError ) goto error; + err = Pa_OpenStream( + &stream, + paNoDevice,/* default input device */ + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + OUTPUT_DEVICE, + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + NUM_BUFFERS, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + if( data->stopMode == MODE_FINISH ) + { + while( Pa_StreamActive( stream ) ) + { + /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime, + data->noteCounter, data->repeatCounter ); + fflush(stdout); /**/ + Pa_Sleep( SLEEP_DUR ); + } + } + else + { + while( data->repeatCounter < MAX_REPEATS ) + { + /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime, + data->noteCounter, data->repeatCounter ); + fflush(stdout); /**/ + Pa_Sleep( SLEEP_DUR ); + } + } + if( data->stopMode == MODE_ABORT ) + { + printf("Call Pa_AbortStream()\n"); + err = Pa_AbortStream( stream ); + } + else + { + printf("Call Pa_StopStream()\n"); + err = Pa_StopStream( stream ); + } + if( err != paNoError ) goto error; + printf("Call Pa_CloseStream()\n"); fflush(stdout); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/pa_tests/patest_sync.c b/pa_tests/patest_sync.c new file mode 100644 index 0000000..e2eb88a --- /dev/null +++ b/pa_tests/patest_sync.c @@ -0,0 +1,227 @@ +/* + * $Id$ + * patest_sync.c + * Test time stamping and synchronization of audio and video. + * A high latency is used so we can hear the difference in time. + * Random durations are used so we know we are hearing the right beep + * and not the one before or after. + * + * Sequence of events: + * Foreground requests a beep. + * Background randomly schedules a beep. + * Foreground waits for the beep to be heard based on Pa_StreamTime(). + * Foreground outputs video (printf) in sync with audio. + * Repeat. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define NUM_BEEPS (6) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#define BEEP_DURATION (1000) +#define LATENCY_MSEC (2000) +#define SLEEP_MSEC (10) +#define TIMEOUT_MSEC ((3 * LATENCY_MSEC) / (2 * SLEEP_MSEC)) +#define NUM_BUFFERS ((LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) +#define STATE_BKG_IDLE (0) +#define STATE_BKG_PENDING (1) +#define STATE_BKG_BEEPING (2) +typedef struct +{ + float left_phase; + float right_phase; + int state; + int requestBeep; /* Set by foreground, cleared by background. */ + PaTimestamp beepTime; + int beepCount; +} +paTestData; +static unsigned long GenerateRandomNumber( void ); +/************************************************************/ +/* Calculate pseudo-random 32 bit number based on linear congruential method. */ +static unsigned long GenerateRandomNumber( void ) +{ + static unsigned long randSeed = 22222; /* Change this for different random sequences. */ + randSeed = (randSeed * 196314165) + 907633515; + return randSeed; +} +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + /* Cast data passed through stream to our structure. */ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + (void) inputBuffer; + + for( i=0; istate ) + { + case STATE_BKG_IDLE: + /* Schedule beep at some random time in the future. */ + if( data->requestBeep ) + { + int random = GenerateRandomNumber() >> 14; + data->beepTime = outTime + (i + random + (SAMPLE_RATE/4)); + data->state = STATE_BKG_PENDING; + data->requestBeep = 0; + data->left_phase = data->right_phase = 0.0; + } + *out++ = 0.0; /* left */ + *out++ = 0.0; /* right */ + break; + case STATE_BKG_PENDING: + if( (outTime + i) >= data->beepTime ) + { + data->state = STATE_BKG_BEEPING; + data->beepCount = BEEP_DURATION; + } + *out++ = 0.0; /* left */ + *out++ = 0.0; /* right */ + break; + case STATE_BKG_BEEPING: + if( data->beepCount <= 0 ) + { + data->state = STATE_BKG_IDLE; + *out++ = 0.0; /* left */ + *out++ = 0.0; /* right */ + } + else + { + /* Play sawtooth wave. */ + *out++ = data->left_phase; /* left */ + *out++ = data->right_phase; /* right */ + /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */ + data->left_phase += 0.01f; + /* When signal reaches top, drop back down. */ + if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f; + /* higher pitch so we can distinguish left and right. */ + data->right_phase += 0.03f; + if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f; + } + data->beepCount -= 1; + break; + default: + data->state = STATE_BKG_IDLE; + break; + } + } + return 0; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData DATA; + int i, timeout; + PaTimestamp previousTime; + printf("PortAudio Test: you should see BEEP at the same time you hear it.\n"); + printf("Wait for a few seconds random delay between BEEPs.\n"); + printf("BEEP %d times.\n", NUM_BEEPS ); + /* Initialize our DATA for use by callback. */ + DATA.left_phase = DATA.right_phase = 0.0; + DATA.state = STATE_BKG_IDLE; + DATA.requestBeep = 0; + /* Initialize library before making any other calls. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + /* Open an audio I/O stream. */ + err = Pa_OpenDefaultStream( + &stream, + 0, /* no input channels */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + SAMPLE_RATE, + FRAMES_PER_BUFFER, + NUM_BUFFERS, + patestCallback, + &DATA ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + previousTime = Pa_StreamTime( stream ); + for( i=0; i 0 ) ) Pa_Sleep(SLEEP_MSEC); + if( timeout <= 0 ) + { + fprintf( stderr, "Timed out waiting for background to acknowledge request.\n" ); + goto error; + } + /* Wait for scheduled beep time. */ + timeout = TIMEOUT_MSEC + (10000/SLEEP_MSEC); + while( (Pa_StreamTime( stream ) < DATA.beepTime) && (timeout-- > 0 ) ) + { + Pa_Sleep(SLEEP_MSEC); + } + if( timeout <= 0 ) + { + fprintf( stderr, "Timed out waiting for time. Now = %g, Beep for %g.\n", + Pa_StreamTime( stream ), DATA.beepTime ); + goto error; + } + /* Beep should be sounding now so print synchronized BEEP. */ + printf("BEEP"); + fflush(stdout); + printf(" at %d, delta = %d\n", + (long) DATA.beepTime, (long) (DATA.beepTime - previousTime) ); + fflush(stdout); + previousTime = DATA.beepTime; + } + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/pa_tests/patest_underflow.c b/pa_tests/patest_underflow.c new file mode 100644 index 0000000..ca07cf4 --- /dev/null +++ b/pa_tests/patest_underflow.c @@ -0,0 +1,151 @@ +/* + * $Id$ + * patest_underflow.c + * Simulate an output buffer underflow condition. + * Tests whether the stream can be stopped when underflowing buffers. + * + * Authors: + * Ross Bencina + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (20) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (2048) +#define MSEC_PER_BUFFER ( (FRAMES_PER_BUFFER * 1000) / SAMPLE_RATE ) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + int sleepTime; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + /* Cause underflow to occur. */ + if( data->sleepTime > 0 ) Pa_Sleep( data->sleepTime ); + data->sleepTime += 1; + + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int i; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; i +#include +#include "portaudio.h" +/* +** Note that many of the older ISA sound cards on PCs do NOT support +** full duplex audio (simultaneous record and playback). +** And some only support full duplex at lower sample rates. +*/ +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) +#if 1 +#define PA_SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#else +#define PA_SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#endif +static int wireCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int wireCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + SAMPLE *out = (SAMPLE*)outputBuffer; + SAMPLE *in = (SAMPLE*)inputBuffer; + unsigned int i; + int finished = 0; + (void) outTime; + + /* This may get called with NULL inputBuffer during initial setup. */ + if( inputBuffer == NULL ) + { + for( i=0; iJV_VPg}vVpflr&clN4ctL+YE&U7Sw$Nrvj#V9W!?cY$ zC`VjAku{{~Rhz%cu2sOcwF=P{YCodiN5gbJ8_|3=JEPZ&vp2N-oMqY46z(6RY;Pke z$K-9jli>L7sC9Nzb3>tG>YT;nPVE#zLoZ2p=y`+zuucjt4j znzm*?BwZ#ng2H1zTe6N`Z2Ruw#V&fWO%hDt8*A(&%LaudV*{1eZ3Uktl?S~8iB!hA z4iV=)QKv(NT|$s>@^F8*`uOqY?g59#vK(duiF%}_blL|h_!Ov5SQ!vkvB4hHI>iZ2 zZ@277mB=AIxn5q8_F3z=)O8I;2cDTWT-$Cq%(8oM2{3g{TfO6yivs4LYSN~S3BQd& zKGjIU5>{Id9SD$XKA8uE-U#Q32C}f&fTs)xe=|im9A&2K=wb4PVT7OkZGbtoAj*?b3 z)&=B4jfFNtg;*&23oUg{2ObQGF6fD#vlGlxpq}xv04oqiA>>-9I+1$hd6NAJRRvpk z09K`fJ+qKO;cSaH9tlIqH4n~)^h-u!y#lAcIIx8CX?cBxmn}P}sCj^`ACfMx5>^mA z&l|Ari2eB?2|Sb@FaMThtMVjLMJW7{eR^bPxF!)&tM;S8r^KAiAH}7*pz{}%)#9(Vj-Ggjm=Su)t=X{?UG_?nC7T#B#1!kJEZ|m7JR8qb zB&W=lX?eR`eLn-j=A5*XT1g-+ikZoEJmA5EC6 zRslDV-6O`az2ZDbyKe=hHX!}DzTlP(*gDAP6jnrvo;Q*zkZOD0q~9Kz3t5N|ZbF`Z zkH*;GM0gMlc9f;zgzr@d?P5CZx^7Zy6Q2@A1@9*4fJB1tlf`gB-}pgZ(=xT|Yj9oL zwt+e@Jmlw#kts96Y>^q0#>=R8k+T><*(G6x44v`pyYc)D&CeF+ujw~4JQ~rzO-h+D z{SIuxw)J{?>(KV#S0tO-OFwR;%D)z5GATU$E-g=g?!n_X9uukAhiZaH_+3#2I!Kh` zC$tz3`^S=DiQX(qNc3x)hkCI7@%rlihllI+PY>&x``f$a$ImxE-Ve#gJjcwFwi_x$ z*r_@KlS&1~fwQNx*=+V(8ery2YaM?`=!B@D7)F$Fsw-OiB`hipywcl>a8ro*2Yqdr z@|u-{As|nkv*=}X=+8c4On9hG@FIeiT))Lk{ZQHf-KH%aI6sh~q5O)B3ir8h8i1`NFBGL+-OowG}5Ic&Q9Z3qTP8RN+1(124i>TSCJz5w|)W&`}Qe zslm ;-) + 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. + +TODO +O- change Pa_StreamTime() to query device (patest_sync.c) +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) ??? +*/ +/* + 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 +#include +#include +#include +#include +#include "portaudio.h" +#include "pa_host.h" +#include "pa_trace.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#else +#include /* JH20010905 */ +#endif + +#include +#include + +/* Some versions of OSS do not define AFMT_S16_NE. Assume little endian. FIXME - check CPU*/ +#ifndef AFMT_S16_NE + #define AFMT_S16_NE AFMT_S16_LE +#endif + +#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; + pthread_t pahsc_ThreadPID; + 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. */ +} +PaHostSoundControl; + +/************************************************* Shared Data ********/ +/* FIXME - put Mutex around this shared data. */ +static int sDeviceIndex = 0; +static internalPortAudioDevice *sDeviceList = NULL; +static int sDefaultInputDeviceID = paNoDevice; +static int sDefaultOutputDeviceID = paNoDevice; +static int sEnumerationError; +static int sPaHostError = 0; + +/************************************************* Prototypes **********/ + +static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ); +static Pa_QueryDevices( void ); +static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ); +static PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate ); + +/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ +static void Pa_StartUsageCalculation( internalPortAudioStream *past ) +{ + struct itimerval itimer; + 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( ¤tTime, NULL ) == 0 ) + { + usecsElapsed = SubtractTime_AminusB( ¤tTime, &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 *******/ + +/********************************************************************* + * Try to open the named device. + * If it opens, try to set various rates and formats and fill in + * the device info structure. + */ +static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ) +{ + int result = paHostError; + int numBytes; + int tempDevHandle; + int numChannels, maxNumChannels; + int format; + int numSampleRates; + int sampleRate; + int numRatesToTry; + 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 settins. + 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)) == -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. + */ + numSampleRates = 0; + numRatesToTry = sizeof(ratesToTry)/sizeof(int); + for (i = 0; i < numRatesToTry; i++) + { + sampleRate = ratesToTry[i]; + + if (ioctl(tempDevHandle, SNDCTL_DSP_SPEED, &sampleRate) >= 0 ) /* PLB20010817 */ + { + if (sampleRate == ratesToTry[i]) + { + DBUG(("Pa_QueryDevice: got sample rate: %d\n", sampleRate)) + pad->pad_SampleRates[numSampleRates] = (float)ratesToTry[i]; + numSampleRates++; + } + } + } + + DBUG(("Pa_QueryDevice: final numSampleRates = %d\n", numSampleRates)) + if (numSampleRates==0) /* HP20010922 */ + { + ERR_RPT(("Pa_QueryDevice: no supported sample rate (or SNDCTL_DSP_SPEED ioctl call failed).\n" )); + goto error; + } + + pad->pad_Info.numSampleRates = numSampleRates; + pad->pad_Info.sampleRates = pad->pad_SampleRates; + + 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; +} + +/********************************************************************* + * 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. + */ +static PaError Pa_QueryDevices( void ) +{ + internalPortAudioDevice *pad, *lastPad; + int numBytes; + int go = 1; + int numDevices = 0; + PaError testResult; + PaError result = paNoError; + + sDefaultInputDeviceID = paNoDevice; + sDefaultOutputDeviceID = paNoDevice; + + lastPad = NULL; + + while( go ) + { + /* Allocate structure to hold device info. */ + pad = 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; + } + } + + 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; +} + +/*************************************************************************/ +static 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(); +} + +/*******************************************************************************************/ +static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) +{ + PaError result = 0; + PaHostSoundControl *pahsc; + short bytes_read = 0; + +#ifdef GNUSTEP + GSRegisterCurrentThread(); /* SB20010904 */ +#endif + +#if 1 + { +#define SCHEDULER_POLICY SCHED_RR + + struct sched_param schp; + memset(&schp, 0, sizeof(schp)); + schp.sched_priority = sched_get_priority_max(SCHEDULER_POLICY); + + if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) + { + perror("sched_setscheduler"); + printf("PortAudio: only superuser can use real-time priority.\n"); + } + else + { + printf("PortAudio: callback priority set to level %d!\n", schp.sched_priority); + } + } +#endif + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paInternalError; + + past->past_IsActive = 1; + DBUG(("entering thread.\n")); + + while( (past->past_StopNow == 0) && (past->past_StopSoon == 0) ) + { + + DBUG(("go!\n")); + /* Read data from device */ + if(pahsc->pahsc_NativeInputBuffer) + { + bytes_read = read(pahsc->pahsc_InputHandle, + (void *)pahsc->pahsc_NativeInputBuffer, + pahsc->pahsc_BytesPerInputBuffer); + + DBUG(("bytes_read: %d\n", bytes_read)); + } + + /* 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 ) + { + + write(pahsc->pahsc_OutputHandle, + (void *)pahsc->pahsc_NativeOutputBuffer, + pahsc->pahsc_BytesPerOutputBuffer); + } + } + + past->past_IsActive = 0; + DBUG(("leaving thread.\n")); + +#ifdef GNUSTEP + GSUnregisterCurrentThread(); /* SB20010904 */ +#endif + return 0; +} + +/*******************************************************************************************/ +static 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. 44100, 22050 and 11025 are safe bets. */ + tmp = sampleRate; + if( ioctl(devHandle,SNDCTL_DSP_SPEED,&tmp) == -1) + { + ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_SPEED\n" )); + return paHostError; + } + if( tmp != sampleRate) + { + ERR_RPT(("Pa_SetupDeviceFormat: HW does not support %d Hz sample rate\n",sampleRate )); + return paHostError; + } + + return result; +} + +static int CalcHigherLogTwo( int n ) +{ + int log2 = 0; + while( (1< 8 ) + { + numBuffers = (numBuffers + 1) >> 1; + framesPerBuffer = framesPerBuffer << 1; + } + + /* calculate size of buffers in bytes */ + bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME */ + + /* 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 )); + } +} + +/************************************************************************* +** 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; + int tmp; + int flags; + int numBytes, maxChannels; + 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; + + /* 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(("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 )); + 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 )); + 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_SetupDeviceFormat( 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 )); + 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_SetupDeviceFormat( 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 ) +{ + return paNoError; +} + +/*************************************************************************/ +PaError PaHost_StartInput( internalPortAudioStream *past ) +{ + 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_ThreadPID), + NULL /*pthread_attr_t * attr*/, + (void*)Pa_AudioThreadProc, past); + if( hres != 0 ) + { + result = paHostError; + sPaHostError = hres; + goto error; + } + +error: + return result; +} + +/*************************************************************************/ +PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) +{ + int hres; + long timeOut; + 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_ThreadPID != -1 ) + { + /* This check is needed for GNUSTEP - SB20010904 */ + if ( !pthread_equal( pahsc->pahsc_ThreadPID, pthread_self() ) ) + { + hres = pthread_join( pahsc->pahsc_ThreadPID, 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_ThreadPID = -1; + } + + past->past_IsActive = 0; + + return result; +} + +/*************************************************************************/ +PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) +{ + return paNoError; +} + +/*************************************************************************/ +PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) +{ + 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; + DBUG(("PaHost_CloseStream: attempt to close output device handle = %d\n", + 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; + DBUG(("PaHost_CloseStream: attempt to close input device handle = %d\n", + 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 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 ) +{ + 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); +} + +/***********************************************************************/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + internalPortAudioStream *past = (internalPortAudioStream *) stream; + /* FIXME - return actual frames played, not frames generated. + ** Need to query the output device somehow. + */ + if( past == NULL ) return paBadStreamPtr; + return past->past_FrameCount; +} + +/***********************************************************************/ +long Pa_GetHostError( void ) +{ + return (long) sPaHostError; +} diff --git a/pa_unix_oss/recplay.c b/pa_unix_oss/recplay.c new file mode 100644 index 0000000..9d4c78c --- /dev/null +++ b/pa_unix_oss/recplay.c @@ -0,0 +1,114 @@ +/* + * recplay.c + * Phil Burk + * Minimal record and playback test. + * + */ +#include +#include +#include +#ifndef __STDC__ +/* #include */ +#endif /* __STDC__ */ +#include +#ifdef __STDC__ +#include +#else /* __STDC__ */ +#include +#endif /* __STDC__ */ +#include + +#define NUM_BYTES (64*1024) +#define BLOCK_SIZE (4*1024) + +#define AUDIO "/dev/dsp" + +char buffer[NUM_BYTES]; + +int audioDev = 0; + +main (int argc, char *argv[]) +{ + int numLeft; + char *ptr; + int num; + int samplesize; + + /********** RECORD ********************/ + /* Open audio device. */ + audioDev = open (AUDIO, O_RDONLY, 0); + if (audioDev == -1) + { + perror (AUDIO); + exit (-1); + } + + /* Set to 16 bit samples. */ + samplesize = 16; + ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); + if (samplesize != 16) + { + perror("Unable to set the sample size."); + exit(-1); + } + + /* Record in blocks */ + printf("Begin recording.\n"); + numLeft = NUM_BYTES; + ptr = buffer; + while( numLeft >= BLOCK_SIZE ) + { + if ( (num = read (audioDev, ptr, BLOCK_SIZE)) < 0 ) + { + perror (AUDIO); + exit (-1); + } + else + { + printf("Read %d bytes\n", num); + ptr += num; + numLeft -= num; + } + } + + close( audioDev ); + + /********** PLAYBACK ********************/ + /* Open audio device for writing. */ + audioDev = open (AUDIO, O_WRONLY, 0); + if (audioDev == -1) + { + perror (AUDIO); + exit (-1); + } + + /* Set to 16 bit samples. */ + samplesize = 16; + ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); + if (samplesize != 16) + { + perror("Unable to set the sample size."); + exit(-1); + } + + /* Play in blocks */ + printf("Begin playing.\n"); + numLeft = NUM_BYTES; + ptr = buffer; + while( numLeft >= BLOCK_SIZE ) + { + if ( (num = write (audioDev, ptr, BLOCK_SIZE)) < 0 ) + { + perror (AUDIO); + exit (-1); + } + else + { + printf("Wrote %d bytes\n", num); + ptr += num; + numLeft -= num; + } + } + + close( audioDev ); +} diff --git a/pa_win_ds/dsound_wrapper.c b/pa_win_ds/dsound_wrapper.c new file mode 100644 index 0000000..e795525 --- /dev/null +++ b/pa_win_ds/dsound_wrapper.c @@ -0,0 +1,466 @@ +/* + * $Id$ + * Simplified DirectSound interface. + * + * Author: Phil Burk & Robert Marsanyi + * + * PortAudio Portable Real-Time Audio Library + * For more information see: http://www.softsynth.com/portaudio/ + * DirectSound Implementation + * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi + * + * 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 +#include +#include +#define INITGUID // Needed to build IID_IDirectSoundNotify. See objbase.h for info. +#include +#include +#include "dsound_wrapper.h" +#include "pa_trace.h" + +/************************************************************************************/ +void DSW_Term( DSoundWrapper *dsw ) +{ + // Cleanup the sound buffers + if (dsw->dsw_OutputBuffer) + { + IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer ); + IDirectSoundBuffer_Release( dsw->dsw_OutputBuffer ); + dsw->dsw_OutputBuffer = NULL; + } +#if SUPPORT_AUDIO_CAPTURE + if (dsw->dsw_InputBuffer) + { + IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer ); + IDirectSoundCaptureBuffer_Release( dsw->dsw_InputBuffer ); + dsw->dsw_InputBuffer = NULL; + } + if (dsw->dsw_pDirectSoundCapture) + { + IDirectSoundCapture_Release( dsw->dsw_pDirectSoundCapture ); + dsw->dsw_pDirectSoundCapture = NULL; + } +#endif /* SUPPORT_AUDIO_CAPTURE */ + if (dsw->dsw_pDirectSound) + { + IDirectSound_Release( dsw->dsw_pDirectSound ); + dsw->dsw_pDirectSound = NULL; + } +} +/************************************************************************************/ +HRESULT DSW_Init( DSoundWrapper *dsw ) +{ + memset( dsw, 0, sizeof(DSoundWrapper) ); + return 0; +} +/************************************************************************************/ +HRESULT DSW_InitOutputDevice( DSoundWrapper *dsw, LPGUID lpGUID ) +{ + // Create the DS object + HRESULT hr = DirectSoundCreate( lpGUID, &dsw->dsw_pDirectSound, NULL ); + if( hr != DS_OK ) return hr; + return hr; +} + +/************************************************************************************/ +HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer ) +{ + DWORD dwDataLen; + DWORD playCursor; + HRESULT result; + LPDIRECTSOUNDBUFFER pPrimaryBuffer; + HWND hWnd; + HRESULT hr; + WAVEFORMATEX wfFormat; + DSBUFFERDESC primaryDesc; + DSBUFFERDESC secondaryDesc; + unsigned char* pDSBuffData; + LARGE_INTEGER counterFrequency; + dsw->dsw_OutputSize = bytesPerBuffer; + dsw->dsw_OutputRunning = FALSE; + dsw->dsw_OutputUnderflows = 0; + dsw->dsw_FramesWritten = 0; + dsw->dsw_BytesPerFrame = nChannels * sizeof(short); + // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the + // applications's window. Also if that window is closed before the Buffer is closed + // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.) + // So we will use GetDesktopWindow() which was suggested by Miller Puckette. + // hWnd = GetForegroundWindow(); + hWnd = GetDesktopWindow(); + // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz. + // Exclusize also prevents unexpected sounds from other apps during a performance. + if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound, + hWnd, DSSCL_EXCLUSIVE)) != DS_OK) + { + return hr; + } + // ----------------------------------------------------------------------- + // Create primary buffer and set format just so we can specify our custom format. + // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz. + // Setup the primary buffer description + ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC)); + primaryDesc.dwSize = sizeof(DSBUFFERDESC); + primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth + primaryDesc.dwBufferBytes = 0; + primaryDesc.lpwfxFormat = NULL; + // Create the buffer + if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound, + &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result; + // Define the buffer format + wfFormat.wFormatTag = WAVE_FORMAT_PCM; + wfFormat.nChannels = nChannels; + wfFormat.nSamplesPerSec = nFrameRate; + wfFormat.wBitsPerSample = 8 * sizeof(short); + wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8; + wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign; + wfFormat.cbSize = 0; /* No extended format info. */ + // Set the primary buffer's format + if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result; + // ---------------------------------------------------------------------- + // Setup the secondary buffer description + ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC)); + secondaryDesc.dwSize = sizeof(DSBUFFERDESC); + secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; + secondaryDesc.dwBufferBytes = bytesPerBuffer; + secondaryDesc.lpwfxFormat = &wfFormat; + // Create the secondary buffer + if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound, + &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result; + // Lock the DS buffer + if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData, + &dwDataLen, NULL, 0, 0)) != DS_OK) return result; + // Zero the DS buffer + ZeroMemory(pDSBuffData, dwDataLen); + // Unlock the DS buffer + if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result; + if( QueryPerformanceFrequency( &counterFrequency ) ) + { + int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short)); + dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate; + AddTraceMessage("dsw_CounterTicksPerBuffer = %d\n", dsw->dsw_CounterTicksPerBuffer.LowPart ); + } + else + { + dsw->dsw_CounterTicksPerBuffer.QuadPart = 0; + } + // Let DSound set the starting write position because if we set it to zero, it looks like the + // buffer is full to begin with. This causes a long pause before sound starts when using large buffers. + hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset ); + if( hr != DS_OK ) + { + return hr; + } + dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerFrame; + /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */ + return DS_OK; +} + +/************************************************************************************/ +HRESULT DSW_StartOutput( DSoundWrapper *dsw ) +{ + HRESULT hr; + QueryPerformanceCounter( &dsw->dsw_LastPlayTime ); + dsw->dsw_LastPlayCursor = 0; + dsw->dsw_FramesPlayed = 0; + hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 ); + if( hr != DS_OK ) + { + return hr; + } + // Start the buffer playback in a loop. + if( dsw->dsw_OutputBuffer != NULL ) + { + hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING ); + if( hr != DS_OK ) + { + return hr; + } + dsw->dsw_OutputRunning = TRUE; + } + + return 0; +} +/************************************************************************************/ +HRESULT DSW_StopOutput( DSoundWrapper *dsw ) +{ + // Stop the buffer playback + if( dsw->dsw_OutputBuffer != NULL ) + { + dsw->dsw_OutputRunning = FALSE; + return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer ); + } + else return 0; +} + +/************************************************************************************/ +HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty ) +{ + HRESULT hr; + DWORD playCursor; + DWORD writeCursor; + long numBytesEmpty; + long playWriteGap; + // Query to see how much room is in buffer. + // Note: Even though writeCursor is not used, it must be passed to prevent DirectSound from dieing + // under WinNT. The Microsoft documentation says we can pass NULL but apparently not. + // Thanks to Max Rheiner for the fix. + hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor ); + if( hr != DS_OK ) + { + return hr; + } + AddTraceMessage("playCursor", playCursor); + AddTraceMessage("dsw_WriteOffset", dsw->dsw_WriteOffset); + // Determine size of gap between playIndex and WriteIndex that we cannot write into. + playWriteGap = writeCursor - playCursor; + if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap + /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */ + /* Attempt to detect playCursor wrap-around and correct it. */ + if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) ) + { + /* How much time has elapsed since last check. */ + LARGE_INTEGER currentTime; + LARGE_INTEGER elapsedTime; + long bytesPlayed; + long bytesExpected; + long buffersWrapped; + QueryPerformanceCounter( ¤tTime ); + elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart; + dsw->dsw_LastPlayTime = currentTime; + /* How many bytes does DirectSound say have been played. */ + bytesPlayed = playCursor - dsw->dsw_LastPlayCursor; + if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap + dsw->dsw_LastPlayCursor = playCursor; + /* Calculate how many bytes we would have expected to been played by now. */ + bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart); + buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize; + if( buffersWrapped > 0 ) + { + AddTraceMessage("playCursor wrapped! bytesPlayed", bytesPlayed ); + AddTraceMessage("playCursor wrapped! bytesExpected", bytesExpected ); + playCursor += (buffersWrapped * dsw->dsw_OutputSize); + bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize); + } + /* Maintain frame output cursor. */ + dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerFrame); + } + numBytesEmpty = playCursor - dsw->dsw_WriteOffset; + if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset + /* Have we underflowed? */ + if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) ) + { + if( dsw->dsw_OutputRunning ) + { + dsw->dsw_OutputUnderflows += 1; + AddTraceMessage("underflow detected! numBytesEmpty", numBytesEmpty ); + } + dsw->dsw_WriteOffset = writeCursor; + numBytesEmpty = dsw->dsw_OutputSize - playWriteGap; + } + *bytesEmpty = numBytesEmpty; + return hr; +} + +/************************************************************************************/ +HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw ) +{ + HRESULT hr; + LPBYTE lpbuf1 = NULL; + LPBYTE lpbuf2 = NULL; + DWORD dwsize1 = 0; + DWORD dwsize2 = 0; + long bytesEmpty; + hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed + if (hr != DS_OK) return hr; + if( bytesEmpty == 0 ) return DS_OK; + // Lock free space in the DS + hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1, + (void **) &lpbuf2, &dwsize2, 0); + if (hr == DS_OK) + { + // Copy the buffer into the DS + ZeroMemory(lpbuf1, dwsize1); + if(lpbuf2 != NULL) + { + ZeroMemory(lpbuf2, dwsize2); + } + // Update our buffer offset and unlock sound buffer + dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize; + IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); + dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerFrame; + } + return hr; +} + +/************************************************************************************/ +HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes ) +{ + HRESULT hr; + LPBYTE lpbuf1 = NULL; + LPBYTE lpbuf2 = NULL; + DWORD dwsize1 = 0; + DWORD dwsize2 = 0; + // Lock free space in the DS + hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1, + (void **) &lpbuf2, &dwsize2, 0); + if (hr == DS_OK) + { + // Copy the buffer into the DS + CopyMemory(lpbuf1, buf, dwsize1); + if(lpbuf2 != NULL) + { + CopyMemory(lpbuf2, buf+dwsize1, dwsize2); + } + // Update our buffer offset and unlock sound buffer + dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize; + IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); + dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerFrame; + } + return hr; +} + +/************************************************************************************/ +DWORD DSW_GetOutputStatus( DSoundWrapper *dsw ) +{ + DWORD status; + if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK) + return( DSERR_INVALIDPARAM ); + else + return( status ); +} + +#if SUPPORT_AUDIO_CAPTURE +/* These routines are used to support audio input. + * Do NOT compile these calls when using NT4 because it does + * not support the entry points. + */ +/************************************************************************************/ +HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID ) +{ + HRESULT hr = DirectSoundCaptureCreate( lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); + if( hr != DS_OK ) return hr; + return hr; +} +/************************************************************************************/ +HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer ) +{ + DSCBUFFERDESC captureDesc; + WAVEFORMATEX wfFormat; + HRESULT result; + // Define the buffer format + wfFormat.wFormatTag = WAVE_FORMAT_PCM; + wfFormat.nChannels = nChannels; + wfFormat.nSamplesPerSec = nFrameRate; + wfFormat.wBitsPerSample = 8 * sizeof(short); + wfFormat.nBlockAlign = wfFormat.nChannels * (wfFormat.wBitsPerSample / 8); + wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign; + wfFormat.cbSize = 0; /* No extended format info. */ + dsw->dsw_InputSize = bytesPerBuffer; + // ---------------------------------------------------------------------- + // Setup the secondary buffer description + ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC)); + captureDesc.dwSize = sizeof(DSCBUFFERDESC); + captureDesc.dwFlags = 0; + captureDesc.dwBufferBytes = bytesPerBuffer; + captureDesc.lpwfxFormat = &wfFormat; + // Create the capture buffer + if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture, + &captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result; + dsw->dsw_ReadOffset = 0; // reset last read position to start of buffer + return DS_OK; +} + +/************************************************************************************/ +HRESULT DSW_StartInput( DSoundWrapper *dsw ) +{ + // Start the buffer playback + if( dsw->dsw_InputBuffer != NULL ) + { + return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING ); + } + else return 0; +} + +/************************************************************************************/ +HRESULT DSW_StopInput( DSoundWrapper *dsw ) +{ + // Stop the buffer playback + if( dsw->dsw_InputBuffer != NULL ) + { + return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer ); + } + else return 0; +} + +/************************************************************************************/ +HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled ) +{ + HRESULT hr; + DWORD capturePos; + DWORD readPos; + long filled; + // Query to see how much data is in buffer. + // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly + // so let's pass a pointer just to be safe. + hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos ); + if( hr != DS_OK ) + { + return hr; + } + filled = readPos - dsw->dsw_ReadOffset; + if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset + *bytesFilled = filled; + return hr; +} + +/************************************************************************************/ +HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes ) +{ + HRESULT hr; + LPBYTE lpbuf1 = NULL; + LPBYTE lpbuf2 = NULL; + DWORD dwsize1 = 0; + DWORD dwsize2 = 0; + // Lock free space in the DS + hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1, + (void **) &lpbuf2, &dwsize2, 0); + if (hr == DS_OK) + { + // Copy from DS to the buffer + CopyMemory( buf, lpbuf1, dwsize1); + if(lpbuf2 != NULL) + { + CopyMemory( buf+dwsize1, lpbuf2, dwsize2); + } + // Update our buffer offset and unlock sound buffer + dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize; + IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); + } + return hr; +} + +#endif /* SUPPORT_AUDIO_CAPTURE */ diff --git a/pa_win_ds/dsound_wrapper.h b/pa_win_ds/dsound_wrapper.h new file mode 100644 index 0000000..e926514 --- /dev/null +++ b/pa_win_ds/dsound_wrapper.h @@ -0,0 +1,106 @@ +#ifndef __DSOUND_WRAPPER_H +#define __DSOUND_WRAPPER_H +/* + * $Id$ + * Simplified DirectSound interface. + * + * Author: Phil Burk & Robert Marsanyi + * + * For PortAudio Portable Real-Time Audio Library + * For more information see: http://www.softsynth.com/portaudio/ + * DirectSound Implementation + * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi + * + * 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 +#if !defined(BOOL) +#define BOOL short +#endif +#ifndef SUPPORT_AUDIO_CAPTURE +#define SUPPORT_AUDIO_CAPTURE (1) +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define DSW_NUM_POSITIONS (4) +#define DSW_NUM_EVENTS (5) +#define DSW_TERMINATION_EVENT (DSW_NUM_POSITIONS) + +typedef struct +{ + /* Output */ + LPDIRECTSOUND dsw_pDirectSound; + LPDIRECTSOUNDBUFFER dsw_OutputBuffer; + DWORD dsw_WriteOffset; /* last write position */ + INT dsw_OutputSize; + INT dsw_BytesPerFrame; + /* Try to detect play buffer underflows. */ + LARGE_INTEGER dsw_CounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */ + LARGE_INTEGER dsw_LastPlayTime; + UINT dsw_LastPlayCursor; + UINT dsw_OutputUnderflows; + BOOL dsw_OutputRunning; + /* use double which lets us can play for several thousand years with enough precision */ + double dsw_FramesWritten; + double dsw_FramesPlayed; +#if SUPPORT_AUDIO_CAPTURE + /* Input */ + LPDIRECTSOUNDCAPTURE dsw_pDirectSoundCapture; + LPDIRECTSOUNDCAPTUREBUFFER dsw_InputBuffer; + UINT dsw_ReadOffset; /* last read position */ + UINT dsw_InputSize; +#endif /* SUPPORT_AUDIO_CAPTURE */ + +} +DSoundWrapper; +HRESULT DSW_Init( DSoundWrapper *dsw ); +void DSW_Term( DSoundWrapper *dsw ); +HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, + int nChannels, int bufSize ); +HRESULT DSW_StartOutput( DSoundWrapper *dsw ); +HRESULT DSW_StopOutput( DSoundWrapper *dsw ); +DWORD DSW_GetOutputStatus( DSoundWrapper *dsw ); +HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes ); +HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw ); +HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty ); +HRESULT DSW_Enumerate( DSoundWrapper *dsw ); + +#if SUPPORT_AUDIO_CAPTURE +HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, + int nChannels, int bufSize ); +HRESULT DSW_StartInput( DSoundWrapper *dsw ); +HRESULT DSW_StopInput( DSoundWrapper *dsw ); +HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes ); +HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled ); +#endif /* SUPPORT_AUDIO_CAPTURE */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __DSOUND_WRAPPER_H */ diff --git a/pa_win_ds/pa_dsound.c b/pa_win_ds/pa_dsound.c new file mode 100644 index 0000000..96f4753 --- /dev/null +++ b/pa_win_ds/pa_dsound.c @@ -0,0 +1,983 @@ +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.softsynth.com/portaudio/ + * DirectSound 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. + * + */ +/* Modifications + * 7/19/01 Mike Berry - casts for compiling with __MWERKS__ CodeWarrior + * 9/27/01 Phil Burk - use number of frames instead of real-time for CPULoad calculation. + */ +/* Compiler flags: + SUPPORT_AUDIO_CAPTURE - define this flag if you want to SUPPORT_AUDIO_CAPTURE + */ + +#include +#include +#ifndef __MWERKS__ +#include +#include +#endif //__MWERKS__ +#include +#include "portaudio.h" +#include "pa_host.h" +#include "pa_trace.h" +#include "dsound_wrapper.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 PA_USE_HIGH_LATENCY (0) +#if PA_USE_HIGH_LATENCY +#define PA_WIN_9X_LATENCY (500) +#define PA_WIN_NT_LATENCY (600) +#else +#define PA_WIN_9X_LATENCY (140) +#define PA_WIN_NT_LATENCY (280) +#endif +/* Trigger an underflow for testing purposes. Should normally be (0). */ +#define PA_SIMULATE_UNDERFLOW (0) +#if PA_SIMULATE_UNDERFLOW +static gUnderCallbackCounter = 0; +#define UNDER_START_GAP (10) +#define UNDER_STOP_GAP (UNDER_START_GAP + 4) +#endif +/************************************************* Definitions ********/ +typedef struct internalPortAudioStream internalPortAudioStream; +typedef struct internalPortAudioDevice +{ + GUID pad_GUID; + GUID *pad_lpGUID; + double pad_SampleRates[10]; /* for pointing to from pad_Info FIXME?!*/ + PaDeviceInfo pad_Info; +} +internalPortAudioDevice; +/* Define structure to contain all DirectSound and Windows specific data. */ +typedef struct PaHostSoundControl +{ + DSoundWrapper pahsc_DSoundWrapper; + MMRESULT pahsc_TimerID; + BOOL pahsc_IfInsideCallback; /* Test for reentrancy. */ + short *pahsc_NativeBuffer; + unsigned int pahsc_BytesPerBuffer; /* native buffer size in bytes */ + double pahsc_ValidFramesWritten; + int pahsc_FramesPerDSBuffer; + /* For measuring CPU utilization. */ + LARGE_INTEGER pahsc_EntryCount; + double pahsc_InverseTicksPerUserBuffer; +} +PaHostSoundControl; +/************************************************* Shared Data ********/ +/* FIXME - put Mutex around this shared data. */ +static int sNumDevices = 0; +static int sDeviceIndex = 0; +static internalPortAudioDevice *sDevices = NULL; +static int sDefaultInputDeviceID = paNoDevice; +static int sDefaultOutputDeviceID = paNoDevice; +static int sEnumerationError; +static int sPaHostError = 0; +/************************************************* Prototypes **********/ +static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ); +static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID, + LPCTSTR lpszDesc, + LPCTSTR lpszDrvName, + LPVOID lpContext ); +static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID, + LPCTSTR lpszDesc, + LPCTSTR lpszDrvName, + LPVOID lpContext ); +static Pa_QueryDevices( void ); +static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, + DWORD dwUser, DWORD dw1, DWORD dw2); +/********************************* 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. */ + QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); +} +static void Pa_EndUsageCalculation( internalPortAudioStream *past ) +{ + LARGE_INTEGER CurrentCount = { 0, 0 }; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + /* + ** Measure CPU utilization during this callback. Note that this calculation + ** assumes that we had the processor the whole time. + */ +#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) + if( QueryPerformanceCounter( &CurrentCount ) ) + { + LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; + double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerUserBuffer; + past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + + (LOWPASS_COEFFICIENT_1 * newUsage); + } +} +/****************************************** END CPU UTILIZATION *******/ +static PaError Pa_QueryDevices( void ) +{ + int numBytes; + sDefaultInputDeviceID = paNoDevice; + sDefaultOutputDeviceID = paNoDevice; + /* Enumerate once just to count devices. */ + sNumDevices = 0; // for default device + DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, NULL ); +#if SUPPORT_AUDIO_CAPTURE + DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, NULL ); +#endif /* SUPPORT_AUDIO_CAPTURE */ + /* Allocate structures to hold device info. */ + numBytes = sNumDevices * sizeof(internalPortAudioDevice); + sDevices = (internalPortAudioDevice *)PaHost_AllocateFastMemory( numBytes ); /* MEM */ + if( sDevices == NULL ) return paInsufficientMemory; + /* Enumerate again to fill in structures. */ + sDeviceIndex = 0; + sEnumerationError = 0; + DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_EnumProc, (void *)0 ); +#if SUPPORT_AUDIO_CAPTURE + if( sEnumerationError != paNoError ) return sEnumerationError; + sEnumerationError = 0; + DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_EnumProc, (void *)1 ); +#endif /* SUPPORT_AUDIO_CAPTURE */ + return sEnumerationError; +} +/************************************************************************************/ +long Pa_GetHostError() +{ + return sPaHostError; +} +/************************************************************************************ +** Just count devices so we know how much memory to allocate. +*/ +static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID, + LPCTSTR lpszDesc, + LPCTSTR lpszDrvName, + LPVOID lpContext ) +{ + sNumDevices++; + return TRUE; +} +/************************************************************************************ +** Extract capabilities info from each device. +*/ +static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID, + LPCTSTR lpszDesc, + LPCTSTR lpszDrvName, + LPVOID lpContext ) +{ + HRESULT hr; + LPDIRECTSOUND lpDirectSound; +#if SUPPORT_AUDIO_CAPTURE + LPDIRECTSOUNDCAPTURE lpDirectSoundCapture; +#endif /* SUPPORT_AUDIO_CAPTURE */ + int isInput = (int) lpContext; /* Passed from Pa_CountDevices() */ + internalPortAudioDevice *pad; + + if( sDeviceIndex >= sNumDevices ) + { + sEnumerationError = paInternalError; + return FALSE; + } + pad = &sDevices[sDeviceIndex]; + /* Copy GUID to static array. Set pointer. */ + if( lpGUID == NULL ) + { + pad->pad_lpGUID = NULL; + } + else + { + memcpy( &pad->pad_GUID, lpGUID, sizeof(GUID) ); + pad->pad_lpGUID = &pad->pad_GUID; + } + pad->pad_Info.sampleRates = pad->pad_SampleRates; /* Point to array. */ + /* Allocate room for descriptive name. */ + if( lpszDesc != NULL ) + { + int len = strlen(lpszDesc); + pad->pad_Info.name = (char *)malloc( len+1 ); + if( pad->pad_Info.name == NULL ) + { + sEnumerationError = paInsufficientMemory; + return FALSE; + } + memcpy( (void *) pad->pad_Info.name, lpszDesc, len+1 ); + } +#if SUPPORT_AUDIO_CAPTURE + if( isInput ) + { + /********** Input ******************************/ + DSCCAPS caps; + if( lpGUID == NULL ) sDefaultInputDeviceID = sDeviceIndex; + hr = DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL ); + if( hr != DS_OK ) + { + pad->pad_Info.maxInputChannels = 0; + DBUG(("Cannot create Capture for %s. Result = 0x%x\n", lpszDesc, hr )); + } + else + { + /* Query device characteristics. */ + caps.dwSize = sizeof(caps); + IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps ); + /* printf("caps.dwFormats = 0x%x\n", caps.dwFormats ); */ + pad->pad_Info.maxInputChannels = caps.dwChannels; + /* Determine sample rates from flags. */ + if( caps.dwChannels == 2 ) + { + int index = 0; + if( caps.dwFormats & WAVE_FORMAT_1S16) pad->pad_SampleRates[index++] = 11025.0; + if( caps.dwFormats & WAVE_FORMAT_2S16) pad->pad_SampleRates[index++] = 22050.0; + if( caps.dwFormats & WAVE_FORMAT_4S16) pad->pad_SampleRates[index++] = 44100.0; + pad->pad_Info.numSampleRates = index; + } + else if( caps.dwChannels == 1 ) + { + int index = 0; + if( caps.dwFormats & WAVE_FORMAT_1M16) pad->pad_SampleRates[index++] = 11025.0; + if( caps.dwFormats & WAVE_FORMAT_2M16) pad->pad_SampleRates[index++] = 22050.0; + if( caps.dwFormats & WAVE_FORMAT_4M16) pad->pad_SampleRates[index++] = 44100.0; + pad->pad_Info.numSampleRates = index; + } + else pad->pad_Info.numSampleRates = 0; + IDirectSoundCapture_Release( lpDirectSoundCapture ); + } + } + else +#endif /* SUPPORT_AUDIO_CAPTURE */ + + { + /********** Output ******************************/ + DSCAPS caps; + if( lpGUID == NULL ) sDefaultOutputDeviceID = sDeviceIndex; + /* Create interfaces for each object. */ + hr = DirectSoundCreate( lpGUID, &lpDirectSound, NULL ); + if( hr != DS_OK ) + { + pad->pad_Info.maxOutputChannels = 0; + DBUG(("Cannot create dsound for %s. Result = 0x%x\n", lpszDesc, hr )); + } + else + { + /* Query device characteristics. */ + caps.dwSize = sizeof(caps); + IDirectSound_GetCaps( lpDirectSound, &caps ); + pad->pad_Info.maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1; + /* Get sample rates. */ + pad->pad_SampleRates[0] = (double) caps.dwMinSecondarySampleRate; + pad->pad_SampleRates[1] = (double) caps.dwMaxSecondarySampleRate; + if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) pad->pad_Info.numSampleRates = -1; + else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate ) + { + if( caps.dwMinSecondarySampleRate == 0 ) + { + /* + ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !! + ** But it supports continuous sampling. + ** So fake range of rates, and hope it really supports it. + */ + pad->pad_SampleRates[0] = 11025.0f; + pad->pad_SampleRates[1] = 48000.0f; + pad->pad_Info.numSampleRates = -1; /* continuous range */ + + DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex )); + } + else + { + pad->pad_Info.numSampleRates = 1; + } + } + else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) ) + { + /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000. + ** But we know that they really support a range of rates! + ** So when we see a ridiculous set of rates, assume it is a range. + */ + pad->pad_Info.numSampleRates = -1; + DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex )); + } + else pad->pad_Info.numSampleRates = 2; + IDirectSound_Release( lpDirectSound ); + } + } + pad->pad_Info.nativeSampleFormats = paInt16; + sDeviceIndex++; + return( TRUE ); +} +/*************************************************************************/ +int Pa_CountDevices() +{ + if( sNumDevices <= 0 ) Pa_Initialize(); + return sNumDevices; +} +static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ) +{ + if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; + return &sDevices[id]; +} +/*************************************************************************/ +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( sNumDevices == 0 ) + { + return Pa_QueryDevices(); + } + return 0; +} +/************************************************************************* +** Returns recommended device ID. +** On the PC, the recommended device can be specified by the user 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 ID by using +** the supplied application "pa_devs". +*/ +#define PA_ENV_BUF_SIZE (32) +#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE") +#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE") +static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) +{ + DWORD hresult; + char envbuf[PA_ENV_BUF_SIZE]; + PaDeviceID recommendedID = paNoDevice; + /* Let user determine default device by setting environment variable. */ + hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); + if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) + { + recommendedID = atoi( envbuf ); + } + return recommendedID; +} +PaDeviceID Pa_GetDefaultInputDeviceID( void ) +{ + PaError result; + result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); + if( result < 0 ) + { + result = Pa_MaybeQueryDevices(); + if( result < 0 ) return result; + result = sDefaultInputDeviceID; + } + return result; +} +PaDeviceID Pa_GetDefaultOutputDeviceID( void ) +{ + PaError result; + result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); + if( result < 0 ) + { + result = Pa_MaybeQueryDevices(); + if( result < 0 ) return result; + result = sDefaultOutputDeviceID; + } + return result; +} +/********************************************************************** +** Make sure that we have queried the device capabilities. +*/ +PaError PaHost_Init( void ) +{ +#if PA_SIMULATE_UNDERFLOW + PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); +#endif + return Pa_MaybeQueryDevices(); +} +static PaError Pa_TimeSlice( internalPortAudioStream *past ) +{ + PaError result = 0; + long bytesEmpty = 0; + long bytesFilled = 0; + long bytesToXfer = 0; + long numChunks; + HRESULT hresult; + PaHostSoundControl *pahsc; + short *nativeBufPtr; + past->past_NumCallbacks += 1; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paInternalError; + /* How much input data is available? */ +#if SUPPORT_AUDIO_CAPTURE + if( past->past_NumInputChannels > 0 ) + { + DSW_QueryInputFilled( &pahsc->pahsc_DSoundWrapper, &bytesFilled ); + bytesToXfer = bytesFilled; + } +#endif /* SUPPORT_AUDIO_CAPTURE */ + /* How much output room is available? */ + if( past->past_NumOutputChannels > 0 ) + { + DSW_QueryOutputSpace( &pahsc->pahsc_DSoundWrapper, &bytesEmpty ); + bytesToXfer = bytesEmpty; + } + AddTraceMessage( "bytesEmpty ", bytesEmpty ); + /* Choose smallest value if both are active. */ + if( (past->past_NumInputChannels > 0) && (past->past_NumOutputChannels > 0) ) + { + bytesToXfer = ( bytesFilled < bytesEmpty ) ? bytesFilled : bytesEmpty; + } + /* printf("bytesFilled = %d, bytesEmpty = %d, bytesToXfer = %d\n", + bytesFilled, bytesEmpty, bytesToXfer); + */ + /* Quantize to multiples of a buffer. */ + numChunks = bytesToXfer / pahsc->pahsc_BytesPerBuffer; + if( numChunks > (long)(past->past_NumUserBuffers/2) ) + { + numChunks = (long)past->past_NumUserBuffers/2; + } + else if( numChunks < 0 ) + { + numChunks = 0; + } + AddTraceMessage( "numChunks ", numChunks ); + nativeBufPtr = pahsc->pahsc_NativeBuffer; + if( numChunks > 0 ) + { + while( numChunks-- > 0 ) + { + /* Measure usage based on time to process one user buffer. */ + Pa_StartUsageCalculation( past ); +#if SUPPORT_AUDIO_CAPTURE + /* Get native data from DirectSound. */ + if( past->past_NumInputChannels > 0 ) + { + hresult = DSW_ReadBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer ); + if( hresult < 0 ) + { + ERR_RPT(("DirectSound ReadBlock failed, hresult = 0x%x\n",hresult)); + sPaHostError = hresult; + break; + } + } +#endif /* SUPPORT_AUDIO_CAPTURE */ + /* Convert 16 bit native data to user data and call user routine. */ + result = Pa_CallConvertInt16( past, nativeBufPtr, nativeBufPtr ); + if( result != 0) break; + /* Pass native data to DirectSound. */ + if( past->past_NumOutputChannels > 0 ) + { + /* static short DEBUGHACK = 0; + DEBUGHACK += 0x0049; + nativeBufPtr[0] = DEBUGHACK; /* Make buzz to see if DirectSound still running. */ + hresult = DSW_WriteBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer ); + if( hresult < 0 ) + { + ERR_RPT(("DirectSound WriteBlock failed, result = 0x%x\n",hresult)); + sPaHostError = hresult; + break; + } + } + Pa_EndUsageCalculation( past ); + } + } + return result; +} +/*******************************************************************/ +static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +{ + internalPortAudioStream *past; + PaHostSoundControl *pahsc; +#if PA_SIMULATE_UNDERFLOW + gUnderCallbackCounter++; + if( (gUnderCallbackCounter >= UNDER_START_GAP) && + (gUnderCallbackCounter <= UNDER_STOP_GAP) ) + { + if( gUnderCallbackCounter == UNDER_START_GAP) + { + AddTraceMessage("Begin stall: gUnderCallbackCounter =======", gUnderCallbackCounter ); + } + if( gUnderCallbackCounter == UNDER_STOP_GAP) + { + AddTraceMessage("End stall: gUnderCallbackCounter =======", gUnderCallbackCounter ); + } + return; + } +#endif + past = (internalPortAudioStream *) dwUser; + if( past == NULL ) return; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + if( !pahsc->pahsc_IfInsideCallback && past->past_IsActive ) + { + if( past->past_StopNow ) + { + past->past_IsActive = 0; + } + else if( past->past_StopSoon ) + { + DSoundWrapper *dsw = &pahsc->pahsc_DSoundWrapper; + if( past->past_NumOutputChannels > 0 ) + { + DSW_ZeroEmptySpace( dsw ); + AddTraceMessage("Pa_TimerCallback: waiting - written ", (int) dsw->dsw_FramesWritten ); + AddTraceMessage("Pa_TimerCallback: waiting - played ", (int) dsw->dsw_FramesPlayed ); + /* clear past_IsActive when all sound played */ + if( dsw->dsw_FramesPlayed >= past->past_FrameCount ) + { + past->past_IsActive = 0; + } + } + else + { + past->past_IsActive = 0; + } + } + else + { + pahsc->pahsc_IfInsideCallback = 1; + if( Pa_TimeSlice( past ) != 0) /* Call time slice independant of timing method. */ + { + past->past_StopSoon = 1; + } + pahsc->pahsc_IfInsideCallback = 0; + } + } +} +/*******************************************************************/ +PaError PaHost_OpenStream( internalPortAudioStream *past ) +{ + HRESULT hr; + PaError result = paNoError; + PaHostSoundControl *pahsc; + int numBytes, maxChannels; + unsigned int minNumBuffers; + internalPortAudioDevice *pad; + DSoundWrapper *dsw; + /* Allocate and initialize host data. */ + pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */ + if( pahsc == NULL ) + { + result = paInsufficientMemory; + goto error; + } + memset( pahsc, 0, sizeof(PaHostSoundControl) ); + past->past_DeviceData = (void *) pahsc; + pahsc->pahsc_TimerID = 0; + dsw = &pahsc->pahsc_DSoundWrapper; + DSW_Init( dsw ); + /* Allocate native buffer. */ + maxChannels = ( past->past_NumOutputChannels > past->past_NumInputChannels ) ? + past->past_NumOutputChannels : past->past_NumInputChannels; + pahsc->pahsc_BytesPerBuffer = past->past_FramesPerUserBuffer * maxChannels * sizeof(short); + if( maxChannels > 0 ) + { + pahsc->pahsc_NativeBuffer = (short *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerBuffer); /* MEM */ + if( pahsc->pahsc_NativeBuffer == NULL ) + { + result = paInsufficientMemory; + goto error; + } + } + else + { + result = paInvalidChannelCount; + 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; + numBytes = pahsc->pahsc_BytesPerBuffer * past->past_NumUserBuffers; + if( numBytes < DSBSIZE_MIN ) + { + result = paBufferTooSmall; + goto error; + } + if( numBytes > DSBSIZE_MAX ) + { + result = paBufferTooBig; + goto error; + } + pahsc->pahsc_FramesPerDSBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers; + { + int msecLatency = (int) ((pahsc->pahsc_FramesPerDSBuffer * 1000) / past->past_SampleRate); + PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", pahsc->pahsc_FramesPerDSBuffer, msecLatency )); + } + /* ------------------ OUTPUT */ + if( (past->past_OutputDeviceID >= 0) && (past->past_NumOutputChannels > 0) ) + { + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); + pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); + hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL ); + /* If this fails, then try each output device until we find one that works. */ + if( hr != DS_OK ) + { + int i; + ERR_RPT(("Creation of requested Audio Output device '%s' failed.\n", + ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) )); + for( i=0; ipad_Info.maxOutputChannels >= past->past_NumOutputChannels ) + { + DBUG(("Try device '%s' instead.\n", pad->pad_Info.name )); + hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL ); + if( hr == DS_OK ) + { + ERR_RPT(("Using device '%s' instead.\n", pad->pad_Info.name )); + break; + } + } + } + } + if( hr != DS_OK ) + { + ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n")); + result = paHostError; + sPaHostError = hr; + goto error; + } + hr = DSW_InitOutputBuffer( dsw, + (unsigned long) (past->past_SampleRate + 0.5), + past->past_NumOutputChannels, numBytes ); + DBUG(("DSW_InitOutputBuffer() returns %x\n", hr)); + if( hr != DS_OK ) + { + result = paHostError; + sPaHostError = hr; + goto error; + } + past->past_FrameCount = pahsc->pahsc_DSoundWrapper.dsw_FramesWritten; + } +#if SUPPORT_AUDIO_CAPTURE + /* ------------------ INPUT */ + if( (past->past_InputDeviceID >= 0) && (past->past_NumInputChannels > 0) ) + { + pad = Pa_GetInternalDevice( past->past_InputDeviceID ); + hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); + /* If this fails, then try each input device until we find one that works. */ + if( hr != DS_OK ) + { + int i; + ERR_RPT(("Creation of requested Audio Capture device '%s' failed.\n", + ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) )); + for( i=0; ipad_Info.maxInputChannels >= past->past_NumInputChannels ) + { + PRINT(("Try device '%s' instead.\n", pad->pad_Info.name )); + hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); + if( hr == DS_OK ) break; + } + } + } + if( hr != DS_OK ) + { + ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n")); + result = paHostError; + sPaHostError = hr; + goto error; + } + hr = DSW_InitInputBuffer( dsw, + (unsigned long) (past->past_SampleRate + 0.5), + past->past_NumInputChannels, numBytes ); + DBUG(("DSW_InitInputBuffer() returns %x\n", hr)); + if( hr != DS_OK ) + { + ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr)); + result = paHostError; + sPaHostError = hr; + goto error; + } + } +#endif /* SUPPORT_AUDIO_CAPTURE */ + /* Calculate scalar used in CPULoad calculation. */ + { + LARGE_INTEGER frequency; + if( QueryPerformanceFrequency( &frequency ) == 0 ) + { + pahsc->pahsc_InverseTicksPerUserBuffer = 0.0; + } + else + { + pahsc->pahsc_InverseTicksPerUserBuffer = past->past_SampleRate / + ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer ); + DBUG(("pahsc_InverseTicksPerUserBuffer = %g\n", pahsc->pahsc_InverseTicksPerUserBuffer )); + } + } + return result; +error: + PaHost_CloseStream( past ); + return result; +} +/*************************************************************************/ +PaError PaHost_StartOutput( internalPortAudioStream *past ) +{ + HRESULT hr; + PaHostSoundControl *pahsc; + PaError result = paNoError; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + /* Give user callback a chance to pre-fill buffer. */ + result = Pa_TimeSlice( past ); + if( result != paNoError ) return result; // FIXME - what if finished? + hr = DSW_StartOutput( &pahsc->pahsc_DSoundWrapper ); + DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr)); + if( hr != DS_OK ) + { + result = paHostError; + sPaHostError = hr; + goto error; + } +error: + return result; +} +/*************************************************************************/ +PaError PaHost_StartInput( internalPortAudioStream *past ) +{ + PaError result = paNoError; +#if SUPPORT_AUDIO_CAPTURE + HRESULT hr; + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + hr = DSW_StartInput( &pahsc->pahsc_DSoundWrapper ); + DBUG(("Pa_StartStream: DSW_StartInput returned = 0x%X.\n", hr)); + if( hr != DS_OK ) + { + result = paHostError; + sPaHostError = hr; + goto error; + } +error: +#endif /* SUPPORT_AUDIO_CAPTURE */ + return result; +} +/*************************************************************************/ +PaError PaHost_StartEngine( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc; + PaError result = paNoError; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + past->past_StopNow = 0; + past->past_StopSoon = 0; + past->past_IsActive = 1; + /* Create timer that will wake us up so we can fill the DSound buffer. */ + { + int msecPerBuffer; + int resolution; + int bufsPerInterrupt = past->past_NumUserBuffers/4; + if( bufsPerInterrupt < 1 ) bufsPerInterrupt = 1; + msecPerBuffer = 1000 * (bufsPerInterrupt * past->past_FramesPerUserBuffer) / (int) past->past_SampleRate; + if( msecPerBuffer < 10 ) msecPerBuffer = 10; + else if( msecPerBuffer > 100 ) msecPerBuffer = 100; + resolution = msecPerBuffer/4; + pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback, + (DWORD) past, TIME_PERIODIC ); + } + if( pahsc->pahsc_TimerID == 0 ) + { + past->past_IsActive = 0; + result = paHostError; + sPaHostError = 0; + goto error; + } +error: + return result; +} +/*************************************************************************/ +PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) +{ + int timeoutMsec; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + if( abort ) past->past_StopNow = 1; + past->past_StopSoon = 1; + /* Set timeout at 20% beyond maximum time we might wait. */ + timeoutMsec = (int) (1200.0 * pahsc->pahsc_FramesPerDSBuffer / past->past_SampleRate); + while( past->past_IsActive && (timeoutMsec > 0) ) + { + Sleep(10); + timeoutMsec -= 10; + } + if( pahsc->pahsc_TimerID != 0 ) + { + timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */ + pahsc->pahsc_TimerID = 0; + } + return paNoError; +} +/*************************************************************************/ +PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) +{ +#if SUPPORT_AUDIO_CAPTURE + HRESULT hr; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; + hr = DSW_StopInput( &pahsc->pahsc_DSoundWrapper ); + DBUG(("DSW_StopInput() result is %x\n", hr)); +#endif /* SUPPORT_AUDIO_CAPTURE */ + return paNoError; +} +/*************************************************************************/ +PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) +{ + HRESULT hr; + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; + hr = DSW_StopOutput( &pahsc->pahsc_DSoundWrapper ); + DBUG(("DSW_StopOutput() result is %x\n", hr)); + return paNoError; +} +/*******************************************************************/ +PaError PaHost_CloseStream( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + DSW_Term( &pahsc->pahsc_DSoundWrapper ); + if( pahsc->pahsc_NativeBuffer ) + { + PaHost_FreeFastMemory( pahsc->pahsc_NativeBuffer, pahsc->pahsc_BytesPerBuffer ); /* MEM */ + pahsc->pahsc_NativeBuffer = NULL; + } + PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */ + past->past_DeviceData = NULL; + return paNoError; +} +/************************************************************************* +** 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 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. +*/ +#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") +int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) +{ + char envbuf[PA_ENV_BUF_SIZE]; + DWORD hostVersion; + DWORD hresult; + int minLatencyMsec = 0; + double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; + int minBuffers; + /* Let user determine minimal latency by setting environment variable. */ + hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); + if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) + { + minLatencyMsec = atoi( envbuf ); + } + else + { + /* Set minimal latency based on whether NT or Win95. + * NT has higher latency. + */ + hostVersion = GetVersion(); + /* High bit clear if NT */ + minLatencyMsec = ( (hostVersion & 0x80000000) == 0 ) ? PA_WIN_NT_LATENCY : PA_WIN_9X_LATENCY ; +#if PA_USE_HIGH_LATENCY + PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); +#endif + + } + minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); + if( minBuffers < 2 ) minBuffers = 2; + return minBuffers; +} +/*************************************************************************/ +PaError PaHost_Term( void ) +{ + int i; + /* Free names allocated during enumeration. */ + for( i=0; ipast_DeviceData; + if( pahsc == NULL ) return paInternalError; + return (PaError) (past->past_IsActive); +} +/*************************************************************************/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + DSoundWrapper *dsw; + internalPortAudioStream *past = (internalPortAudioStream *) stream; + PaHostSoundControl *pahsc; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + dsw = &pahsc->pahsc_DSoundWrapper; + return dsw->dsw_FramesPlayed; +} diff --git a/pa_win_ds/portaudio.def b/pa_win_ds/portaudio.def new file mode 100644 index 0000000..8012b99 --- /dev/null +++ b/pa_win_ds/portaudio.def @@ -0,0 +1,28 @@ +LIBRARY PortAudio +DESCRIPTION 'PortAudio Portable interface to audio HW' + +EXPORTS + ; Explicit exports can go here + Pa_Initialize @1 + Pa_Terminate @2 + Pa_GetHostError @3 + Pa_GetErrorText @4 + Pa_CountDevices @5 + Pa_GetDefaultInputDeviceID @6 + Pa_GetDefaultOutputDeviceID @7 + Pa_GetDeviceInfo @8 + Pa_OpenStream @9 + Pa_OpenDefaultStream @10 + Pa_CloseStream @11 + Pa_StartStream @12 + Pa_StopStream @13 + Pa_StreamActive @14 + Pa_StreamTime @15 + Pa_GetCPULoad @16 + Pa_GetMinNumBuffers @17 + Pa_Sleep @18 + + ;123456789012345678901234567890123456 + ;000000000111111111122222222223333333 + + diff --git a/pa_win_wmme/Makefile.cygwin b/pa_win_wmme/Makefile.cygwin new file mode 100644 index 0000000..5cb4ace --- /dev/null +++ b/pa_win_wmme/Makefile.cygwin @@ -0,0 +1,34 @@ + +# Makefile for PortAudio on cygwin +# Contributed by Bill Eldridge on 6/13/2001 + +ARCH= pa_win_wmme + +TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) + +.c.o: + -gcc -c -I./pa_common $< -o $*.o + -gcc $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm + +all: sharedlib tests + +sharedlib: ./pa_common/pa_lib.c + gcc -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o + gcc -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o + dlltool --export-all --output-def pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o + gcc -shared -Wl,--enable-auto-image-base -o pa_win_wmme/portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/lib/w32api -lwinmm + cp pa_win_wmme/portaudio.dll /usr/local/bin + +tests: $(TESTS:.c=.o) + +sine: + gcc -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o + gcc pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm + +clean: + -rm ./pa_tests/*.exe + +nothing: + gcc pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm + + diff --git a/pa_win_wmme/pa_win_wmme.c b/pa_win_wmme/pa_win_wmme.c new file mode 100644 index 0000000..2b3dea2 --- /dev/null +++ b/pa_win_wmme/pa_win_wmme.c @@ -0,0 +1,1493 @@ +/* + * $Id$ + * pa_win_wmme.c + * Implementation of PortAudio for Windows MultiMedia Extensions (WMME) + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Authors: Ross Bencina and Phil Burk + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtainingF + * 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. + * + */ +/* + All memory allocations and frees are marked with MEM for quick review. +*/ + +/* Modification History: + PLB = Phil Burk + JM = Julien Maillard + PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer) + PLB20010413 - check for excessive numbers of channels + PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC + including condition including of memory.h, + and explicit typecasting on memory allocation + PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory + PLB20010816 - pass process instead of thread to SetPriorityClass() + PLB20010927 - use number of frames instead of real-time for CPULoad calculation. + JM20020118 - prevent hung thread when buffers underflow. +*/ + +#include +#include +#include +#include +#include +#include +/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ +#ifndef __MWERKS__ +#include +#include +#endif /* __MWERKS__ */ +#include "portaudio.h" +#include "pa_host.h" +#include "pa_trace.h" + +/************************************************* Constants ********/ +#define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ +#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ +/* Switches for debugging. */ +#define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ +/* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ +#define PA_TRACE_RUN (0) +#define PA_TRACE_START_STOP (1) +#if PA_USE_HIGH_LATENCY + #define PA_MIN_MSEC_PER_HOST_BUFFER (100) + #define PA_MAX_MSEC_PER_HOST_BUFFER (300) /* Do not exceed unless user buffer exceeds */ + #define PA_MIN_NUM_HOST_BUFFERS (4) + #define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ + #define PA_WIN_9X_LATENCY (400) +#else + #define PA_MIN_MSEC_PER_HOST_BUFFER (10) + #define PA_MAX_MSEC_PER_HOST_BUFFER (100) /* Do not exceed unless user buffer exceeds */ + #define PA_MIN_NUM_HOST_BUFFERS (3) + #define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ + #define PA_WIN_9X_LATENCY (200) +#endif +#define MIN_TIMEOUT_MSEC (1000) +/* +** Use higher latency for NT because it is even worse at real-time +** operation than Win9x. +*/ +#define PA_WIN_NT_LATENCY (PA_WIN_9X_LATENCY * 2) + +#if PA_SIMULATE_UNDERFLOW +static gUnderCallbackCounter = 0; +#define UNDER_SLEEP_AT (40) +#define UNDER_SLEEP_FOR (500) +#endif + +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) /* PRINT(x) */ +#define DBUGX(x) /* PRINT(x) */ +/************************************************* Definitions ********/ +/************************************************************** + * Structure for internal host specific stream data. + * This is allocated on a per stream basis. + */ +typedef struct PaHostSoundControl +{ + /* Input -------------- */ + HWAVEIN pahsc_HWaveIn; + WAVEHDR *pahsc_InputBuffers; + int pahsc_CurrentInputBuffer; + int pahsc_BytesPerHostInputBuffer; + int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */ + /* Output -------------- */ + HWAVEOUT pahsc_HWaveOut; + WAVEHDR *pahsc_OutputBuffers; + int pahsc_CurrentOutputBuffer; + int pahsc_BytesPerHostOutputBuffer; + int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */ + /* Run Time -------------- */ + PaTimestamp pahsc_FramesPlayed; + long pahsc_LastPosition; /* used to track frames played. */ + /* For measuring CPU utilization. */ + LARGE_INTEGER pahsc_EntryCount; + double pahsc_InverseTicksPerHostBuffer; + /* Init Time -------------- */ + int pahsc_NumHostBuffers; + int pahsc_FramesPerHostBuffer; + int pahsc_UserBuffersPerHostBuffer; + CRITICAL_SECTION pahsc_StreamLock; /* Mutext to prevent threads from colliding. */ + INT pahsc_StreamLockInited; +#if PA_USE_TIMER_CALLBACK + BOOL pahsc_IfInsideCallback; /* Test for reentrancy. */ + MMRESULT pahsc_TimerID; +#else + HANDLE pahsc_AbortEvent; + int pahsc_AbortEventInited; + HANDLE pahsc_BufferEvent; + int pahsc_BufferEventInited; + HANDLE pahsc_EngineThread; + DWORD pahsc_EngineThreadID; +#endif +} +PaHostSoundControl; +/************************************************* Shared Data ********/ +/* FIXME - put Mutex around this shared data. */ +static int sNumInputDevices = 0; +static int sNumOutputDevices = 0; +static int sNumDevices = 0; +static PaDeviceInfo **sDevicePtrs = NULL; +static int sDefaultInputDeviceID = paNoDevice; +static int sDefaultOutputDeviceID = paNoDevice; +static int sPaHostError = 0; +static const char sMapperSuffixInput[] = " - Input"; +static const char sMapperSuffixOutput[] = " - Output"; +/************************************************* Macros ********/ +/* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ +#define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) +/************************************************* Prototypes **********/ +static Pa_QueryDevices( void ); +static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, + DWORD dwUser, DWORD dw1, DWORD dw2); +PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); +static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc ); +static PaError PaHost_BackgroundManager( internalPortAudioStream *past ); + +/********************************* 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. */ + QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); +} +static void Pa_EndUsageCalculation( internalPortAudioStream *past ) +{ + LARGE_INTEGER CurrentCount = { 0, 0 }; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + /* + ** Measure CPU utilization during this callback. Note that this calculation + ** assumes that we had the processor the whole time. + */ +#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) + if( QueryPerformanceCounter( &CurrentCount ) ) + { + LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; + double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerHostBuffer; + past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + + (LOWPASS_COEFFICIENT_1 * newUsage); + } +} +/****************************************** END CPU UTILIZATION *******/ + +static PaError Pa_QueryDevices( void ) +{ + int numBytes; + /* Count the devices and add one extra for the WAVE_MAPPER */ + sNumInputDevices = waveInGetNumDevs() + 1; + sDefaultInputDeviceID = 0; + sNumOutputDevices = waveOutGetNumDevs() + 1; + sDefaultOutputDeviceID = sNumInputDevices; + sNumDevices = sNumInputDevices + sNumOutputDevices; + /* Allocate structures to hold device info. */ + /* PLB20010402 - was allocating too much memory. */ + /* numBytes = sNumDevices * sizeof(PaDeviceInfo); // PLB20010402 */ + numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */ + sDevicePtrs = (PaDeviceInfo **) GlobalAlloc( GPTR, numBytes ); /* MEM */ + if( sDevicePtrs == NULL ) return paInsufficientMemory; + return paNoError; +} +/************************************************************************************/ +long Pa_GetHostError() +{ + return sPaHostError; +} +/*************************************************************************/ +int Pa_CountDevices() +{ + if( sNumDevices <= 0 ) Pa_Initialize(); + return sNumDevices; +} +/************************************************************************* +** If a PaDeviceInfo structure has not already been created, +** then allocate one and fill it in for the selected device. +** +** We create one extra input and one extra output device for the WAVE_MAPPER. +** [Does anyone know how to query the default device and get its name?] +*/ +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) +{ +#define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */ +#define NUM_CUSTOMSAMPLINGRATES 5 /* must be the same number of elements as in the array below */ +#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES) + static DWORD customSamplingRates[] = { 32000, 48000, 64000, 88200, 96000 }; + PaDeviceInfo *deviceInfo; + double *sampleRates; /* non-const ptr */ + int i; + char *s; + + if( id < 0 || id >= sNumDevices ) + return NULL; + if( sDevicePtrs[ id ] != NULL ) + { + return sDevicePtrs[ id ]; + } + deviceInfo = (PaDeviceInfo *)GlobalAlloc( GPTR, sizeof(PaDeviceInfo) ); /* MEM */ + if( deviceInfo == NULL ) return NULL; + deviceInfo->structVersion = 1; + deviceInfo->maxInputChannels = 0; + deviceInfo->maxOutputChannels = 0; + deviceInfo->numSampleRates = 0; + sampleRates = (double*)GlobalAlloc( GPTR, MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */ + deviceInfo->sampleRates = sampleRates; + deviceInfo->nativeSampleFormats = paInt16; /* should query for higher bit depths below */ + if( id < sNumInputDevices ) + { + /* input device */ + int inputMmID = id - 1; /* WAVE_MAPPER is -1 so we start with WAVE_MAPPER */ + WAVEINCAPS wic; + if( waveInGetDevCaps( inputMmID, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR ) + goto error; + + /* Append I/O suffix to WAVE_MAPPER device. */ + if( inputMmID == WAVE_MAPPER ) + { + s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */ + strcpy( s, wic.szPname ); + strcat( s, sMapperSuffixInput ); + } + else + { + s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 ); /* MEM */ + strcpy( s, wic.szPname ); + } + deviceInfo->name = s; + deviceInfo->maxInputChannels = wic.wChannels; + /* Sometimes a device can return a rediculously large number of channels. + ** This happened with an SBLive card on a Windows ME box. + ** If that happens, then force it to 2 channels. PLB20010413 + */ + if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) ) + { + ERR_RPT(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels )); + deviceInfo->maxInputChannels = 2; + } + /* Add a sample rate to the list if we can do stereo 16 bit at that rate + * based on the format flags. */ + if( wic.dwFormats & WAVE_FORMAT_1M16 ||wic.dwFormats & WAVE_FORMAT_1S16 ) + sampleRates[ deviceInfo->numSampleRates++ ] = 11025.; + if( wic.dwFormats & WAVE_FORMAT_2M16 ||wic.dwFormats & WAVE_FORMAT_2S16 ) + sampleRates[ deviceInfo->numSampleRates++ ] = 22050.; + if( wic.dwFormats & WAVE_FORMAT_4M16 ||wic.dwFormats & WAVE_FORMAT_4S16 ) + sampleRates[ deviceInfo->numSampleRates++ ] = 44100.; + /* Add a sample rate to the list if we can do stereo 16 bit at that rate + * based on opening the device successfully. */ + for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ) + { + WAVEFORMATEX wfx; + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nSamplesPerSec = customSamplingRates[i]; + wfx.wBitsPerSample = 16; + wfx.cbSize = 0; /* ignored */ + wfx.nChannels = (WORD)deviceInfo->maxInputChannels; + wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); + wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); + if( waveInOpen( NULL, inputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) + { + sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i]; + } + } + + } + else if( id - sNumInputDevices < sNumOutputDevices ) + { + /* output device */ + int outputMmID = id - sNumInputDevices - 1; + WAVEOUTCAPS woc; + if( waveOutGetDevCaps( outputMmID, &woc, sizeof( WAVEOUTCAPS ) ) != MMSYSERR_NOERROR ) + goto error; + /* Append I/O suffix to WAVE_MAPPER device. */ + if( outputMmID == WAVE_MAPPER ) + { + s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */ + strcpy( s, woc.szPname ); + strcat( s, sMapperSuffixOutput ); + } + else + { + s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 ); /* MEM */ + strcpy( s, woc.szPname ); + } + deviceInfo->name = s; + deviceInfo->maxOutputChannels = woc.wChannels; + /* Sometimes a device can return a rediculously large number of channels. + ** This happened with an SBLive card on a Windows ME box. + ** If that happens, then force it to 2 channels. PLB20010413 + */ + if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) ) + { + ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels )); + deviceInfo->maxOutputChannels = 2; + } + /* Add a sample rate to the list if we can do stereo 16 bit at that rate + * based on the format flags. */ + if( woc.dwFormats & WAVE_FORMAT_1M16 ||woc.dwFormats & WAVE_FORMAT_1S16 ) + sampleRates[ deviceInfo->numSampleRates++ ] = 11025.; + if( woc.dwFormats & WAVE_FORMAT_2M16 ||woc.dwFormats & WAVE_FORMAT_2S16 ) + sampleRates[ deviceInfo->numSampleRates++ ] = 22050.; + if( woc.dwFormats & WAVE_FORMAT_4M16 ||woc.dwFormats & WAVE_FORMAT_4S16 ) + sampleRates[ deviceInfo->numSampleRates++ ] = 44100.; + /* Add a sample rate to the list if we can do stereo 16 bit at that rate + * based on opening the device successfully. */ + for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ) + { + WAVEFORMATEX wfx; + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nSamplesPerSec = customSamplingRates[i]; + wfx.wBitsPerSample = 16; + wfx.cbSize = 0; /* ignored */ + wfx.nChannels = (WORD)deviceInfo->maxOutputChannels; + wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); + wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); + if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) + { + sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i]; + } + } + } + sDevicePtrs[ id ] = deviceInfo; + return deviceInfo; +error: + GlobalFree( sampleRates ); /* MEM */ + GlobalFree( deviceInfo ); /* MEM */ + + return NULL; +} +/************************************************************************* +** Returns recommended device ID. +** On the PC, the recommended device can be specified by the user 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 ID by using +** the supplied application "pa_devs". +*/ +#define PA_ENV_BUF_SIZE (32) +#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE") +#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE") +static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) +{ + DWORD hresult; + char envbuf[PA_ENV_BUF_SIZE]; + PaDeviceID recommendedID = paNoDevice; + /* Let user determine default device by setting environment variable. */ + hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); + if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) + { + recommendedID = atoi( envbuf ); + } + return recommendedID; +} +static PaError Pa_MaybeQueryDevices( void ) +{ + if( sNumDevices == 0 ) + { + return Pa_QueryDevices(); + } + return 0; +} +/********************************************************************** +** Check for environment variable, else query devices and use result. +*/ +PaDeviceID Pa_GetDefaultInputDeviceID( void ) +{ + PaError result; + result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); + if( result < 0 ) + { + result = Pa_MaybeQueryDevices(); + if( result < 0 ) return result; + result = sDefaultInputDeviceID; + } + return result; +} +PaDeviceID Pa_GetDefaultOutputDeviceID( void ) +{ + PaError result; + result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); + if( result < 0 ) + { + result = Pa_MaybeQueryDevices(); + if( result < 0 ) return result; + result = sDefaultOutputDeviceID; + } + return result; +} +/********************************************************************** +** Initialize Host dependant part of API. +*/ +PaError PaHost_Init( void ) +{ +#if PA_SIMULATE_UNDERFLOW + PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); +#endif + return Pa_MaybeQueryDevices(); +} + +/********************************************************************** +** Check WAVE buffers to see if they are done. +** Fill any available output buffers and use any available +** input buffers by calling user callback. +** +** This routine will loop until: +** user callback returns !=0 OR +** all output buffers are filled OR +** past->past_StopSoon is set OR +** an error occurs when calling WMME. +** +** Returns >0 when user requests a stop, <0 on error. +** +*/ +static PaError Pa_TimeSlice( internalPortAudioStream *past ) +{ + PaError result = 0; + long bytesEmpty = 0; + long bytesFilled = 0; + long buffersEmpty = 0; + MMRESULT mresult; + char *inBufPtr; + char *outBufPtr; + int gotInput = 0; + int gotOutput = 0; + int i; + int buffersProcessed = 0; + int done = 0; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paInternalError; + + past->past_NumCallbacks += 1; +#if PA_TRACE_RUN + AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks ); +#endif + + /* JM20020118 - prevent hung thread when buffers underflow. */ + /* while( !done ) /* BAD */ + while( !done && !past->past_StopSoon ) /* GOOD */ + { +#if PA_SIMULATE_UNDERFLOW + if(gUnderCallbackCounter++ == UNDER_SLEEP_AT) + { + Sleep(UNDER_SLEEP_FOR); + } +#endif + + /* If we are using output, then we need an empty output buffer. */ + gotOutput = 0; + outBufPtr = NULL; + if( past->past_NumOutputChannels > 0 ) + { + if((pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ].dwFlags & WHDR_DONE) == 0) + { + break; /* If none empty then bail and try again later. */ + } + else + { + outBufPtr = pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ].lpData; + gotOutput = 1; + } + } + /* Use an input buffer if one is available. */ + gotInput = 0; + inBufPtr = NULL; + if( ( past->past_NumInputChannels > 0 ) && + (pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ].dwFlags & WHDR_DONE) ) + { + inBufPtr = pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ].lpData; + gotInput = 1; +#if PA_TRACE_RUN + AddTraceMessage("Pa_TimeSlice: got input buffer at ", (int)inBufPtr ); + AddTraceMessage("Pa_TimeSlice: got input buffer # ", pahsc->pahsc_CurrentInputBuffer ); +#endif + + } + /* If we can't do anything then bail out. */ + if( !gotInput && !gotOutput ) break; + buffersProcessed += 1; + /* Each Wave buffer contains multiple user buffers so do them all now. */ + /* Base Usage on time it took to process one host buffer. */ + Pa_StartUsageCalculation( past ); + for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) + { + if( done ) + { + if( gotOutput ) + { + /* Clear remainder of wave buffer if we are waiting for stop. */ + AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); + memset( outBufPtr, 0, pahsc->pahsc_BytesPerUserOutputBuffer ); + } + } + else + { + /* Convert 16 bit native data to user data and call user routine. */ + result = Pa_CallConvertInt16( past, (short *) inBufPtr, (short *) outBufPtr ); + if( result != 0) done = 1; + } + if( gotInput ) inBufPtr += pahsc->pahsc_BytesPerUserInputBuffer; + if( gotOutput) outBufPtr += pahsc->pahsc_BytesPerUserOutputBuffer; + } + Pa_EndUsageCalculation( past ); + /* Send WAVE buffer to Wave Device to be refilled. */ + if( gotInput ) + { + mresult = waveInAddBuffer( pahsc->pahsc_HWaveIn, + &pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ], + sizeof(WAVEHDR) ); + if( mresult != MMSYSERR_NOERROR ) + { + sPaHostError = mresult; + result = paHostError; + break; + } + pahsc->pahsc_CurrentInputBuffer = (pahsc->pahsc_CurrentInputBuffer+1 >= pahsc->pahsc_NumHostBuffers) ? + 0 : pahsc->pahsc_CurrentInputBuffer+1; + } + /* Write WAVE buffer to Wave Device. */ + if( gotOutput ) + { +#if PA_TRACE_START_STOP + AddTraceMessage( "Pa_TimeSlice: writing buffer ", pahsc->pahsc_CurrentOutputBuffer ); +#endif + mresult = waveOutWrite( pahsc->pahsc_HWaveOut, + &pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ], + sizeof(WAVEHDR) ); + if( mresult != MMSYSERR_NOERROR ) + { + sPaHostError = mresult; + result = paHostError; + break; + } + pahsc->pahsc_CurrentOutputBuffer = (pahsc->pahsc_CurrentOutputBuffer+1 >= pahsc->pahsc_NumHostBuffers) ? + 0 : pahsc->pahsc_CurrentOutputBuffer+1; + } + + } + +#if PA_TRACE_RUN + AddTraceMessage("Pa_TimeSlice: buffersProcessed ", buffersProcessed ); +#endif + return (result != 0) ? result : done; +} + +/*******************************************************************/ +static PaError PaHost_BackgroundManager( internalPortAudioStream *past ) +{ + PaError result = 0; + int i; + int numQueuedOutputBuffers = 0; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + + /* Has someone asked us to abort by calling Pa_AbortStream()? */ + if( past->past_StopNow ) + { + past->past_IsActive = 0; /* Will cause thread to return. */ + } + /* Has someone asked us to stop by calling Pa_StopStream() + * OR has a user callback returned '1' to indicate finished. + */ + else if( past->past_StopSoon ) + { + /* Poll buffer and when all have played then exit thread. */ + /* Count how many output buffers are queued. */ + numQueuedOutputBuffers = 0; + if( past->past_NumOutputChannels > 0 ) + { + for( i=0; ipahsc_NumHostBuffers; i++ ) + { + if( !( pahsc->pahsc_OutputBuffers[ i ].dwFlags & WHDR_DONE) ) + { +#if PA_TRACE_START_STOP + AddTraceMessage( "WinMMPa_OutputThreadProc: waiting for buffer ", i ); +#endif + numQueuedOutputBuffers++; + } + } + } +#if PA_TRACE_START_STOP + AddTraceMessage( "WinMMPa_OutputThreadProc: numQueuedOutputBuffers ", numQueuedOutputBuffers ); +#endif + if( numQueuedOutputBuffers == 0 ) + { + past->past_IsActive = 0; /* Will cause thread to return. */ + } + } + else + { + /* Process full input buffer and fill up empty output buffers. */ + if( (result = Pa_TimeSlice( past )) != 0) + { + /* User callback has asked us to stop. */ +#if PA_TRACE_START_STOP + AddTraceMessage( "WinMMPa_OutputThreadProc: TimeSlice() returned ", result ); +#endif + past->past_StopSoon = 1; /* Request that audio play out then stop. */ + result = paNoError; + } + } + + PaHost_UpdateStreamTime( pahsc ); + return result; +} + +#if PA_USE_TIMER_CALLBACK +/*******************************************************************/ +static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +{ + internalPortAudioStream *past; + PaHostSoundControl *pahsc; + PaError result; + past = (internalPortAudioStream *) dwUser; + if( past == NULL ) return; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + if( pahsc->pahsc_IfInsideCallback ) + { + if( pahsc->pahsc_TimerID != 0 ) + { + timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */ + pahsc->pahsc_TimerID = 0; + } + return; + } + pahsc->pahsc_IfInsideCallback = 1; + /* Manage flags and audio processing. */ + result = PaHost_BackgroundManager( past ); + if( result != paNoError ) + { + past->past_IsActive = 0; + } + pahsc->pahsc_IfInsideCallback = 0; +} +#else /* PA_USE_TIMER_CALLBACK */ +/*******************************************************************/ +static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) +{ + internalPortAudioStream *past; + PaHostSoundControl *pahsc; + void *inputBuffer=NULL; + HANDLE events[2]; + int numEvents = 0; + DWORD result = 0; + DWORD waitResult; + DWORD numTimeouts = 0; + DWORD timeOut; + past = (internalPortAudioStream *) pArg; + pahsc = (PaHostSoundControl *) past->past_DeviceData; +#if PA_TRACE_START_STOP + AddTraceMessage( "WinMMPa_OutputThreadProc: timeoutPeriod", timeoutPeriod ); + AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", past->past_NumUserBuffers ); +#endif + /* Calculate timeOut as half the time it would take to play all buffers. */ + timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate); + /* Get event(s) ready for wait. */ + events[numEvents++] = pahsc->pahsc_BufferEvent; + if( pahsc->pahsc_AbortEventInited ) events[numEvents++] = pahsc->pahsc_AbortEvent; + /* Stay in this thread as long as we are "active". */ + while( past->past_IsActive ) + { + /*******************************************************************/ + /******** WAIT here for an event from WMME or PA *******************/ + /*******************************************************************/ + waitResult = WaitForMultipleObjects( numEvents, events, FALSE, timeOut ); + /* Error? */ + if( waitResult == WAIT_FAILED ) + { + sPaHostError = GetLastError(); + result = paHostError; + past->past_IsActive = 0; + } + /* Timeout? Don't stop. Just keep polling for DONE.*/ + else if( waitResult == WAIT_TIMEOUT ) + { +#if PA_TRACE_START_STOP + AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedOutputBuffers ); +#endif + numTimeouts += 1; + } + /* Manage flags and audio processing. */ + result = PaHost_BackgroundManager( past ); + if( result != paNoError ) + { + past->past_IsActive = 0; + } + } + return result; +} +#endif + +/*******************************************************************/ +PaError PaHost_OpenInputStream( internalPortAudioStream *past ) +{ + MMRESULT mr; + PaError result = paNoError; + PaHostSoundControl *pahsc; + int i; + int inputMmId; + int bytesPerInputFrame; + WAVEFORMATEX wfx; + const PaDeviceInfo *pad; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID)); + pad = Pa_GetDeviceInfo( past->past_InputDeviceID ); + if( pad == NULL ) return paInternalError; + switch( pad->nativeSampleFormats ) + { + case paInt32: + case paFloat32: + bytesPerInputFrame = sizeof(float) * past->past_NumInputChannels; + break; + default: + bytesPerInputFrame = sizeof(short) * past->past_NumInputChannels; + break; + } + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = (WORD) past->past_NumInputChannels; + wfx.nSamplesPerSec = (DWORD) past->past_SampleRate; + wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * past->past_SampleRate); + wfx.nBlockAlign = (WORD)bytesPerInputFrame; + wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/past->past_NumInputChannels) * 8); + wfx.cbSize = 0; + inputMmId = PaDeviceIdToWinId( past->past_InputDeviceID ); +#if PA_USE_TIMER_CALLBACK + mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx, + 0, 0, CALLBACK_NULL ); +#else + mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx, + (DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT ); +#endif + if( mr != MMSYSERR_NOERROR ) + { + ERR_RPT(("PortAudio: PaHost_OpenInputStream() failed!\n")); + result = paHostError; + sPaHostError = mr; + goto error; + } + /* Allocate an array to hold the buffer pointers. */ + pahsc->pahsc_InputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ + if( pahsc->pahsc_InputBuffers == NULL ) + { + result = paInsufficientMemory; + goto error; + } + /* Allocate each buffer. */ + for( i=0; ipahsc_NumHostBuffers; i++ ) + { + pahsc->pahsc_InputBuffers[i].lpData = (char *)GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostInputBuffer ); /* MEM */ + if( pahsc->pahsc_InputBuffers[i].lpData == NULL ) + { + result = paInsufficientMemory; + goto error; + } + pahsc->pahsc_InputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostInputBuffer; + pahsc->pahsc_InputBuffers[i].dwUser = i; + if( ( mr = waveInPrepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) + { + result = paHostError; + sPaHostError = mr; + goto error; + } + } + return result; +error: + return result; +} +/*******************************************************************/ +PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) +{ + MMRESULT mr; + PaError result = paNoError; + PaHostSoundControl *pahsc; + int i; + int outputMmID; + int bytesPerOutputFrame; + WAVEFORMATEX wfx; + const PaDeviceInfo *pad; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); + pad = Pa_GetDeviceInfo( past->past_OutputDeviceID ); + if( pad == NULL ) return paInternalError; + switch( pad->nativeSampleFormats ) + { + case paInt32: + case paFloat32: + bytesPerOutputFrame = sizeof(float) * past->past_NumOutputChannels; + break; + default: + bytesPerOutputFrame = sizeof(short) * past->past_NumOutputChannels; + break; + } + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = (WORD) past->past_NumOutputChannels; + wfx.nSamplesPerSec = (DWORD) past->past_SampleRate; + wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * past->past_SampleRate); + wfx.nBlockAlign = (WORD)bytesPerOutputFrame; + wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/past->past_NumOutputChannels) * 8); + wfx.cbSize = 0; + outputMmID = PaDeviceIdToWinId( past->past_OutputDeviceID ); +#if PA_USE_TIMER_CALLBACK + mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx, + 0, 0, CALLBACK_NULL ); +#else + + pahsc->pahsc_AbortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if( pahsc->pahsc_AbortEvent == NULL ) + { + result = paHostError; + sPaHostError = GetLastError(); + goto error; + } + pahsc->pahsc_AbortEventInited = 1; + mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx, + (DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT ); +#endif + if( mr != MMSYSERR_NOERROR ) + { + ERR_RPT(("PortAudio: PaHost_OpenOutputStream() failed!\n")); + result = paHostError; + sPaHostError = mr; + goto error; + } + /* Allocate an array to hold the buffer pointers. */ + pahsc->pahsc_OutputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ + if( pahsc->pahsc_OutputBuffers == NULL ) + { + result = paInsufficientMemory; + goto error; + } + /* Allocate each buffer. */ + for( i=0; ipahsc_NumHostBuffers; i++ ) + { + pahsc->pahsc_OutputBuffers[i].lpData = (char *) GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostOutputBuffer ); /* MEM */ + if( pahsc->pahsc_OutputBuffers[i].lpData == NULL ) + { + result = paInsufficientMemory; + goto error; + } + pahsc->pahsc_OutputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostOutputBuffer; + pahsc->pahsc_OutputBuffers[i].dwUser = i; + if( (mr = waveOutPrepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) + { + result = paHostError; + sPaHostError = mr; + goto error; + } + } + return result; +error: + return result; +} +/*******************************************************************/ +PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer; +} +/******************************************************************* +* Determine number of WAVE Buffers +* and how many User Buffers we can put into each WAVE buffer. +*/ +static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + unsigned int minNumBuffers; + int minFramesPerHostBuffer; + int maxFramesPerHostBuffer; + int minTotalFrames; + int userBuffersPerHostBuffer; + int framesPerHostBuffer; + int numHostBuffers; + /* Calculate minimum and maximum sizes based on timing and sample rate. */ + minFramesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); + minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); + maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); + maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer )); + /* Determine number of user buffers based on minimum latency. */ + minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); + past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; + DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); + minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; + /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ + if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) + { + userBuffersPerHostBuffer = + (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / + past->past_FramesPerUserBuffer; + } + else + { + userBuffersPerHostBuffer = 1; + } + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + /* Make sure we have anough WAVE buffers. */ + if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) + { + numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; + } + else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) && + ((int) past->past_FramesPerUserBuffer < (maxFramesPerHostBuffer/2) ) ) + { + /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ + while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) + { + userBuffersPerHostBuffer += 1; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + /* If we have gone too far, back up one. */ + if( (framesPerHostBuffer > maxFramesPerHostBuffer) || + (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) ) + { + userBuffersPerHostBuffer -= 1; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + break; + } + } + } + + pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; + pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; + pahsc->pahsc_NumHostBuffers = numHostBuffers; + DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); +} +/*******************************************************************/ +PaError PaHost_OpenStream( internalPortAudioStream *past ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc; + /* Allocate and initialize host data. */ + pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */ + if( pahsc == NULL ) + { + result = paInsufficientMemory; + goto error; + } + memset( pahsc, 0, sizeof(PaHostSoundControl) ); + past->past_DeviceData = (void *) pahsc; + /* Figure out how user buffers fit into WAVE buffers. */ + PaHost_CalcNumHostBuffers( past ); + { + int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate); + DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); + } + InitializeCriticalSection( &pahsc->pahsc_StreamLock ); + pahsc->pahsc_StreamLockInited = 1; + +#if (PA_USE_TIMER_CALLBACK == 0) + pahsc->pahsc_BufferEventInited = 0; + pahsc->pahsc_BufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( pahsc->pahsc_BufferEvent == NULL ) + { + result = paHostError; + sPaHostError = GetLastError(); + goto error; + } + pahsc->pahsc_BufferEventInited = 1; +#endif /* (PA_USE_TIMER_CALLBACK == 0) */ + /* ------------------ OUTPUT */ + pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels * sizeof(short); + pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer; + if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) + { + result = PaHost_OpenOutputStream( past ); + if( result < 0 ) goto error; + } + /* ------------------ INPUT */ + pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels * sizeof(short); + pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer; + if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) ) + { + result = PaHost_OpenInputStream( past ); + if( result < 0 ) goto error; + } + /* Calculate scalar used in CPULoad calculation. */ + { + LARGE_INTEGER frequency; + if( QueryPerformanceFrequency( &frequency ) == 0 ) + { + pahsc->pahsc_InverseTicksPerHostBuffer = 0.0; + } + else + { + pahsc->pahsc_InverseTicksPerHostBuffer = past->past_SampleRate / + ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer * pahsc->pahsc_UserBuffersPerHostBuffer ); + DBUG(("pahsc_InverseTicksPerHostBuffer = %g\n", pahsc->pahsc_InverseTicksPerHostBuffer )); + } + } + return result; +error: + PaHost_CloseStream( past ); + return result; +} +/*************************************************************************/ +PaError PaHost_StartOutput( internalPortAudioStream *past ) +{ + MMRESULT mr; + PaHostSoundControl *pahsc; + PaError result = paNoError; + int i; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( past->past_OutputDeviceID != paNoDevice ) + { + if( (mr = waveOutPause( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR ) + { + result = paHostError; + sPaHostError = mr; + goto error; + } + for( i=0; ipahsc_NumHostBuffers; i++ ) + { + ZeroMemory( pahsc->pahsc_OutputBuffers[i].lpData, pahsc->pahsc_OutputBuffers[i].dwBufferLength ); + mr = waveOutWrite( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) ); + if( mr != MMSYSERR_NOERROR ) + { + result = paHostError; + sPaHostError = mr; + goto error; + } + past->past_FrameCount += pahsc->pahsc_FramesPerHostBuffer; + } + pahsc->pahsc_CurrentOutputBuffer = 0; + if( (mr = waveOutRestart( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR ) + { + result = paHostError; + sPaHostError = mr; + goto error; + } + } + DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr)); +error: + return result; +} +/*************************************************************************/ +PaError PaHost_StartInput( internalPortAudioStream *past ) +{ + PaError result = paNoError; + MMRESULT mr; + int i; + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( past->past_InputDeviceID != paNoDevice ) + { + for( i=0; ipahsc_NumHostBuffers; i++ ) + { + mr = waveInAddBuffer( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) ); + if( mr != MMSYSERR_NOERROR ) + { + result = paHostError; + sPaHostError = mr; + goto error; + } + } + pahsc->pahsc_CurrentInputBuffer = 0; + mr = waveInStart( pahsc->pahsc_HWaveIn ); + DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", hr)); + if( mr != MMSYSERR_NOERROR ) + { + result = paHostError; + sPaHostError = mr; + goto error; + } + } +error: + return result; +} +/*************************************************************************/ +PaError PaHost_StartEngine( internalPortAudioStream *past ) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; +#if PA_USE_TIMER_CALLBACK + int resolution; + int bufsPerTimerCallback; + int msecPerBuffer; +#endif /* PA_USE_TIMER_CALLBACK */ + + past->past_StopSoon = 0; + past->past_StopNow = 0; + past->past_IsActive = 1; + pahsc->pahsc_FramesPlayed = 0.0; + pahsc->pahsc_LastPosition = 0; +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result ); +#endif +#if PA_USE_TIMER_CALLBACK + /* Create timer that will wake us up so we can fill the DSound buffer. */ + bufsPerTimerCallback = pahsc->pahsc_NumHostBuffers/4; + if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; + if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; + msecPerBuffer = (1000 * bufsPerTimerCallback * + pahsc->pahsc_UserBuffersPerHostBuffer * + past->past_FramesPerUserBuffer ) / (int) past->past_SampleRate; + if( msecPerBuffer < 10 ) msecPerBuffer = 10; + else if( msecPerBuffer > 100 ) msecPerBuffer = 100; + resolution = msecPerBuffer/4; + pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution, + (LPTIMECALLBACK) Pa_TimerCallback, + (DWORD) past, TIME_PERIODIC ); + if( pahsc->pahsc_TimerID == 0 ) + { + result = paHostError; + sPaHostError = GetLastError();; + goto error; + } +#else /* PA_USE_TIMER_CALLBACK */ + ResetEvent( pahsc->pahsc_AbortEvent ); + /* Create thread that waits for audio buffers to be ready for processing. */ + pahsc->pahsc_EngineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, past, 0, &pahsc->pahsc_EngineThreadID ); + if( pahsc->pahsc_EngineThread == NULL ) + { + result = paHostError; + sPaHostError = GetLastError();; + goto error; + } +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_StartEngine: thread ", (int) pahsc->pahsc_EngineThread ); +#endif + /* I used to pass the thread which was failing. I now pass GetCurrentProcess(). + ** This fix could improve latency for some applications. It could also result in CPU + ** starvation if the callback did too much processing. + ** I also added result checks, so we might see more failures at initialization. + ** Thanks to Alberto di Bene for spotting this. + */ + if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */ + { + result = paHostError; + sPaHostError = GetLastError();; + goto error; + } + if( !SetThreadPriority( pahsc->pahsc_EngineThread, THREAD_PRIORITY_HIGHEST ) ) + { + result = paHostError; + sPaHostError = GetLastError();; + goto error; + } +#endif +error: + return result; +} + +/*************************************************************************/ +PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) +{ + int timeOut; + 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; + + /* Calculate timeOut longer than longest time it could take to play all buffers. */ + timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate); + if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; + +#if PA_USE_TIMER_CALLBACK + if( (past->past_OutputDeviceID != paNoDevice) && + past->past_IsActive && + (pahsc->pahsc_TimerID != 0) ) + { + /* Wait for IsActive to drop. */ + while( (past->past_IsActive) && (timeOut > 0) ) + { + Sleep(10); + timeOut -= 10; + } + timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */ + pahsc->pahsc_TimerID = 0; + } +#else /* PA_USE_TIMER_CALLBACK */ +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_StopEngine: thread ", (int) pahsc->pahsc_EngineThread ); +#endif + if( (past->past_OutputDeviceID != paNoDevice) && + (past->past_IsActive) && + (pahsc->pahsc_EngineThread != NULL) ) + { + DWORD got; + /* Tell background thread to stop generating more data and to let current data play out. */ + DBUG(("PaHost_StopEngine: waiting for background thread.\n")); + got = WaitForSingleObject( pahsc->pahsc_EngineThread, timeOut ); + if( got == WAIT_TIMEOUT ) + { + ERR_RPT(("PaHost_StopEngine: timed out while waiting for background thread to finish.\n")); + return paTimedOut; + } + CloseHandle( pahsc->pahsc_EngineThread ); + pahsc->pahsc_EngineThread = NULL; + } +#endif /* PA_USE_TIMER_CALLBACK */ + + past->past_IsActive = 0; + return paNoError; +} +/*************************************************************************/ +PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) +{ + MMRESULT mr; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; + if( pahsc->pahsc_HWaveIn != NULL ) + { + mr = waveInReset( pahsc->pahsc_HWaveIn ); + if( mr != MMSYSERR_NOERROR ) + { + sPaHostError = mr; + return paHostError; + } + } + return paNoError; +} +/*************************************************************************/ +PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) +{ + MMRESULT mr; + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); +#endif + if( pahsc->pahsc_HWaveOut != NULL ) + { + mr = waveOutReset( pahsc->pahsc_HWaveOut ); + if( mr != MMSYSERR_NOERROR ) + { + sPaHostError = mr; + return paHostError; + } + } + return paNoError; +} +/*******************************************************************/ +PaError PaHost_CloseStream( internalPortAudioStream *past ) +{ + int i; + PaHostSoundControl *pahsc; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); +#endif + /* Free data and device for output. */ + if( pahsc->pahsc_HWaveOut ) + { + if( pahsc->pahsc_OutputBuffers ) + { + for( i=0; ipahsc_NumHostBuffers; i++ ) + { + waveOutUnprepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) ); + GlobalFree( pahsc->pahsc_OutputBuffers[i].lpData ); /* MEM */ + } + GlobalFree( pahsc->pahsc_OutputBuffers ); /* MEM */ + } + waveOutClose( pahsc->pahsc_HWaveOut ); + } + /* Free data and device for input. */ + if( pahsc->pahsc_HWaveIn ) + { + if( pahsc->pahsc_InputBuffers ) + { + for( i=0; ipahsc_NumHostBuffers; i++ ) + { + waveInUnprepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) ); + GlobalFree( pahsc->pahsc_InputBuffers[i].lpData ); /* MEM */ + } + GlobalFree( pahsc->pahsc_InputBuffers ); /* MEM */ + } + waveInClose( pahsc->pahsc_HWaveIn ); + } +#if (PA_USE_TIMER_CALLBACK == 0) + if( pahsc->pahsc_AbortEventInited ) CloseHandle( pahsc->pahsc_AbortEvent ); + if( pahsc->pahsc_BufferEventInited ) CloseHandle( pahsc->pahsc_BufferEvent ); +#endif + if( pahsc->pahsc_StreamLockInited ) + DeleteCriticalSection( &pahsc->pahsc_StreamLock ); + PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */ + past->past_DeviceData = NULL; + return paNoError; +} +/************************************************************************* +** 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 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. +*/ +#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") +int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) +{ + char envbuf[PA_ENV_BUF_SIZE]; + DWORD hostVersion; + DWORD hresult; + int minLatencyMsec = 0; + double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; + int minBuffers; + /* Let user determine minimal latency by setting environment variable. */ + hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); + if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) + { + minLatencyMsec = atoi( envbuf ); + } + else + { + /* Set minimal latency based on whether NT or Win95. + * NT has higher latency. + */ + hostVersion = GetVersion(); + /* High bit clear if NT */ + minLatencyMsec = ( (hostVersion & 0x80000000) == 0 ) ? PA_WIN_NT_LATENCY : PA_WIN_9X_LATENCY ; +#if PA_USE_HIGH_LATENCY + PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); +#endif + + } + DBUG(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); + minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); + if( minBuffers < 2 ) minBuffers = 2; + return minBuffers; +} +/************************************************************************* +** Cleanup device info. +*/ +PaError PaHost_Term( void ) +{ + int i; + if( sNumDevices > 0 ) + { + if( sDevicePtrs != NULL ) + { + for( i=0; iname ); /* MEM */ + GlobalFree( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */ + GlobalFree( sDevicePtrs[i] ); /* MEM */ + } + } + GlobalFree( sDevicePtrs ); /* MEM */ + sDevicePtrs = NULL; + } + sNumDevices = 0; + } + return paNoError; +} +/*************************************************************************/ +void Pa_Sleep( long msec ) +{ + Sleep( msec ); +} +/************************************************************************* + * 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(). + * Memory will be set to zero. + */ +void *PaHost_AllocateFastMemory( long numBytes ) +{ + void *addr = GlobalAlloc( GPTR, numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */ + 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 ) +{ + if( addr != NULL ) GlobalFree( addr ); /* MEM */ +} +/***********************************************************************/ +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; +} +/************************************************************************* + * This must be called periodically because mmtime.u.sample + * is a DWORD and can wrap and lose sync after a few hours. + */ +static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc ) +{ + MMRESULT mr; + MMTIME mmtime; + mmtime.wType = TIME_SAMPLES; + if( pahsc->pahsc_HWaveOut != NULL ) + { + mr = waveOutGetPosition( pahsc->pahsc_HWaveOut, &mmtime, sizeof(mmtime) ); + } + else + { + mr = waveInGetPosition( pahsc->pahsc_HWaveIn, &mmtime, sizeof(mmtime) ); + } + if( mr != MMSYSERR_NOERROR ) + { + sPaHostError = mr; + return paHostError; + } + /* This data has two variables and is shared by foreground and background. */ + /* So we need to make it thread safe. */ + EnterCriticalSection( &pahsc->pahsc_StreamLock ); + pahsc->pahsc_FramesPlayed += ((long)mmtime.u.sample) - pahsc->pahsc_LastPosition; + pahsc->pahsc_LastPosition = (long)mmtime.u.sample; + LeaveCriticalSection( &pahsc->pahsc_StreamLock ); + return paNoError; +} +/*************************************************************************/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + PaHostSoundControl *pahsc; + internalPortAudioStream *past = (internalPortAudioStream *) stream; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + PaHost_UpdateStreamTime( pahsc ); + return pahsc->pahsc_FramesPlayed; +} diff --git a/pablio/README.txt b/pablio/README.txt new file mode 100644 index 0000000..99c7d14 --- /dev/null +++ b/pablio/README.txt @@ -0,0 +1,39 @@ +README for PABLIO +Portable Audio Blocking I/O Library +Author: Phil Burk + +PABLIO is a simplified interface to PortAudio that provide +read/write style blocking I/O. + +Please see the .DOC file for documentation. + +/* + * More information on PortAudio at: http://www.portaudio.com + * 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. + * + */ + + diff --git a/pablio/pablio.c b/pablio/pablio.c new file mode 100644 index 0000000..452eccc --- /dev/null +++ b/pablio/pablio.c @@ -0,0 +1,307 @@ +/* + * $Id$ + * pablio.c + * Portable Audio Blocking Input/Output utility. + * + * Author: Phil Burk, http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include +#include "portaudio.h" +#include "ringbuffer.h" +#include "pablio.h" +#include + +/************************************************************************/ +/******** Constants *****************************************************/ +/************************************************************************/ + +#define FRAMES_PER_BUFFER (256) + +/************************************************************************/ +/******** Prototypes ****************************************************/ +/************************************************************************/ + +static int blockingIOCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); +static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame ); +static PaError PABLIO_TermFIFO( RingBuffer *rbuf ); + +/************************************************************************/ +/******** Functions *****************************************************/ +/************************************************************************/ + +/* Called from PortAudio. + * Read and write data only if there is room in FIFOs. + */ +static int blockingIOCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + PABLIO_Stream *data = (PABLIO_Stream*)userData; + long numBytes = data->bytesPerFrame * framesPerBuffer; + (void) outTime; + + /* This may get called with NULL inputBuffer during initial setup. */ + if( inputBuffer != NULL ) + { + RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes ); + } + if( outputBuffer != NULL ) + { + int i; + int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes ); + /* Zero out remainder of buffer if we run out of data. */ + for( i=numRead; ibuffer ) free( rbuf->buffer ); + rbuf->buffer = NULL; + return paNoError; +} + +/************************************************************ + * Write data to ring buffer. + * Will not return until all the data has been written. + */ +long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) +{ + long bytesWritten; + char *p = (char *) data; + long numBytes = aStream->bytesPerFrame * numFrames; + while( numBytes > 0) + { + bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes ); + numBytes -= bytesWritten; + p += bytesWritten; + if( numBytes > 0) Pa_Sleep(10); + } + return numFrames; +} + +/************************************************************ + * Read data from ring buffer. + * Will not return until all the data has been read. + */ +long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) +{ + long bytesRead; + char *p = (char *) data; + long numBytes = aStream->bytesPerFrame * numFrames; + while( numBytes > 0) + { + bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes ); + numBytes -= bytesRead; + p += bytesRead; + if( numBytes > 0) Pa_Sleep(10); + } + return numFrames; +} + +/************************************************************ + * Return the number of frames that could be written to the stream without + * having to wait. + */ +long GetAudioStreamWriteable( PABLIO_Stream *aStream ) +{ + int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); + return bytesEmpty / aStream->bytesPerFrame; +} + +/************************************************************ + * Return the number of frames that are available to be read from the + * stream without having to wait. + */ +long GetAudioStreamReadable( PABLIO_Stream *aStream ) +{ + int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO ); + return bytesFull / aStream->bytesPerFrame; +} + +/************************************************************/ +static unsigned long RoundUpToNextPowerOf2( unsigned long n ) +{ + long numBits = 0; + if( ((n-1) & n) == 0) return n; /* Already Power of two. */ + while( n > 0 ) + { + n= n>>1; + numBits++; + } + return (1<samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2; + aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame; + + /* Initialize PortAudio */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + /* Warning: numFrames must be larger than amount of data processed per interrupt + * inside PA to prevent glitches. Just to be safe, adjust size upwards. + */ + minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); + numFrames = minNumBuffers * FRAMES_PER_BUFFER; + numFrames = RoundUpToNextPowerOf2( numFrames ); + + /* Initialize Ring Buffers */ + doRead = ((flags & PABLIO_READ) != 0); + doWrite = ((flags & PABLIO_WRITE) != 0); + if(doRead) + { + err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame ); + if( err != paNoError ) goto error; + } + if(doWrite) + { + long numBytes; + err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame ); + if( err != paNoError ) goto error; + /* Make Write FIFO appear full initially. */ + numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); + RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes ); + } + + /* Open a PortAudio stream that we will use to communicate with the underlying + * audio drivers. */ + err = Pa_OpenStream( + &aStream->stream, + (doRead ? Pa_GetDefaultInputDeviceID() : paNoDevice), + (doRead ? aStream->samplesPerFrame : 0 ), + format, + NULL, + (doWrite ? Pa_GetDefaultOutputDeviceID() : paNoDevice), + (doWrite ? aStream->samplesPerFrame : 0 ), + format, + NULL, + sampleRate, + FRAMES_PER_BUFFER, + minNumBuffers, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + blockingIOCallback, + aStream ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( aStream->stream ); + if( err != paNoError ) goto error; + + *rwblPtr = aStream; + return paNoError; + +error: + CloseAudioStream( aStream ); + *rwblPtr = NULL; + return err; +} + +/************************************************************/ +PaError CloseAudioStream( PABLIO_Stream *aStream ) +{ + PaError err; + int bytesEmpty; + int byteSize = aStream->outFIFO.bufferSize; + + /* If we are writing data, make sure we play everything written. */ + if( byteSize > 0 ) + { + bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); + while( bytesEmpty < byteSize ) + { + Pa_Sleep( 10 ); + bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); + } + } + + err = Pa_StopStream( aStream->stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( aStream->stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + +error: + PABLIO_TermFIFO( &aStream->inFIFO ); + PABLIO_TermFIFO( &aStream->outFIFO ); + free( aStream ); + return err; +} diff --git a/pablio/pablio.def b/pablio/pablio.def new file mode 100644 index 0000000..a10f952 --- /dev/null +++ b/pablio/pablio.def @@ -0,0 +1,35 @@ +LIBRARY PABLIO +DESCRIPTION 'PABLIO Portable Audio Blocking I/O' + +EXPORTS + ; Explicit exports can go here + Pa_Initialize @1 + Pa_Terminate @2 + Pa_GetHostError @3 + Pa_GetErrorText @4 + Pa_CountDevices @5 + Pa_GetDefaultInputDeviceID @6 + Pa_GetDefaultOutputDeviceID @7 + Pa_GetDeviceInfo @8 + Pa_OpenStream @9 + Pa_OpenDefaultStream @10 + Pa_CloseStream @11 + Pa_StartStream @12 + Pa_StopStream @13 + Pa_StreamActive @14 + Pa_StreamTime @15 + Pa_GetCPULoad @16 + Pa_GetMinNumBuffers @17 + Pa_Sleep @18 + + OpenAudioStream @19 + CloseAudioStream @20 + WriteAudioStream @21 + ReadAudioStream @22 + + Pa_GetSampleSize @23 + + ;123456789012345678901234567890123456 + ;000000000111111111122222222223333333 + + diff --git a/pablio/pablio.h b/pablio/pablio.h new file mode 100644 index 0000000..c1ad84a --- /dev/null +++ b/pablio/pablio.h @@ -0,0 +1,109 @@ +#ifndef _PABLIO_H +#define _PABLIO_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * $Id$ + * PABLIO.h + * Portable Audio Blocking read/write utility. + * + * Author: Phil Burk, http://www.softsynth.com/portaudio/ + * + * Include file for PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include +#include "portaudio.h" +#include "ringbuffer.h" +#include + +typedef struct +{ + RingBuffer inFIFO; + RingBuffer outFIFO; + PortAudioStream *stream; + int bytesPerFrame; + int samplesPerFrame; +} +PABLIO_Stream; + +/* Values for flags for OpenAudioStream(). */ +#define PABLIO_READ (1<<0) +#define PABLIO_WRITE (1<<1) +#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE) +#define PABLIO_MONO (1<<2) +#define PABLIO_STEREO (1<<3) + +/************************************************************ + * Write data to ring buffer. + * Will not return until all the data has been written. + */ +long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); + +/************************************************************ + * Read data from ring buffer. + * Will not return until all the data has been read. + */ +long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); + +/************************************************************ + * Return the number of frames that could be written to the stream without + * having to wait. + */ +long GetAudioStreamWriteable( PABLIO_Stream *aStream ); + +/************************************************************ + * Return the number of frames that are available to be read from the + * stream without having to wait. + */ +long GetAudioStreamReadable( PABLIO_Stream *aStream ); + +/************************************************************ + * Opens a PortAudio stream with default characteristics. + * Allocates PABLIO_Stream structure. + * + * flags parameter can be an ORed combination of: + * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, + * and either PABLIO_MONO or PABLIO_STEREO + */ +PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate, + PaSampleFormat format, long flags ); + +PaError CloseAudioStream( PABLIO_Stream *aStream ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _PABLIO_H */ diff --git a/pablio/ringbuffer.c b/pablio/ringbuffer.c new file mode 100644 index 0000000..16031fe --- /dev/null +++ b/pablio/ringbuffer.c @@ -0,0 +1,199 @@ +/* + * $Id$ + * ringbuffer.c + * Ring Buffer utility.. + * + * Author: Phil Burk, http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include +#include "ringbuffer.h" +#include + +/*************************************************************************** + * Initialize FIFO. + * numBytes must be power of 2, returns -1 if not. + */ +long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr ) +{ + if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */ + rbuf->bufferSize = numBytes; + rbuf->buffer = (char *)dataPtr; + RingBuffer_Flush( rbuf ); + rbuf->bigMask = (numBytes*2)-1; + rbuf->smallMask = (numBytes)-1; + return 0; +} +/*************************************************************************** +** Return number of bytes available for reading. */ +long RingBuffer_GetReadAvailable( RingBuffer *rbuf ) +{ + return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); +} +/*************************************************************************** +** Return number of bytes available for writing. */ +long RingBuffer_GetWriteAvailable( RingBuffer *rbuf ) +{ + return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf)); +} + +/*************************************************************************** +** Clear buffer. Should only be called when buffer is NOT being read. */ +void RingBuffer_Flush( RingBuffer *rbuf ) +{ + rbuf->writeIndex = rbuf->readIndex = 0; +} + +/*************************************************************************** +** Get address of region(s) to which we can write data. +** If the region is contiguous, size2 will be zero. +** If non-contiguous, size2 will be the size of second region. +** Returns room available to be written or numBytes, whichever is smaller. +*/ +long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes, + void **dataPtr1, long *sizePtr1, + void **dataPtr2, long *sizePtr2 ) +{ + long index; + long available = RingBuffer_GetWriteAvailable( rbuf ); + if( numBytes > available ) numBytes = available; + /* Check to see if write is not contiguous. */ + index = rbuf->writeIndex & rbuf->smallMask; + if( (index + numBytes) > rbuf->bufferSize ) + { + /* Write data in two blocks that wrap the buffer. */ + long firstHalf = rbuf->bufferSize - index; + *dataPtr1 = &rbuf->buffer[index]; + *sizePtr1 = firstHalf; + *dataPtr2 = &rbuf->buffer[0]; + *sizePtr2 = numBytes - firstHalf; + } + else + { + *dataPtr1 = &rbuf->buffer[index]; + *sizePtr1 = numBytes; + *dataPtr2 = NULL; + *sizePtr2 = 0; + } + return numBytes; +} + + +/*************************************************************************** +*/ +long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes ) +{ + return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask; +} + +/*************************************************************************** +** Get address of region(s) from which we can read data. +** If the region is contiguous, size2 will be zero. +** If non-contiguous, size2 will be the size of second region. +** Returns room available to be written or numBytes, whichever is smaller. +*/ +long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes, + void **dataPtr1, long *sizePtr1, + void **dataPtr2, long *sizePtr2 ) +{ + long index; + long available = RingBuffer_GetReadAvailable( rbuf ); + if( numBytes > available ) numBytes = available; + /* Check to see if read is not contiguous. */ + index = rbuf->readIndex & rbuf->smallMask; + if( (index + numBytes) > rbuf->bufferSize ) + { + /* Write data in two blocks that wrap the buffer. */ + long firstHalf = rbuf->bufferSize - index; + *dataPtr1 = &rbuf->buffer[index]; + *sizePtr1 = firstHalf; + *dataPtr2 = &rbuf->buffer[0]; + *sizePtr2 = numBytes - firstHalf; + } + else + { + *dataPtr1 = &rbuf->buffer[index]; + *sizePtr1 = numBytes; + *dataPtr2 = NULL; + *sizePtr2 = 0; + } + return numBytes; +} +/*************************************************************************** +*/ +long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes ) +{ + return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask; +} + +/*************************************************************************** +** Return bytes written. */ +long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes ) +{ + long size1, size2, numWritten; + void *data1, *data2; + numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); + if( size2 > 0 ) + { + + memcpy( data1, data, size1 ); + data = ((char *)data) + size1; + memcpy( data2, data, size2 ); + } + else + { + memcpy( data1, data, size1 ); + } + RingBuffer_AdvanceWriteIndex( rbuf, numWritten ); + return numWritten; +} + +/*************************************************************************** +** Return bytes read. */ +long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes ) +{ + long size1, size2, numRead; + void *data1, *data2; + numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); + if( size2 > 0 ) + { + memcpy( data, data1, size1 ); + data = ((char *)data) + size1; + memcpy( data, data2, size2 ); + } + else + { + memcpy( data, data1, size1 ); + } + RingBuffer_AdvanceReadIndex( rbuf, numRead ); + return numRead; +} diff --git a/pablio/ringbuffer.h b/pablio/ringbuffer.h new file mode 100644 index 0000000..dd769be --- /dev/null +++ b/pablio/ringbuffer.h @@ -0,0 +1,101 @@ +#ifndef _RINGBUFFER_H +#define _RINGBUFFER_H +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * $Id$ + * ringbuffer.h + * Ring Buffer utility.. + * + * Author: Phil Burk, http://www.softsynth.com + * + * This program is distributed with the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include +#include "ringbuffer.h" +#include + +typedef struct +{ + long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */ + long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */ + long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */ + long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */ + long smallMask; /* Used for fitting indices to buffer. */ + char *buffer; +} +RingBuffer; +/* + * Initialize Ring Buffer. + * numBytes must be power of 2, returns -1 if not. + */ +long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr ); + +/* Clear buffer. Should only be called when buffer is NOT being read. */ +void RingBuffer_Flush( RingBuffer *rbuf ); + +/* Return number of bytes available for writing. */ +long RingBuffer_GetWriteAvailable( RingBuffer *rbuf ); +/* Return number of bytes available for read. */ +long RingBuffer_GetReadAvailable( RingBuffer *rbuf ); +/* Return bytes written. */ +long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes ); +/* Return bytes read. */ +long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes ); + +/* Get address of region(s) to which we can write data. +** If the region is contiguous, size2 will be zero. +** If non-contiguous, size2 will be the size of second region. +** Returns room available to be written or numBytes, whichever is smaller. +*/ +long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes, + void **dataPtr1, long *sizePtr1, + void **dataPtr2, long *sizePtr2 ); +long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes ); + +/* Get address of region(s) from which we can read data. +** If the region is contiguous, size2 will be zero. +** If non-contiguous, size2 will be the size of second region. +** Returns room available to be written or numBytes, whichever is smaller. +*/ +long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes, + void **dataPtr1, long *sizePtr1, + void **dataPtr2, long *sizePtr2 ); + +long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _RINGBUFFER_H */ diff --git a/pablio/test_rw.c b/pablio/test_rw.c new file mode 100644 index 0000000..245e19c --- /dev/null +++ b/pablio/test_rw.c @@ -0,0 +1,99 @@ +/* + * $Id$ + * test_rw.c + * Read input from one stream and write it to another. + * + * Author: Phil Burk, http://www.softsynth.com/portaudio/ + * + * This program uses PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * For more information see: 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. + * + */ + +#include +#include +#include "pablio.h" + +/* +** Note that many of the older ISA sound cards on PCs do NOT support +** full duplex audio (simultaneous record and playback). +** And some only support full duplex at lower sample rates. +*/ +#define SAMPLE_RATE (22050) +#define NUM_SECONDS (15) +#define SAMPLES_PER_FRAME (2) + +/* Select whether we will use floats or shorts. */ +#if 1 +#define SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#else +#define SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#endif + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i; + SAMPLE samples[SAMPLES_PER_FRAME]; + PaError err; + PABLIO_Stream *aStream; + + printf("Full duplex sound test using PortAudio and RingBuffers\n"); + fflush(stdout); + + /* Open simplified blocking I/O layer on top of PortAudio. */ + err = OpenAudioStream( &aStream, SAMPLE_RATE, SAMPLE_TYPE, + (PABLIO_READ_WRITE | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + + /* Process samples in the foreground. */ + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ ) + { + /* Read one frame of data into sample array from audio input. */ + ReadAudioStream( aStream, samples, 1 ); + /* Write that same frame of data to output. */ + /* samples[1] = (i&256) * (1.0f/256.0f); /* sawtooth */ + WriteAudioStream( aStream, samples, 1 ); + } + + CloseAudioStream( aStream ); + + printf("Full duplex sound test complete.\n" ); + fflush(stdout); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} diff --git a/pablio/test_rw_echo.c b/pablio/test_rw_echo.c new file mode 100644 index 0000000..9ba8c8d --- /dev/null +++ b/pablio/test_rw_echo.c @@ -0,0 +1,123 @@ +/* + * $Id$ + * test_rw_echo.c + * Echo delayed input to output. + * + * Author: Phil Burk, http://www.softsynth.com/portaudio/ + * + * This program uses PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * + * Note that if you need low latency, you should not use PABLIO. + * Use the PA_OpenStream callback technique which is lower level + * than PABLIO. + * + * For more information see: 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. + * + */ + +#include +#include +#include +#include "pablio.h" +#include + +/* +** Note that many of the older ISA sound cards on PCs do NOT support +** full duplex audio (simultaneous record and playback). +** And some only support full duplex at lower sample rates. +*/ +#define SAMPLE_RATE (22050) +#define NUM_SECONDS (20) +#define SAMPLES_PER_FRAME (2) + +/* Select whether we will use floats or shorts. */ +#if 1 +#define SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#else +#define SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#endif + +#define NUM_ECHO_FRAMES (2*SAMPLE_RATE) +SAMPLE samples[NUM_ECHO_FRAMES][SAMPLES_PER_FRAME] = {0.0}; + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i; + PaError err; + PABLIO_Stream *aInStream; + PABLIO_Stream *aOutStream; + int index; + + printf("Full duplex sound test using PABLIO\n"); + fflush(stdout); + + /* Open simplified blocking I/O layer on top of PortAudio. */ + /* Open input first so it can start to fill buffers. */ + err = OpenAudioStream( &aInStream, SAMPLE_RATE, SAMPLE_TYPE, + (PABLIO_READ | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + /* printf("opened input\n"); fflush(stdout); /**/ + + err = OpenAudioStream( &aOutStream, SAMPLE_RATE, SAMPLE_TYPE, + (PABLIO_WRITE | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + /* printf("opened output\n"); fflush(stdout); /**/ + + /* Process samples in the foreground. */ + index = 0; + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ ) + { + /* Write old frame of data to output. */ + /* samples[index][1] = (i&256) * (1.0f/256.0f); /* sawtooth */ + WriteAudioStream( aOutStream, &samples[index][0], 1 ); + + /* Read one frame of data into sample array for later output. */ + ReadAudioStream( aInStream, &samples[index][0], 1 ); + index += 1; + if( index >= NUM_ECHO_FRAMES ) index = 0; + + if( (i & 0xFFFF) == 0 ) printf("i = %d\n", i ); fflush(stdout); /**/ + } + + CloseAudioStream( aOutStream ); + CloseAudioStream( aInStream ); + + printf("R/W echo sound test complete.\n" ); + fflush(stdout); + return 0; + +error: + fprintf( stderr, "An error occured while using PortAudio\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} diff --git a/pablio/test_w_saw.c b/pablio/test_w_saw.c new file mode 100644 index 0000000..d5d4e9b --- /dev/null +++ b/pablio/test_w_saw.c @@ -0,0 +1,108 @@ +/* + * $Id$ + * test_w_saw.c + * Generate stereo sawtooth waveforms. + * + * Author: Phil Burk, http://www.softsynth.com + * + * This program uses PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * + * For more information see: 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. + * + */ + +#include +#include +#include +#include "pablio.h" +#include + +#define SAMPLE_RATE (44100) +#define NUM_SECONDS (6) +#define SAMPLES_PER_FRAME (2) + +#define FREQUENCY (220.0f) +#define PHASE_INCREMENT (2.0f * FREQUENCY / SAMPLE_RATE) +#define FRAMES_PER_BLOCK (100) + +float samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME]; +float phases[SAMPLES_PER_FRAME]; + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i,j; + PaError err; + PABLIO_Stream *aOutStream; + + printf("Generate sawtooth waves using PABLIO.\n"); + fflush(stdout); + + /* Open simplified blocking I/O layer on top of PortAudio. */ + err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paFloat32, + (PABLIO_WRITE | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + + /* Initialize oscillator phases. */ + phases[0] = 0.0; + phases[1] = 0.0; + + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) + { + /* Generate sawtooth waveforms in a block for efficiency. */ + for( j=0; j 1.0f ) phases[0] -= 2.0f; + samples[j][0] = phases[0]; + + /* On the second channel, generate a sawtooth wave a fifth higher. */ + phases[1] += PHASE_INCREMENT * (3.0f / 2.0f); + if( phases[1] > 1.0f ) phases[1] -= 2.0f; + samples[j][1] = phases[1]; + } + + /* Write samples to output. */ + WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK ); + } + + CloseAudioStream( aOutStream ); + + printf("Sawtooth sound test complete.\n" ); + fflush(stdout); + return 0; + +error: + fprintf( stderr, "An error occured while using PABLIO\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} diff --git a/pablio/test_w_saw8.c b/pablio/test_w_saw8.c new file mode 100644 index 0000000..0a9d05a --- /dev/null +++ b/pablio/test_w_saw8.c @@ -0,0 +1,106 @@ +/* + * $Id$ + * test_w_saw8.c + * Generate stereo 8 bit sawtooth waveforms. + * + * Author: Phil Burk, http://www.softsynth.com + * + * This program uses PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * + * For more information see: 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. + * + */ + +#include +#include +#include +#include "pablio.h" +#include + +#define SAMPLE_RATE (22050) +#define NUM_SECONDS (6) +#define SAMPLES_PER_FRAME (2) + + +#define FRAMES_PER_BLOCK (100) + +unsigned char samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME]; +unsigned char phases[SAMPLES_PER_FRAME]; + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i,j; + PaError err; + PABLIO_Stream *aOutStream; + + printf("Generate unsigned 8 bit sawtooth waves using PABLIO.\n"); + fflush(stdout); + + /* Open simplified blocking I/O layer on top of PortAudio. */ + err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paUInt8, + (PABLIO_WRITE | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + + /* Initialize oscillator phases to "ground" level for paUInt8. */ + phases[0] = 128; + phases[1] = 128; + + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) + { + /* Generate sawtooth waveforms in a block for efficiency. */ + for( j=0; j Date: Tue, 22 Jan 2002 00:55:40 +0000 Subject: [PATCH 002/814] Removed extra Id --- pa_tests/patest_sine.c | 1 - 1 file changed, 1 deletion(-) diff --git a/pa_tests/patest_sine.c b/pa_tests/patest_sine.c index f6d8f6a..1f0dcd7 100644 --- a/pa_tests/patest_sine.c +++ b/pa_tests/patest_sine.c @@ -1,5 +1,4 @@ /* - * $Id$ * $Id$ * patest_sine.c * Play a sine wave using the Portable Audio api for several seconds. From e29246b0eaa6ccbd4ea181a49ee2639179b8719c Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 23 Jan 2002 20:01:11 +0000 Subject: [PATCH 003/814] fixed formatting, typos and grammar in comments reordered PaTimestamp to put all device info functionality together --- pa_common/portaudio.h | 183 +++++++++++++++++++++++++----------------- 1 file changed, 108 insertions(+), 75 deletions(-) diff --git a/pa_common/portaudio.h b/pa_common/portaudio.h index 231e804..48e0d55 100644 --- a/pa_common/portaudio.h +++ b/pa_common/portaudio.h @@ -63,6 +63,7 @@ typedef enum { /* Pa_Initialize() is the library initialisation function - call this before using the library. + */ PaError Pa_Initialize( void ); @@ -70,19 +71,25 @@ PaError Pa_Initialize( void ); /* Pa_Terminate() is the library termination function - call this after using the library. + */ PaError Pa_Terminate( void ); /* - Return host specific error. - This can be called after receiving a paHostError. + Pa_GetHostError() returns a host specific error code. + This can be called after receiving a PortAudio error code of paHostError. + */ + long Pa_GetHostError( void ); /* - Translate the error number into a human readable message. + Pa_GetErrorText() translates the supplied PortAudio error number + into a human readable message. + */ + const char *Pa_GetErrorText( PaError errnum ); /* @@ -92,11 +99,12 @@ const char *Pa_GetErrorText( PaError errnum ); 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 devices. + Formats marked "always available" are supported (emulated) by all + PortAudio implementations. The floating point representation uses +1.0 and -1.0 as the respective maximum and minimum. - + */ typedef unsigned long PaSampleFormat; @@ -106,24 +114,27 @@ typedef unsigned long PaSampleFormat; #define paInt24 ((PaSampleFormat) (1<<3)) #define paPackedInt24 ((PaSampleFormat) (1<<4)) #define paInt8 ((PaSampleFormat) (1<<5)) -#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */ +#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */ #define paCustomFormat ((PaSampleFormat) (1<<16)) /* Device enumeration mechanism. - Device ids range from 0 to Pa_CountDevices()-1. + Device ids range from 0 to Pa_CountDevices()-1. Devices may support input, output or both. Device 0 is always the "default" device and should support at least stereo in and out if that is available - on the taget platform _even_ if this involves kludging an input/output + on the target platform _even_ if this involves kludging an input/output device on platforms that usually separate input from output. Other platform specific devices are specified by positive device ids. + */ typedef int PaDeviceID; #define paNoDevice -1 +int Pa_CountDevices(); + typedef struct { int structVersion; @@ -138,12 +149,10 @@ typedef struct } PaDeviceInfo; - -int Pa_CountDevices(); /* - Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() - - Return the default device ID or paNoDevice if there is no devices. + 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 @@ -151,34 +160,40 @@ int Pa_CountDevices(); set PA_RECOMMENDED_OUTPUT_DEVICE=1 - The user should first determine the available device ID by using + 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 useful for syncronisation. The type is used in the outTime - argument to the callback function and the result of Pa_StreamTime() + 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; /* - Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure - referring to the device specified by id. - If id is out of range the function returns NULL. - - The returned structure is owned by the PortAudio implementation and must - not be manipulated or freed. The pointer is only guaranteed to be valid - between calls to Pa_Initialize() and Pa_Terminate(). -*/ - -const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID ); - -/* - PortAudioCallback is implemented by clients of the portable audio api. + 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 @@ -194,15 +209,15 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID ); intended for storing synthesis data etc. return value: - The callback can return a nonzero value to stop the stream. This may be + 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 - nonzero value must fill the entire outputBuffer. + 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)( @@ -216,12 +231,11 @@ typedef int (PortAudioCallback)( These flags may be supplied (ored together) in the streamFlags argument to the Pa_OpenStream() function. - - [ suggestions? ] + */ #define paNoFlag (0) -#define paClipOff (1<<0) /* disable defult clipping of out of range samples */ +#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; @@ -246,15 +260,15 @@ typedef void PortAudioStream; 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 - device input record for the device specified in the inputDevice parameter. + PaDeviceInfo record for the device specified by the inputDevice parameter. If inputDevice is paNoDevice numInputChannels is ignored. - inputSampleFormat is the format of inputBuffer provided to the callback + 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 sound devices 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. + 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. @@ -276,24 +290,24 @@ typedef void PortAudioStream; outputDriverInfo is never required for correct operation. If not used outputDriverInfo should be NULL. - sampleRate is the desired sampleRate for input and output + 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.) + 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 behavior of the - streaming process. Some flags may only be relevant to certain buffer formats. + 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.) @@ -303,10 +317,10 @@ typedef void PortAudioStream; for processing the audio buffers. return value: - Apon success Pa_OpenStream() returns PaNoError and places a pointer to a + 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 nonzero error code is returned (see - PAError above) and the value of stream is invalid. + If a call to Pa_OpenStream() fails a non-zero error code is returned (see + PaError above) and the value of stream is invalid. */ @@ -328,15 +342,16 @@ PaError Pa_OpenStream( PortAudioStream** stream, /* - Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that - opens the default input and/or ouput devices. Most parameters have - identical meaning to their Pa_OpenStream() counterparts, with the following - exceptions: + 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 (same as passing paNoDevice in the device arguments to Pa_OpenStream() ) + 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, @@ -351,15 +366,17 @@ PaError Pa_OpenDefaultStream( PortAudioStream** stream, /* 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_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. + Pa_AbortStream() stops playing immediately without waiting for pending + buffers to complete. + */ PaError Pa_StartStream( PortAudioStream *stream ); @@ -369,37 +386,43 @@ PaError Pa_StopStream( PortAudioStream *stream ); PaError Pa_AbortStream( PortAudioStream *stream ); /* - Pa_StreamActive() returns one when the stream is playing audio, - zero when not playing, or a negative error number if the - stream is invalid. + 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 for the stream in samples. - This time may be used as a time reference (for example syncronising audio to + 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 ); /* - The "CPU Load" is a fraction of total CPU time consumed by the - stream's audio processing. + 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 ); /* - Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for - the current host based on minimum latency. + 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: @@ -409,23 +432,33 @@ double Pa_GetCPULoad( PortAudioStream* stream ); 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 ); /* - 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() 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 ); /* - Return size in bytes of a single sample in a given PaSampleFormat - or paSampleFormatNotSupported. + 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 */ From 59dda9858acecd25e3251d8a6948c5490502ec95 Mon Sep 17 00:00:00 2001 From: rossb Date: Thu, 24 Jan 2002 22:42:56 +0000 Subject: [PATCH 004/814] more comment cleanups, removed incorrect synthetic device 0 comment --- pa_common/portaudio.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pa_common/portaudio.h b/pa_common/portaudio.h index 48e0d55..8c5eae5 100644 --- a/pa_common/portaudio.h +++ b/pa_common/portaudio.h @@ -102,8 +102,10 @@ const char *Pa_GetErrorText( PaError errnum ); Formats marked "always available" are supported (emulated) by all PortAudio implementations. - The floating point representation uses +1.0 and -1.0 as the respective - maximum and minimum. + 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" */ @@ -114,7 +116,7 @@ typedef unsigned long PaSampleFormat; #define paInt24 ((PaSampleFormat) (1<<3)) #define paPackedInt24 ((PaSampleFormat) (1<<4)) #define paInt8 ((PaSampleFormat) (1<<5)) -#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */ +#define paUInt8 ((PaSampleFormat) (1<<6)) #define paCustomFormat ((PaSampleFormat) (1<<16)) /* @@ -122,11 +124,7 @@ typedef unsigned long PaSampleFormat; Device ids range from 0 to Pa_CountDevices()-1. - Devices may support input, output or both. Device 0 is always the "default" - device and should support at least stereo in and out if that is available - on the target platform _even_ if this involves kludging an input/output - device on platforms that usually separate input from output. Other platform - specific devices are specified by positive device ids. + Devices may support input, output or both. */ From 9ba97df1157fe905e8a0ebfa31d7b9f82c4198b3 Mon Sep 17 00:00:00 2001 From: phil Date: Thu, 31 Jan 2002 04:25:55 +0000 Subject: [PATCH 005/814] Added file for testing CVS --- testcvs/changeme.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 testcvs/changeme.txt diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt new file mode 100644 index 0000000..aa81f4c --- /dev/null +++ b/testcvs/changeme.txt @@ -0,0 +1,2 @@ +This is just a dopy little file used to test the CVS repository. +Feel free to trash this file. From 4e5d7d23fd7c955823b8df31fd17d5bc605a0fdd Mon Sep 17 00:00:00 2001 From: stephane Date: Thu, 31 Jan 2002 19:02:56 +0000 Subject: [PATCH 006/814] tweak test --- testcvs/changeme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt index aa81f4c..6eee6b8 100644 --- a/testcvs/changeme.txt +++ b/testcvs/changeme.txt @@ -1,2 +1,3 @@ This is just a dopy little file used to test the CVS repository. Feel free to trash this file. +Minor change. From 2638cf43c9bf9d863f9b3370195d39fcac2585ee Mon Sep 17 00:00:00 2001 From: stephane Date: Thu, 31 Jan 2002 19:08:14 +0000 Subject: [PATCH 007/814] test --- testcvs/changeme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt index 6eee6b8..b34e276 100644 --- a/testcvs/changeme.txt +++ b/testcvs/changeme.txt @@ -1,3 +1,4 @@ This is just a dopy little file used to test the CVS repository. Feel free to trash this file. Minor change. +Another tweak. \ No newline at end of file From 879780faa4496263201a01973069ac83836f0cea Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 31 Jan 2002 19:16:05 +0000 Subject: [PATCH 008/814] tweak --- testcvs/changeme.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt index b34e276..73d777f 100644 --- a/testcvs/changeme.txt +++ b/testcvs/changeme.txt @@ -1,4 +1,5 @@ This is just a dopy little file used to test the CVS repository. Feel free to trash this file. Minor change. -Another tweak. \ No newline at end of file +Another tweak. +philburk tweak From 5813acec61551c74907df6b59d876c89bcedeeac Mon Sep 17 00:00:00 2001 From: stephane Date: Thu, 31 Jan 2002 19:38:16 +0000 Subject: [PATCH 009/814] test from stephane --- testcvs/changeme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt index 73d777f..e71086d 100644 --- a/testcvs/changeme.txt +++ b/testcvs/changeme.txt @@ -3,3 +3,4 @@ Feel free to trash this file. Minor change. Another tweak. philburk tweak +stephane test \ No newline at end of file From 1b96fa74a38dc05d668572fa85b89277210e7b3b Mon Sep 17 00:00:00 2001 From: stephane Date: Fri, 1 Feb 2002 10:18:16 +0000 Subject: [PATCH 010/814] Cleanup, test of multiple-stream opening --- pa_asio/pa_asio.cpp | 45 ++++----------------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/pa_asio/pa_asio.cpp b/pa_asio/pa_asio.cpp index 66adf48..7d98a19 100644 --- a/pa_asio/pa_asio.cpp +++ b/pa_asio/pa_asio.cpp @@ -51,17 +51,18 @@ 11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz + 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz TO DO : - Check Pa_StopSteam and Pa_AbortStream - Optimization for Input only or Ouput only (really necessary ??) - - Opening of several streams */ #include #include +#include #include "portaudio.h" #include "pa_host.h" @@ -167,16 +168,6 @@ typedef struct PaHostSoundControl //---------------------------------------------------------- -// name of the ASIO device to be used -#if WINDOWS - //#define ASIO_DRIVER_NAME "ASIO Multimedia Driver" - #define ASIO_DRIVER_NAME "ASIO Sample" -#elif MAC - //#define ASIO_DRIVER_NAME "Apple Sound Manager" - #define ASIO_DRIVER_NAME "ASIO Delta1010" - //#define ASIO_DRIVER_NAME "DigiDesign DirectIO" -#endif - #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) @@ -271,34 +262,6 @@ bool loadAsioDriver(char *name); unsigned long get_sys_reference_time(); -// For callback debugging on Mac : to be removed in the final version - -/* -#define MidiSharePPC_68k -#include - -void SendVal (long val) -{ - MidiEvPtr ev = MidiNewEv(typeTempo); - if (ev) { - Tempo(ev) = val; - MidiSendIm(0,ev); - } -} - -void MidiPrintText ( char * s) -{ - MidiEvPtr e; - long c = 0; - - if (e = MidiNewEv(typeTextual)){ - for (c = 0 ; *s ; s++,c++) MidiAddField (e ,*s); - MidiSendIm (0, e); - } -} -*/ - - /************************************************************************************/ /****************** Macro ************************************************************/ /************************************************************************************/ @@ -2620,8 +2583,8 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) ASIOError err; int32 device; - /* TO DO : Check if a stream already runs */ - //if (asioDriverInfo.past != NULL) return paHostError; (does not work) + /* Check if a stream already runs */ + if (asioDriverInfo.past != NULL) return paHostError; /* Check the device number */ if ((past->past_InputDeviceID != paNoDevice) From ae00b6ebdee66d13453558f1c042a7e702a64443 Mon Sep 17 00:00:00 2001 From: phil Date: Thu, 7 Feb 2002 17:54:56 +0000 Subject: [PATCH 011/814] try lower latency, better print messages --- pa_tests/patest_latency.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pa_tests/patest_latency.c b/pa_tests/patest_latency.c index 2daf431..a081b29 100644 --- a/pa_tests/patest_latency.c +++ b/pa_tests/patest_latency.c @@ -3,7 +3,7 @@ * Hear the latency caused by bug buffers. * Play a sine wave and change frequency based on letter input. * - * Author: Phil Burk + * Author: Phil Burk , and Darren Gibbs * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com @@ -36,15 +36,18 @@ #include #include #include "portaudio.h" + #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (256) -#if 1 +#define FRAMES_PER_BUFFER (64) + +#if 0 #define MIN_LATENCY_MSEC (2000) #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #else #define NUM_BUFFERS (0) #endif + #define MIN_FREQ (100.0f) #define CalcPhaseIncrement(freq) ((freq)/SAMPLE_RATE) #ifndef M_PI @@ -108,7 +111,7 @@ int main(void) paTestData data; int i; int done = 0; - printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS ); + printf("PortAudio Test: enter letter then hit ENTER. numBuffers = %d\n", NUM_BUFFERS ); /* initialise sinusoidal wavetable */ for( i=0; i Date: Thu, 7 Feb 2002 17:57:44 +0000 Subject: [PATCH 012/814] add fflush(stdout) so we can see progress --- pa_tests/debug_record.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pa_tests/debug_record.c b/pa_tests/debug_record.c index fd4118e..6acd161 100644 --- a/pa_tests/debug_record.c +++ b/pa_tests/debug_record.c @@ -42,15 +42,17 @@ #define SAMPLE_RATE (22050) #define NUM_SECONDS (10) #define SLEEP_DUR_MSEC (200) -#define REC_BUF_FRAMES (1<<10) +#define FRAMES_PER_BUFFER (1<<10) #define NUM_REC_BUFS (0) -#if 0 + +#if 1 #define PA_SAMPLE_TYPE paFloat32 typedef float SAMPLE; #else #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; #endif + typedef struct { long frameIndex; /* Index into sample array. */ @@ -195,7 +197,7 @@ int main(void) PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, - REC_BUF_FRAMES, /* frames per buffer */ + FRAMES_PER_BUFFER, /* frames per buffer */ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ recordCallback, @@ -203,6 +205,7 @@ int main(void) if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; + printf("Now recording!\n"); fflush(stdout); for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) { @@ -217,8 +220,9 @@ int main(void) break; } Pa_Sleep(100); - printf("index = %d\n", data.frameIndex ); + printf("index = %d\n", data.frameIndex ); fflush(stdout); } + err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; /* Playback recorded data. */ @@ -235,7 +239,7 @@ int main(void) PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, - 1024, /* frames per buffer */ + FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ playCallback, @@ -265,7 +269,7 @@ int main(void) printf("Largest recorded sample = %d\n", max ); } /* Write recorded data to a file. */ -#if 0 +#if 1 { FILE *fid; fid = fopen("recorded.raw", "wb"); From 03fca8ce5d9dc14a0653adeb01a422b4377b3d20 Mon Sep 17 00:00:00 2001 From: phil Date: Thu, 7 Feb 2002 18:04:00 +0000 Subject: [PATCH 013/814] Mods made with Darren Gibbs. fixed isInput so GetProperty works better, fixed device queries for numChannels and sampleRates, one CoreAudio device now maps to separate input and output PaDevices, audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices). --- pa_mac_core/pa_mac_core.c | 748 +++++++++++++++++++------------------- 1 file changed, 374 insertions(+), 374 deletions(-) diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c index 3dc4d74..3d38e2b 100644 --- a/pa_mac_core/pa_mac_core.c +++ b/pa_mac_core/pa_mac_core.c @@ -37,6 +37,17 @@ 3.29.2001 - Phil Burk - First pass... converted from Window MME code with help from Darren. 3.30.2001 - Darren Gibbs - Added more support for dynamically querying device info. 12.7.2001 - Gord Peters - Tweaks to compile on PA V17 and OS X 10.1 + 2.7.2002 - Darren and Phil - fixed isInput so GetProperty works better, + fixed device queries for numChannels and sampleRates, + one CoreAudio device now maps to separate input and output PaDevices, + audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices). + +TODO: +O- conversion for other user formats besides paFloat32 +O- FIFO between input and output callbacks if different devices, like in pa_mac.c +O- debug mono output +O- error check for unsupported sample rates +O- BUG: if ask for 22050 when only 44100 supported then get 44100 and no error message */ #include #include @@ -47,9 +58,6 @@ #include "pa_trace.h" /************************************************* Constants ********/ -#define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ -#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ - /* Switches for debugging. */ #define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ @@ -57,20 +65,17 @@ #define PA_TRACE_RUN (0) #define PA_TRACE_START_STOP (1) -#define PA_MIN_MSEC_PER_HOST_BUFFER (10) -#define PA_MAX_MSEC_PER_HOST_BUFFER (100) /* Do not exceed unless user buffer exceeds */ -#define PA_MIN_NUM_HOST_BUFFERS (3) -#define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ -#define PA_MIN_LATENCY_MSEC (200) - -#define MIN_TIMEOUT_MSEC (1000) +#define PA_MIN_LATENCY_MSEC (8) +#define MIN_TIMEOUT_MSEC (1000) #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ -/************************************************* Definitions ********/ +// define value of isInput passed to CodeAudio routines +#define IS_INPUT (true) +#define IS_OUTPUT (false) /************************************************************** * Structure for internal host specific stream data. @@ -78,11 +83,11 @@ */ typedef struct PaHostSoundControl { + AudioDeviceID pahsc_AudioDeviceID; // Must be the same for input and output for now. /* Input -------------- */ int pahsc_BytesPerHostInputBuffer; int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */ /* Output -------------- */ - AudioDeviceID pahsc_OutputAudioDeviceID; int pahsc_BytesPerHostOutputBuffer; int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */ /* Run Time -------------- */ @@ -92,7 +97,6 @@ typedef struct PaHostSoundControl // LARGE_INTEGER pahsc_EntryCount; // LARGE_INTEGER pahsc_LastExitCount; /* Init Time -------------- */ - int pahsc_NumHostBuffers; int pahsc_FramesPerHostBuffer; int pahsc_UserBuffersPerHostBuffer; @@ -102,14 +106,30 @@ typedef struct PaHostSoundControl } PaHostSoundControl; +/************************************************************** + * Structure for internal extended device info. + * There will be one or two PortAudio devices for each Core Audio device: + * one input and or one output. + */ +typedef struct PaHostDeviceInfo +{ + PaDeviceInfo paInfo; + AudioDeviceID audioDeviceID; +} +PaHostDeviceInfo; + /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ -static int sNumDevices = 0; -static PaDeviceInfo **sDevicePtrs = NULL; +static int sNumPaDevices = 0; /* Total number of PaDeviceInfos */ +static int sNumInputDevices = 0; /* Total number of input PaDeviceInfos */ +static int sNumOutputDevices = 0; +static PaHostDeviceInfo *sDeviceInfos = NULL; static int sDefaultInputDeviceID = paNoDevice; static int sDefaultOutputDeviceID = paNoDevice; static int sPaHostError = 0; -static AudioDeviceID *sDeviceIDList; // Array of AudioDeviceIDs + +static int sNumCoreDevices = 0; +static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs static const char sMapperSuffixInput[] = " - Input"; static const char sMapperSuffixOutput[] = " - Output"; @@ -123,6 +143,14 @@ static const char sMapperSuffixOutput[] = " - Output"; static PaError Pa_QueryDevices( void ); PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); + +static int PaHost_ScanDevices( Boolean isInput ); +static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput ); + +static PaDeviceID Pa_QueryDefaultInputDevice( void ); +static PaDeviceID Pa_QueryDefaultOutputDevice( void ); +static void PaHost_CalcHostBufferSize( internalPortAudioStream *past ); + /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { @@ -170,24 +198,55 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) #endif } -static PaDeviceID Pa_QueryDefaultDevice( int deviceEnum ) +/************************************************************************/ +static PaDeviceID Pa_QueryDefaultInputDevice( void ) { OSStatus err = noErr; UInt32 count; int i; - AudioDeviceID tempDevice = kAudioDeviceUnknown; + AudioDeviceID tempDeviceID = kAudioDeviceUnknown; PaDeviceID defaultDeviceID; // get the default output device for the HAL // it is required to pass the size of the data to be returned count = sizeof(AudioDeviceID); - err = AudioHardwareGetProperty( deviceEnum, &count, (void *) &tempDevice); + err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &tempDeviceID); if (err != noErr) goto Bail; - // find index of default device + // scan input devices to see which one matches this device defaultDeviceID = paNoDevice; - for( i=0; i= sNumPaDevices ) + return NULL; - PaDeviceInfo *deviceInfo; - AudioDeviceID devID; - double *sampleRates; /* non-const ptr */ - double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0}; + return &sDeviceInfos[id].paInfo; +} + +/************************************************************************* +** Scan all of the Core Audio devices to see which support input or output. +** Changes sNumDevices, and fills in sDeviceInfos. +*/ +static int PaHost_ScanDevices( Boolean isInput ) +{ + int coreDeviceIndex; + int result; + PaHostDeviceInfo *hostDeviceInfo; + int numAdded = 0; + + for( coreDeviceIndex=0; coreDeviceIndexaudioDeviceID )); + if( result > 0 ) + { + sNumPaDevices += 1; // bump global counter if we got one + numAdded += 1; + } + else if( result < 0 ) return result; + } + return numAdded; +} + +/************************************************************************* +** Try to fill in the device info for this device. +** Return 1 if a good device that PA can use. +** Return 0 if not appropriate +** or return negative error. +** +*/ +static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput ) +{ + OSErr err; int index; AudioStreamBasicDescription formatDesc; Boolean result; + AudioDeviceID devID; + double *sampleRates = NULL; /* non-const ptr */ - if( id < 0 || id >= sNumDevices ) - return NULL; - - if( sDevicePtrs[ id ] != NULL ) - { - return sDevicePtrs[ id ]; - } - - deviceInfo = PaHost_AllocateFastMemory( sizeof(PaDeviceInfo) ); - if( deviceInfo == NULL ) return NULL; + PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo; + double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0}; + int maxNumSampleRates = sizeof( possibleSampleRates ) / sizeof( double ); deviceInfo->structVersion = 1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->numSampleRates = -1; + devID = sCoreDeviceIDs[ coreDeviceIndex ]; + hostDeviceInfo->audioDeviceID = devID; - // fill in format descriptor - if( id < sNumDevices ) + // Figure out supported sample rates + // Make room in case device supports all rates. + sampleRates = (double*)PaHost_AllocateFastMemory( maxNumSampleRates * sizeof(double) ); + if( sampleRates == NULL ) return paInsufficientMemory; + + deviceInfo->sampleRates = sampleRates; + deviceInfo->numSampleRates = 0; + + // Loop through the possible sampling rates and check each to see if the device supports it. + for (index = 0; index < maxNumSampleRates; index ++) { - devID = sDeviceIDList[ id ]; + memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); + formatDesc.mSampleRate = possibleSampleRates[index]; + result = deviceDoesSupportFormat( devID, &formatDesc, isInput ); - // Get the device name - deviceInfo->name = deviceNameFromID( devID ); - - // Figure out supported sample rates - // Make room in case device supports all rates. - sampleRates = (double*)PaHost_AllocateFastMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); - deviceInfo->sampleRates = sampleRates; - deviceInfo->numSampleRates = 0; - - // Loop through the possible sampling rates and check each to see if the device supports it. - for (index = 0; index < MAX_NUMSAMPLINGRATES; index ++) + if (result == true) { - memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); - formatDesc.mSampleRate = possibleSampleRates[index]; - result = deviceDoesSupportFormat( devID, &formatDesc ); - - if (result == true) - { - deviceInfo->numSampleRates += 1; - *sampleRates = possibleSampleRates[index]; - sampleRates++; - } + deviceInfo->numSampleRates += 1; + *sampleRates = possibleSampleRates[index]; + sampleRates++; } + } + // If no sample rates supported, then not a very good device. + if( deviceInfo->numSampleRates == 0 ) goto error; - // Get data format info from the device. - deviceDataFormatFromID(devID, &formatDesc); + // Get data format info from the device. + err = deviceDataFormatFromID(devID, &formatDesc, isInput ); + // If no channels supported, then not a very good device. + if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error; - deviceInfo->maxInputChannels = 0; // FIXME - Input and Output are separate devices! + if( isInput ) + { + deviceInfo->maxInputChannels = formatDesc.mChannelsPerFrame; + } + else + { deviceInfo->maxOutputChannels = formatDesc.mChannelsPerFrame; - - // FIXME - where to put current sample rate?: formatDesc.mSampleRate - - // Right now the Core Audio headers only define one formatID: LinearPCM - // Apparently LinearPCM must be Float32 for now. - // FIXME - - switch (formatDesc.mFormatID) - { - case kAudioFormatLinearPCM: - deviceInfo->nativeSampleFormats = paFloat32; - - // FIXME - details about the format are in these flags. - // formatDesc.mFormatFlags - - // here are the possibilities - // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer - // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little - // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer, - // only valid if kLinearPCMFormatFlagIsFloat is clear - // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible, - // clear if they are high or low aligned within the channel - // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed - - break; - default: - deviceInfo->nativeSampleFormats = paFloat32; // FIXME - break; - } - } - sDevicePtrs[ id ] = deviceInfo; - return deviceInfo; + // FIXME - where to put current sample rate?: formatDesc.mSampleRate - /* FIXME - error: - free( sampleRates ); - free( deviceInfo ); - */ + // Right now the Core Audio headers only define one formatID: LinearPCM + // Apparently LinearPCM must be Float32 for now. + switch (formatDesc.mFormatID) + { + case kAudioFormatLinearPCM: + deviceInfo->nativeSampleFormats = paFloat32; - return NULL; + // FIXME - details about the format are in these flags. + // formatDesc.mFormatFlags + + // here are the possibilities + // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer + // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little + // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer, + // only valid if kLinearPCMFormatFlagIsFloat is clear + // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible, + // clear if they are high or low aligned within the channel + // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed + break; + + default: + deviceInfo->nativeSampleFormats = paFloat32; // FIXME + break; + } + + + // Get the device name + deviceInfo->name = deviceNameFromID( devID, isInput ); + return 1; + +error: + if( sampleRates != NULL ) free( sampleRates ); + return 0; } /************************************************************************* @@ -491,7 +586,7 @@ static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) static PaError Pa_MaybeQueryDevices( void ) { - if( sNumDevices == 0 ) + if( sNumPaDevices == 0 ) { return Pa_QueryDevices(); } @@ -622,7 +717,10 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL return (result != 0) ? result : done; } -OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* contextPtr) +OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, + const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, + AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, + void* contextPtr) { PaError result = 0; @@ -665,6 +763,7 @@ OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const return result; } +#if 0 static int PaHost_CalcTimeOut( internalPortAudioStream *past ) { /* Calculate timeOut longer than longest time it could take to play all buffers. */ @@ -672,59 +771,36 @@ static int PaHost_CalcTimeOut( internalPortAudioStream *past ) if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; return timeOut; } - +#endif /*******************************************************************/ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) { - PaError result = paNoError; PaHostSoundControl *pahsc; + const PaHostDeviceInfo *hostDeviceInfo; + PaError result = paNoError; + UInt32 bytesPerHostBuffer; + UInt32 dataSize; + OSStatus err = noErr; int bytesPerInputFrame; - const PaDeviceInfo *pad; pahsc = (PaHostSoundControl *) past->past_DeviceData; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID)); - pad = Pa_GetDeviceInfo( past->past_InputDeviceID ); - if( pad == NULL ) return paInternalError; + if( (past->past_InputDeviceID < 0) || (past->past_InputDeviceID >= sNumPaDevices) ) + { + return paInvalidDeviceId; + } + hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID]; - bytesPerInputFrame = Pa_GetSampleSize(pad->nativeSampleFormats) * past->past_NumInputChannels; + // calculate buffer sizes in bytes + bytesPerInputFrame = Pa_GetSampleSize(past->past_InputSampleFormat) * past->past_NumInputChannels; pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame; - pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer; - // FIXME - return result; -} + pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerInputFrame; -/*******************************************************************/ -PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) -{ - PaError result = paNoError; - PaHostSoundControl *pahsc; - const PaDeviceInfo *pad; - UInt32 bytesPerHostBuffer; - UInt32 dataSize; - UInt32 hardwareLatency = -1; - Boolean writeable = false; - OSStatus err = noErr; - int bytesPerOutputFrame; - - pahsc = (PaHostSoundControl *) past->past_DeviceData; - - DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); - pad = Pa_GetDeviceInfo( past->past_OutputDeviceID ); - if( pad == NULL ) return paInternalError; - - pahsc->pahsc_OutputAudioDeviceID = sDeviceIDList[past->past_OutputDeviceID]; - - bytesPerOutputFrame = Pa_GetSampleSize(pad->nativeSampleFormats) * past->past_NumOutputChannels; - pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame; - pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer; - - // FIXME - force host buffer to user size - - // change the bufferSize of the device - bytesPerHostBuffer = past->past_OutputBufferSize; // FIXME + // Change the bufferSize of the device! Is this per device or just for our stream? + bytesPerHostBuffer = pahsc->pahsc_BytesPerHostInputBuffer; dataSize = sizeof(UInt32); - err = AudioDeviceSetProperty( pahsc->pahsc_OutputAudioDeviceID, 0, 0, false, + err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT, kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); if( err != noErr ) { @@ -733,22 +809,47 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) goto error; } - // FIXME -- this isn't working for some reason. I can't figure out what the error code is. + return result; + +error: + return result; +} + +/*******************************************************************/ +PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) +{ + PaHostSoundControl *pahsc; + const PaHostDeviceInfo *hostDeviceInfo; + PaError result = paNoError; + UInt32 bytesPerHostBuffer; + UInt32 dataSize; + OSStatus err = noErr; + int bytesPerOutputFrame; + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); + if( (past->past_OutputDeviceID < 0) || (past->past_OutputDeviceID >= sNumPaDevices) ) + { + return paInvalidDeviceId; + } + hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID]; + + // calculate buffer sizes in bytes + bytesPerOutputFrame = Pa_GetSampleSize(past->past_OutputSampleFormat) * past->past_NumOutputChannels; + pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame; + pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerOutputFrame; + + // Change the bufferSize of the device! Is this per device or just for our stream? + bytesPerHostBuffer = pahsc->pahsc_BytesPerHostOutputBuffer; dataSize = sizeof(UInt32); - err = AudioDeviceGetProperty(pahsc->pahsc_OutputAudioDeviceID, 0, false, kAudioDevicePropertyLatency, &dataSize, &writeable); + err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT, + kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); if( err != noErr ) { - PRINT(("A CoreAudio error occurred: %s.\n", coreAudioErrorString( err ) )); - } - - err = AudioDeviceGetProperty(pahsc->pahsc_OutputAudioDeviceID, 0, false, kAudioDevicePropertyLatency, &dataSize, (void *)&hardwareLatency); - if ( err != noErr ) - { - PRINT(("A CoreAudio error occurred: %s.\n", coreAudioErrorString( err ) )); - } - else - { - PRINT(("Output Stream Hardware Latency = %d frames.\n", hardwareLatency )); + ERR_RPT(("Could not force buffer size!")); + result = paHostError; + goto error; } return result; @@ -761,92 +862,38 @@ error: PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer; + return pahsc->pahsc_FramesPerHostBuffer; } /******************************************************************* -* Determine number of WAVE Buffers -* and how many User Buffers we can put into each WAVE buffer. +* Determine how many User Buffers we can put into our CoreAudio stream buffer. +* Uses: +* past->past_FramesPerUserBuffer, etc. +* Sets: +* past->past_NumUserBuffers +* pahsc->pahsc_UserBuffersPerHostBuffer +* pahsc->pahsc_FramesPerHostBuffer */ -void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) +static void PaHost_CalcHostBufferSize( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = past->past_DeviceData; - unsigned int minNumBuffers; - int minFramesPerHostBuffer; - int maxFramesPerHostBuffer; - int minTotalFrames; - int userBuffersPerHostBuffer; - int framesPerHostBuffer; - int numHostBuffers; + unsigned int minNumUserBuffers; - /* Calculate minimum and maximum sizes based on timing and sample rate. */ - minFramesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); - minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; - DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); - - maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); - maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7; - DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer )); - - /* Determine number of user buffers based on minimum latency. */ - minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); - past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; + // Determine number of user buffers based on minimum latency. + minNumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); + // Compare to user requested number in user wants more than the minimum. + past->past_NumUserBuffers = ( minNumUserBuffers > past->past_NumUserBuffers ) ? + minNumUserBuffers : past->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); - minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; - - /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ - if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) - { - userBuffersPerHostBuffer = - (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / - past->past_FramesPerUserBuffer; - } - else - { - userBuffersPerHostBuffer = 1; - } - - - framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; - /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ - numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; - - /* Make sure we have anough WAVE buffers. */ - if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) - { - numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; - } - else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) && - ((int) past->past_FramesPerUserBuffer < (maxFramesPerHostBuffer/2) ) ) - { - /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ - while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) - { - userBuffersPerHostBuffer += 1; - framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; - numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; - /* If we have gone too far, back up one. */ - if( (framesPerHostBuffer > maxFramesPerHostBuffer) || - (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) ) - { - userBuffersPerHostBuffer -= 1; - framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; - numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; - break; - } - } - } - - pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; - pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; - pahsc->pahsc_NumHostBuffers = numHostBuffers; + // For CoreAudio, we only have one Host buffer, so... + pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers; + // Calculate size of CoreAudio buffer. + pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); - DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); - DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); } /*******************************************************************/ @@ -865,12 +912,20 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; - /* Figure out how user buffers fit into WAVE buffers. */ - // FIXME - just force for now + // If we are using both input and out, then they must be on the same CoreAudio device, + // until we implement a FIFO between two devices. + if( (past->past_OutputDeviceID != paNoDevice) && (past->past_InputDeviceID != paNoDevice) ) + { + AudioDeviceID inputID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; + AudioDeviceID outputID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; + if( inputID != outputID ) + { + ERR_RPT(("PortAudio: input and output must use same CoreAudio device!\n")); + return paInvalidDeviceId; + } + } - pahsc->pahsc_UserBuffersPerHostBuffer = 1; - pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer; - pahsc->pahsc_NumHostBuffers = 2; // FIXME - dunno?! + PaHost_CalcHostBufferSize( past ); { int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate); @@ -882,6 +937,7 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { result = PaHost_OpenOutputStream( past ); if( result < 0 ) goto error; + pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; } /* ------------------ INPUT */ @@ -889,6 +945,7 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { result = PaHost_OpenInputStream( past ); if( result < 0 ) goto error; + pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; } return result; @@ -901,118 +958,85 @@ error: /*************************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { - PaHostSoundControl *pahsc; - PaError result = paNoError; - OSStatus err = noErr; - - - pahsc = (PaHostSoundControl *) past->past_DeviceData; - - if( past->past_OutputDeviceID != paNoDevice ) - { - // Associate an IO proc with the device and pass a pointer to the audio data context - err = AudioDeviceAddIOProc(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc, past); - if (err != noErr) goto error; - - // start playing sound through the device - err = AudioDeviceStart(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); - if (err != noErr) goto error; - } - -error: - return result; + return 0; } /*************************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *past ) { - PaError result = paNoError; - PaHostSoundControl *pahsc; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - - if( past->past_InputDeviceID != paNoDevice ) - { - // FIXME - } - return result; + return 0; } /*************************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *past ) { + OSStatus err = noErr; PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; -#if PA_USE_TIMER_CALLBACK - int resolution; - int bufsPerTimerCallback; - int msecPerBuffer; -#endif /* PA_USE_TIMER_CALLBACK */ - past->past_StopSoon = 0; past->past_StopNow = 0; past->past_IsActive = 1; pahsc->pahsc_FramesPlayed = 0.0; pahsc->pahsc_LastPosition = 0; + // Associate an IO proc with the device and pass a pointer to the audio data context + err = AudioDeviceAddIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc, past); + if (err != noErr) goto error; + + // start playing sound through the device + err = AudioDeviceStart(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto error; + return result; + #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result ); #endif - return result; + +error: + return paHostError; // FIXME - save host error } /*************************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { - int timeOut; + OSStatus err = noErr; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; + (void) abort; /* 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; - - timeOut = PaHost_CalcTimeOut( past ); past->past_IsActive = 0; +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); +#endif + + // FIXME - we should ask proc to stop instead of stopping abruptly + err = AudioDeviceStop(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto Bail; + + err = AudioDeviceRemoveIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto Bail; + return paNoError; + +Bail: + return paHostError; // FIXME - save err } /*************************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; - (void) abort; - - // FIXME return paNoError; } /*************************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { - PaHostSoundControl *pahsc; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; - (void) abort; - -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); -#endif - - // FIXME if( pahsc->pahsc_OutputAudioDeviceID != ??? ) - { - OSStatus err = noErr; - - err = AudioDeviceStop(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); - if (err != noErr) goto Bail; - - err = AudioDeviceRemoveIOProc(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); - if (err != noErr) goto Bail; - } -Bail: return paNoError; } @@ -1028,9 +1052,6 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); #endif - /* Free data and device for output. */ - - /* Free data and device for input. */ free( pahsc ); past->past_DeviceData = NULL; @@ -1040,33 +1061,23 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) /************************************************************************* ** 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 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. +** on minimum latency. */ -#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") - -int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) +int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) { - int minLatencyMsec = 0; - double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; - int minBuffers; + int minUserBuffers; + int minFramesPerHostBuffer; - /* Let user determine minimal latency by setting environment variable. */ - { - minLatencyMsec = PA_MIN_LATENCY_MSEC; - } + // Calculate minimum and maximum sizes based on timing and sample rate. + minFramesPerHostBuffer = (int) (PA_MIN_LATENCY_MSEC * sampleRate / 1000.0); + // round up to nearest multiple of 8 + minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; + DBUG(("Pa_GetMinNumBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); - DBUG(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); - minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); - if( minBuffers < 2 ) minBuffers = 2; + minUserBuffers = (minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer; + if( minUserBuffers < 1 ) minUserBuffers = 1; - return minBuffers; + return minUserBuffers; } /************************************************************************* @@ -1076,29 +1087,18 @@ PaError PaHost_Term( void ) { int i; - if( sNumDevices > 0 ) + if( sDeviceInfos != NULL ) { - - if( sDevicePtrs != NULL ) + for( i=0; iname ); - free( (void*)sDevicePtrs[i]->sampleRates ); - free( sDevicePtrs[i] ); - } - } - - free( sDevicePtrs ); - sDevicePtrs = NULL; + if( sDeviceInfos[i].paInfo.name != NULL ) free( (char*)sDeviceInfos[i].paInfo.name ); + if( sDeviceInfos[i].paInfo.sampleRates != NULL ) free( (void*)sDeviceInfos[i].paInfo.sampleRates ); } - - sNumDevices = 0; + free( sDeviceInfos ); + sDeviceInfos = NULL; } + + sNumPaDevices = 0; return paNoError; } From 2c79fcd98b3f71dab525f2c9361a7f1ad5460df1 Mon Sep 17 00:00:00 2001 From: phil Date: Thu, 7 Feb 2002 18:15:27 +0000 Subject: [PATCH 014/814] notes on CoreAudio implementation --- pa_mac_core/notes.txt | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 pa_mac_core/notes.txt diff --git a/pa_mac_core/notes.txt b/pa_mac_core/notes.txt new file mode 100644 index 0000000..094a99c --- /dev/null +++ b/pa_mac_core/notes.txt @@ -0,0 +1,32 @@ +Notes on Core Audio Implementation of PortAudio + +by Phil Burk and Darren Gibbs + +Document last updated Feb 7, 2002 + +WHAT WORKS + +Output with very low latency, <10 msec. +Half duplex input or output. +Full duplex on the same CoreAudio device. +The paFLoat32 sample format. + +KNOWN BUGS OR LIMITATIONS + +We do not yet support simultaneous input and output on different +devices. Note that some CoreAudio devices like the Roland UH30 look +like one device but are actually two different CoreAudio devices. The +BuiltIn audio is typically one CoreAudio device. + +User formats other than the native paFloat32 are not yet supported. + +DEVICE MAPPING + +CoreAudio devices can support both input and output. But the sample +rates supported may be different. So we have map one or two PortAudio +device to each CoreAudio device depending on whether it supports +input, output or both. + +When we query devices, we first get a list of CoreAudio devices. Then +we scan the list and add a PortAudio device for each CoreAudio device +that supports input. Then we make a scan for output devices. From 5f6b6644dd953e221a8c163dbba92f11cd9462a2 Mon Sep 17 00:00:00 2001 From: dmazzoni Date: Mon, 18 Feb 2002 06:07:07 +0000 Subject: [PATCH 015/814] Added O_NONBLOCK to all open() calls, so that PortAudio does not hang if the device is in use by another program. --- pa_unix_oss/pa_unix_oss.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pa_unix_oss/pa_unix_oss.c b/pa_unix_oss/pa_unix_oss.c index 400de91..accd7c1 100644 --- a/pa_unix_oss/pa_unix_oss.c +++ b/pa_unix_oss/pa_unix_oss.c @@ -249,7 +249,7 @@ static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice * the correct order for OSS is: format, channels, sample rate */ - if ( (tempDevHandle = open(deviceName,O_WRONLY)) == -1 ) + if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 ) { DBUG(("Pa_QueryDevice: could not open %s\n", deviceName )); return paHostError; @@ -777,7 +777,7 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_RDWR\n", pad->pad_DeviceName )); pahsc->pahsc_OutputHandle = pahsc->pahsc_InputHandle = - open(pad->pad_DeviceName,O_RDWR); + 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 )); @@ -797,7 +797,7 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_WRONLY\n", pad->pad_DeviceName )); - pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY); + 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 )); @@ -815,7 +815,7 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { pad = Pa_GetInternalDevice( past->past_InputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_RDONLY\n", pad->pad_DeviceName )); - pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY); + 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 )); From 7e73ac614da85dcf1021260eb98abedf346f00ab Mon Sep 17 00:00:00 2001 From: dmazzoni Date: Tue, 19 Feb 2002 08:24:21 +0000 Subject: [PATCH 016/814] Fixed the nonblocking open - now it tries to open each device in nonblocking mode, and if that succeeds, closes it and opens it again in blocking mode - and added a new Pa_StreamTime implementation that uses SNDCTL_DSP_GET[I/O]PTR. --- pa_unix_oss/pa_unix_oss.c | 87 +++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 9 deletions(-) diff --git a/pa_unix_oss/pa_unix_oss.c b/pa_unix_oss/pa_unix_oss.c index accd7c1..9b7211f 100644 --- a/pa_unix_oss/pa_unix_oss.c +++ b/pa_unix_oss/pa_unix_oss.c @@ -58,9 +58,14 @@ Modfication History 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. + TODO -O- change Pa_StreamTime() to query device (patest_sync.c) O- put semaphore lock around shared data? O- handle native formats better O- handle stereo-only device better ??? @@ -159,6 +164,10 @@ typedef struct PaHostSoundControl /* 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; @@ -511,6 +520,8 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) PaError result = 0; PaHostSoundControl *pahsc; short bytes_read = 0; + count_info info; + int delta; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ @@ -526,12 +537,12 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) { - perror("sched_setscheduler"); - printf("PortAudio: only superuser can use real-time priority.\n"); + DBUG(("sched_setscheduler")); + DBUG(("PortAudio: only superuser can use real-time priority.\n")); } else { - printf("PortAudio: callback priority set to level %d!\n", schp.sched_priority); + DBUG(("PortAudio: callback priority set to level %d!\n", schp.sched_priority)); } } #endif @@ -578,6 +589,17 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) (void *)pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); } + + + /* 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; } past->past_IsActive = 0; @@ -776,8 +798,20 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { 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|O_NONBLOCK); + 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 )); @@ -797,6 +831,8 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { 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) { @@ -804,6 +840,15 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) 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 ); @@ -815,6 +860,8 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { 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) { @@ -822,6 +869,15 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) 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 ); @@ -1058,11 +1114,24 @@ PaError PaHost_StreamActive( internalPortAudioStream *past ) PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *past = (internalPortAudioStream *) stream; - /* FIXME - return actual frames played, not frames generated. - ** Need to query the output device somehow. - */ + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + PaTimestamp streamTime; + count_info info; + int delta; + if( past == NULL ) return paBadStreamPtr; - return past->past_FrameCount; + + 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)); + + } } /***********************************************************************/ From f51bc7d2c49751eae9c2b255281ab18b36db21a5 Mon Sep 17 00:00:00 2001 From: stephane Date: Tue, 19 Feb 2002 13:45:51 +0000 Subject: [PATCH 017/814] New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows --- pa_asio/pa_asio.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/pa_asio/pa_asio.cpp b/pa_asio/pa_asio.cpp index 7d98a19..70cd383 100644 --- a/pa_asio/pa_asio.cpp +++ b/pa_asio/pa_asio.cpp @@ -52,6 +52,7 @@ 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz + 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows: Stephane Letz TO DO : @@ -282,6 +283,16 @@ unsigned long get_sys_reference_time(); #endif +bool Pa_ASIO_loadAsioDriver(char *name) +{ + #ifdef WINDOWS + CoInitialize(0); + #endif + return loadAsioDriver(name); +} + + + // Utilities for alignement buffer size computation int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);} int PPCM (int a, int b) {return (a*b) / PGCD (a,b);} @@ -420,7 +431,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) names[i] = (char*)PaHost_AllocateFastMemory(32); /* MUST BE CHECKED : to force fragments loading on Mac */ - loadAsioDriver("dummy"); + Pa_ASIO_loadAsioDriver("dummy"); /* Get names of all available ASIO drivers */ asioDrivers->getDriverNames(names,PA_MAX_DEVICE_INFO); @@ -442,7 +453,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) #endif /* If the driver can be loaded : */ - if ( !loadAsioDriver(names[driver]) ) + if ( !Pa_ASIO_loadAsioDriver(names[driver]) ) { DBUG(("PaASIO_QueryDeviceInfo could not loadAsioDriver %s\n", names[driver])); } @@ -713,7 +724,7 @@ unsigned long get_sys_reference_time() // get the system reference time #if WINDOWS return timeGetTime(); - #elif MAC + #elif MAC static const double twoRaisedTo32 = 4294967296.; UnsignedWide ys; Microseconds(&ys); @@ -2402,7 +2413,7 @@ static PaError Pa_ASIO_loadDevice (long device) { PaDeviceInfo * dev = &(sDevices[device].pad_Info); - if (!loadAsioDriver((char *) dev->name)) return paHostError; + if (!Pa_ASIO_loadAsioDriver((char *) dev->name)) return paHostError; if (ASIOInit(&asioDriverInfo.pahsc_driverInfo) != ASE_OK) return paHostError; if (ASIOGetChannels(&asioDriverInfo.pahsc_NumInputChannels, &asioDriverInfo.pahsc_NumOutputChannels) != ASE_OK) return paHostError; if (ASIOGetBufferSize(&asioDriverInfo.pahsc_minSize, &asioDriverInfo.pahsc_maxSize, &asioDriverInfo.pahsc_preferredSize, &asioDriverInfo.pahsc_granularity) != ASE_OK) return paHostError; From 821ccde9108ffe46e13ca6aeefe66775b67f4fc6 Mon Sep 17 00:00:00 2001 From: phil Date: Tue, 19 Feb 2002 20:04:26 +0000 Subject: [PATCH 018/814] Added README and LICENSE so we can make nightly builds from CVS --- LICENSE.txt | 65 ++++++++++++++++++++++++++++++++++++++++++ README.txt | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 LICENSE.txt create mode 100644 README.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..105da3f --- /dev/null +++ b/LICENSE.txt @@ -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/ + * Implementation + * Copyright (c) 1999-2000 + * + * 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/README.txt b/README.txt new file mode 100644 index 0000000..d1e5d7d --- /dev/null +++ b/README.txt @@ -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 From c2a838e392c00fa399e4b22f567ce7f7cbf9b1ca Mon Sep 17 00:00:00 2001 From: phil Date: Tue, 19 Feb 2002 20:04:47 +0000 Subject: [PATCH 019/814] Used to prepare files for checkin on Windows --- fixfile.bat | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100755 fixfile.bat diff --git a/fixfile.bat b/fixfile.bat new file mode 100755 index 0000000..48f6fbc --- /dev/null +++ b/fixfile.bat @@ -0,0 +1,7 @@ +rem Use Astyle to fix style in a file +fixlines -p %1% +astyle --style=ansi -c -o --convert-tabs --indent-preprocessor %1% +del %1%.orig +@rem convert line terminators to Unix style LFs +fixlines -u %1% +del %1%.bak From 891814e2c1d6344a0e70d435fd4fcab29ae30159 Mon Sep 17 00:00:00 2001 From: phil Date: Wed, 20 Feb 2002 17:57:44 +0000 Subject: [PATCH 020/814] from Bill Eldridge --- Makefile.mingw | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Makefile.mingw diff --git a/Makefile.mingw b/Makefile.mingw new file mode 100644 index 0000000..2043a16 --- /dev/null +++ b/Makefile.mingw @@ -0,0 +1,57 @@ + +# Makefile for PortAudio on mingw (http://mingw.sourceforge.net) + +# Contributed by Bill Eldridge, bill@rfa.org, Radio Free Asia +# Copyright 2002/02/20, GPL + +# Uses a common mingw32 cross-compiler that defaults +# to everything in /usr/local/cross-tools + +# First edit your path with +# export PATH=/usr/local/cross-tools/bin:$PATH + +# Usage: make -f Makefile.mingw all +# or make -f Makefile.mingw sharedlib +# make -f Makefile.mingw tests +# +# Then copy executables & portaudio.dll to your Windows machine +# +# To make work with pa_win_ds, you'll have to substitue +# all the pa_win_wmme files with pa_win_ds files, no biggie. + +CC= i586-mingw32msvc-gcc +DLLTOOL= i586-mingw32msvc-dlltool +DLLWRAP= i586-mingw32msvc-dllwrap + +ARCH= pa_win_wmme + +TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) + +.c.o: + -$(CC) -c -I./pa_common $< -o $*.o + -$(CC) $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm + +all: sharedlib tests + +sharedlib: ./pa_common/pa_lib.c + $(CC) -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o + $(CC) -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o + $(CC) -shared -mthreads -o portaudio.dll pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm + $(DLLWRAP) --export-all --output-def=libportaudio.def --output-lib=libportaudio.a --dllname=portaudio.dll --drivername=i586-mingw32msvc-gcc pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm + $(CC) -shared -Wl,--enable-auto-image-base -o portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm + + +tests: $(TESTS:.c=.o) + +sine: + $(CC) -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o + $(CC) pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm + +clean: + -rm ./pa_tests/*.exe + -rm ./pa_tests/*.o + +nothing: + $(CC) pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm + + From ce52e6e9028632a24cf0061dace3e580c16bd5de Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 00:50:50 +0000 Subject: [PATCH 021/814] test tweak --- testcvs/changeme.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt index e71086d..2866c3b 100644 --- a/testcvs/changeme.txt +++ b/testcvs/changeme.txt @@ -3,4 +3,6 @@ Feel free to trash this file. Minor change. Another tweak. philburk tweak -stephane test \ No newline at end of file +stephane test +Phil changed this again on 2/21/02. Yawn... + From ecf3adbcdba7339d815a5525870f1cc437be7867 Mon Sep 17 00:00:00 2001 From: stephane Date: Fri, 22 Feb 2002 10:28:39 +0000 Subject: [PATCH 022/814] Explicit cast needed for compilation with Code Warrior 7 --- pa_mac_core/pa_mac_core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c index 3d38e2b..43fab18 100644 --- a/pa_mac_core/pa_mac_core.c +++ b/pa_mac_core/pa_mac_core.c @@ -41,6 +41,8 @@ fixed device queries for numChannels and sampleRates, one CoreAudio device now maps to separate input and output PaDevices, audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices). + 2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7 + TODO: O- conversion for other user formats besides paFloat32 @@ -278,7 +280,7 @@ static PaError Pa_QueryDevices( void ) ERR_RPT(("No Devices Available\n")); // make space for the devices we are about to get - sCoreDeviceIDs = malloc(outSize); + sCoreDeviceIDs = (AudioDeviceID *)malloc(outSize); // get an array of AudioDeviceIDs err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sCoreDeviceIDs); @@ -331,7 +333,7 @@ char *deviceNameFromID(AudioDeviceID deviceID, Boolean isInput ) err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, &outWritable); if (err == noErr) { - deviceName = malloc( outSize + 1); + deviceName = (char*)malloc( outSize + 1); if( deviceName ) { err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, deviceName); @@ -671,7 +673,7 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL gotOutput = 0; if( past->past_NumOutputChannels > 0 ) { - outBufPtr = outOutputData->mBuffers[0].mData, + outBufPtr = (char*)outOutputData->mBuffers[0].mData, gotOutput = 1; } @@ -680,7 +682,7 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL inBufPtr = NULL; if( past->past_NumInputChannels > 0 ) { - inBufPtr = inInputData->mBuffers[0].mData, + inBufPtr = (char*)inInputData->mBuffers[0].mData, gotInput = 1; } @@ -877,7 +879,7 @@ PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) */ static void PaHost_CalcHostBufferSize( internalPortAudioStream *past ) { - PaHostSoundControl *pahsc = past->past_DeviceData; + PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData; unsigned int minNumUserBuffers; // Determine number of user buffers based on minimum latency. From 390f19304218a12ec020004f614e84d7ddaa293d Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 21:40:48 +0000 Subject: [PATCH 023/814] Added WatchDog proc if audio running at high priority. Check error return from read() and write(). Check CPU endianness instead of assuming Little Endian. --- pa_unix_oss/pa_unix_oss.c | 312 +++++++++++++++++++++++++++++++------- 1 file changed, 258 insertions(+), 54 deletions(-) diff --git a/pa_unix_oss/pa_unix_oss.c b/pa_unix_oss/pa_unix_oss.c index 9b7211f..135a7c7 100644 --- a/pa_unix_oss/pa_unix_oss.c +++ b/pa_unix_oss/pa_unix_oss.c @@ -63,7 +63,9 @@ Modfication History 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. TODO O- put semaphore lock around shared data? @@ -117,10 +119,6 @@ PaDriverInfo; #include #include -/* Some versions of OSS do not define AFMT_S16_NE. Assume little endian. FIXME - check CPU*/ -#ifndef AFMT_S16_NE - #define AFMT_S16_NE AFMT_S16_LE -#endif #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) @@ -140,6 +138,9 @@ PaDriverInfo; #define DEVICE_NAME_BASE "/dev/audio" #endif +/* What is a pthread_t anyway? Here is a guess at a value that will never happen in real life. */ +#define INVALID_THREAD (-1) + #define MAX_CHARS_DEVNAME (32) #define MAX_SAMPLE_RATES (10) typedef struct internalPortAudioDevice @@ -156,7 +157,11 @@ typedef struct PaHostSoundControl { int pahsc_OutputHandle; int pahsc_InputHandle; - pthread_t pahsc_ThreadPID; + int pahsc_AudioPriority; /* priority of background audio thread */ + pthread_t pahsc_AudioThread; /* background audio thread */ + pthread_t pahsc_WatchDogThread; /* highest priority thread that protects system */ + pthread_t pahsc_CanaryThread; /* low priority thread that detects abuse by audio */ + struct timeval pahsc_CanaryTime; short *pahsc_NativeInputBuffer; short *pahsc_NativeOutputBuffer; unsigned int pahsc_BytesPerInputBuffer; /* native buffer size in bytes */ @@ -173,24 +178,21 @@ PaHostSoundControl; /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ -static int sDeviceIndex = 0; static internalPortAudioDevice *sDeviceList = NULL; static int sDefaultInputDeviceID = paNoDevice; static int sDefaultOutputDeviceID = paNoDevice; -static int sEnumerationError; static int sPaHostError = 0; /************************************************* Prototypes **********/ static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ); -static Pa_QueryDevices( void ); +static PaError Pa_QueryDevices( void ); static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ); static PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate ); /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { - struct itimerval itimer; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ @@ -233,6 +235,19 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) } /****************************************** END CPU UTILIZATION *******/ + +/********************************************************************* + * Some versions of OSS do not define AFMT_S16_NE. So check CPU. + * PowerPC is Big Endian. X86 is Little Endian. + */ +static 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; +} + /********************************************************************* * Try to open the named device. * If it opens, try to set various rates and formats and fill in @@ -241,7 +256,6 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ) { int result = paHostError; - int numBytes; int tempDevHandle; int numChannels, maxNumChannels; int format; @@ -272,7 +286,7 @@ static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice * goto error; } if( format & AFMT_U8 ) pad->pad_Info.nativeSampleFormats |= paUInt8; - if( format & AFMT_S16_NE ) pad->pad_Info.nativeSampleFormats |= paInt16; + if( format & Get_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. @@ -384,7 +398,6 @@ error: static PaError Pa_QueryDevices( void ) { internalPortAudioDevice *pad, *lastPad; - int numBytes; int go = 1; int numDevices = 0; PaError testResult; @@ -514,57 +527,243 @@ PaError PaHost_Init( void ) return Pa_MaybeQueryDevices(); } -/*******************************************************************************************/ -static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) +/******************************************************************************************* + * 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 ) { - PaError result = 0; - PaHostSoundControl *pahsc; - short bytes_read = 0; - count_info info; - int delta; + int result; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif -#if 1 + while( (result = usleep( WATCHDOG_INTERVAL_USEC )) == 0 ) + { + gettimeofday( &pahsc->pahsc_CanaryTime, NULL ); + } + + DBUG(("PaHost_CanaryProc: exiting.\n")); + +#ifdef GNUSTEP + GSUnregisterCurrentThread(); /* SB20010904 */ +#endif + + return result; +} + +/******************************************************************************************* + * Monitor audio thread and kill 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 ) +{ + PaError result = 0; + 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) { -#define SCHEDULER_POLICY SCHED_RR + 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( (result = usleep( WATCHDOG_INTERVAL_USEC )) == 0 ) + { + int delta; + struct timeval currentTime; + + gettimeofday( ¤tTime, NULL ); - struct sched_param schp; - memset(&schp, 0, sizeof(schp)); - schp.sched_priority = sched_get_priority_max(SCHEDULER_POLICY); - - if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) + /* If audio thread is not advancing, then kill it. */ + delta = currentTime.tv_sec - pahsc->pahsc_EntryTime.tv_sec; + DBUG(("PaHost_WatchDogProc: audio delta = %d\n", delta )); + if( delta > WATCHDOG_MAX_SECONDS ) { - DBUG(("sched_setscheduler")); - DBUG(("PortAudio: only superuser can use real-time priority.\n")); + ERR_RPT(("PaHost_WatchDogProc: killing hung audio thread!\n")); + goto killAudio; } - else + + /* If canary died, then kill audio and canary. */ + delta = currentTime.tv_sec - pahsc->pahsc_CanaryTime.tv_sec; + if( delta > WATCHDOG_MAX_SECONDS ) { - DBUG(("PortAudio: callback priority set to level %d!\n", schp.sched_priority)); + ERR_RPT(("PaHost_WatchDogProc: canary died! Killing runaway audio thread!\n")); + goto killAudio; } } + + DBUG(("PaHost_WatchDogProc: exiting.\n")); +#ifdef GNUSTEP + GSUnregisterCurrentThread(); /* SB20010904 */ #endif + return 0; + +killAudio: + pthread_kill( pahsc->pahsc_AudioThread, SIGKILL ); + pthread_cancel( pahsc->pahsc_CanaryThread ); + pthread_join( pahsc->pahsc_CanaryThread, NULL ); + pahsc->pahsc_CanaryThread = INVALID_THREAD; + pahsc->pahsc_WatchDogThread = INVALID_THREAD; + +#ifdef GNUSTEP + GSUnregisterCurrentThread(); /* SB20010904 */ +#endif + return 0; +} + +/*******************************************************************************************/ +static void PaHost_StopWatchDog( PaHostSoundControl *pahsc ) +{ +/* Cancel WatchDog thread if there is one. */ + if( pahsc->pahsc_WatchDogThread != INVALID_THREAD ) + { + pthread_cancel( pahsc->pahsc_WatchDogThread ); + pthread_join( pahsc->pahsc_WatchDogThread, NULL ); + pahsc->pahsc_WatchDogThread = INVALID_THREAD; + } +/* Cancel Canary thread if there is one. */ + if( pahsc->pahsc_CanaryThread != INVALID_THREAD ) + { + pthread_cancel( pahsc->pahsc_CanaryThread ); + pthread_join( pahsc->pahsc_CanaryThread, NULL ); + pahsc->pahsc_CanaryThread = INVALID_THREAD; + } +} + +/*******************************************************************************************/ +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. */ + hres = pthread_create(&(pahsc->pahsc_CanaryThread), + NULL /*pthread_attr_t * attr*/, + (void*)PaHost_CanaryProc, pahsc); + if( hres != 0 ) + { + pahsc->pahsc_CanaryThread = INVALID_THREAD; + result = paHostError; + sPaHostError = hres; + goto error; + } + + /* Launch a watchdog thread to prevent runaway audio thread. */ + hres = pthread_create(&(pahsc->pahsc_WatchDogThread), + NULL /*pthread_attr_t * attr*/, + (void*)PaHost_WatchDogProc, pahsc); + if( hres != 0 ) + { + pahsc->pahsc_WatchDogThread = INVALID_THREAD; + result = paHostError; + sPaHostError = hres; + goto error; + } + 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; + + /* 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) + { + PRINT(("PortAudio: only superuser can use real-time priority.\n")); + } + else + { + PRINT(("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; + count_info info; + int delta; 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) ) { - - DBUG(("go!\n")); /* Read data from device */ if(pahsc->pahsc_NativeInputBuffer) { + DBUG(("Pa_AudioThreadProc: attempt to read %d bytes\n", pahsc->pahsc_BytesPerInputBuffer)); bytes_read = read(pahsc->pahsc_InputHandle, (void *)pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer); - - DBUG(("bytes_read: %d\n", bytes_read)); + DBUG(("Pa_AudioThreadProc: bytes_read = %d\n", bytes_read)); + if( bytes_read < pahsc->pahsc_BytesPerInputBuffer ) + { + ERR_RPT(("PortAudio: read interrupted! Only got %d bytes.\n", bytes_read )); + break; + } } /* Convert 16 bit native data to user data and call user routine. */ @@ -585,12 +784,16 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) if( pahsc->pahsc_NativeOutputBuffer ) { - write(pahsc->pahsc_OutputHandle, + bytes_written = write(pahsc->pahsc_OutputHandle, (void *)pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); + if( bytes_written < pahsc->pahsc_BytesPerOutputBuffer ) + { + ERR_RPT(("PortAudio: write interrupted! Only got %d bytes.\n", bytes_written )); + break; + } } - /* Update current stream time (using a double so that we don't wrap around like info.bytes does) */ if( pahsc->pahsc_NativeOutputBuffer ) @@ -603,12 +806,15 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) } past->past_IsActive = 0; - DBUG(("leaving thread.\n")); + PaHost_StopWatchDog( pahsc ); + + DBUG(("leaving audio thread.\n")); +error: #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif - return 0; + return result; } /*******************************************************************************************/ @@ -619,13 +825,13 @@ static PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleR /* Set format, channels, and rate in this order to keep OSS happy. */ /* Set data format. FIXME - handle more native formats. */ - tmp = AFMT_S16_NE; + tmp = Get_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) + if( tmp != Get_AFMT_S16_NE() ) { ERR_RPT(("Pa_SetupDeviceFormat: HW does not support AFMT_S16_NE\n" )); return paHostError; @@ -674,7 +880,7 @@ static int CalcHigherLogTwo( int n ) static void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, int channelsPerFrame ) { int tmp; - int numFrames , bufferSize, powerOfTwo; + int bufferSize, powerOfTwo; /* Increase size of buffers and reduce number of buffers to reduce latency inside driver. */ while( numBuffers > 8 ) @@ -684,7 +890,7 @@ static void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, i } /* calculate size of buffers in bytes */ - bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME */ + bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME - other sizes? */ /* Calculate next largest power of two */ powerOfTwo = CalcHigherLogTwo( bufferSize ); @@ -737,9 +943,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { PaError result = paNoError; PaHostSoundControl *pahsc; - int tmp; - int flags; - int numBytes, maxChannels; unsigned int minNumBuffers; internalPortAudioDevice *pad; DBUG(("PaHost_OpenStream() called.\n" )); @@ -756,6 +959,8 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; /* No device currently opened. */ pahsc->pahsc_InputHandle = BAD_DEVICE_ID; + pahsc->pahsc_AudioThread = INVALID_THREAD; + pahsc->pahsc_WatchDogThread = INVALID_THREAD; /* Allocate native buffers. */ pahsc->pahsc_BytesPerInputBuffer = past->past_FramesPerUserBuffer * @@ -925,13 +1130,14 @@ PaError PaHost_StartEngine( internalPortAudioStream *past ) * - 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_ThreadPID), + hres = pthread_create(&(pahsc->pahsc_AudioThread), NULL /*pthread_attr_t * attr*/, (void*)Pa_AudioThreadProc, past); if( hres != 0 ) { result = paHostError; sPaHostError = hres; + pahsc->pahsc_AudioThread = INVALID_THREAD; goto error; } @@ -943,7 +1149,6 @@ error: PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { int hres; - long timeOut; PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; @@ -955,12 +1160,12 @@ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) if( abort ) past->past_StopNow = 1; /* Join thread to recover memory resources. */ - if( pahsc->pahsc_ThreadPID != -1 ) + if( pahsc->pahsc_AudioThread != INVALID_THREAD ) { /* This check is needed for GNUSTEP - SB20010904 */ - if ( !pthread_equal( pahsc->pahsc_ThreadPID, pthread_self() ) ) + if ( !pthread_equal( pahsc->pahsc_AudioThread, pthread_self() ) ) { - hres = pthread_join( pahsc->pahsc_ThreadPID, NULL ); + hres = pthread_join( pahsc->pahsc_AudioThread, NULL ); } else { @@ -973,7 +1178,7 @@ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) result = paHostError; sPaHostError = hres; } - pahsc->pahsc_ThreadPID = -1; + pahsc->pahsc_AudioThread = INVALID_THREAD; } past->past_IsActive = 0; @@ -1085,7 +1290,7 @@ void Pa_Sleep( long msec ) */ void *PaHost_AllocateFastMemory( long numBytes ) { - void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */ + void *addr = malloc( numBytes ); /* FIXME - do we need physical, wired, non-virtual memory? */ if( addr != NULL ) memset( addr, 0, numBytes ); return addr; } @@ -1115,7 +1320,6 @@ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *past = (internalPortAudioStream *) stream; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - PaTimestamp streamTime; count_info info; int delta; From ac04f6d6109307679b8c1fd083a70ce0fc49853c Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 21:44:19 +0000 Subject: [PATCH 024/814] Add watch dog that simulates hung audio thread. --- pa_tests/patest_hang.c | 151 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 pa_tests/patest_hang.c diff --git a/pa_tests/patest_hang.c b/pa_tests/patest_hang.c new file mode 100644 index 0000000..6d533da --- /dev/null +++ b/pa_tests/patest_hang.c @@ -0,0 +1,151 @@ +/* + * $Id$ + * Play a sine then hang audio callback to test watchdog. + * + * Authors: + * Ross Bencina + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" + + +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (1024) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +typedef struct paTestData +{ + int sleepFor; + double phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + double phaseInc = 0.02; + double phase = data->phase; + + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( i=0; i TWOPI ) phase -= TWOPI; + /* This is not a very efficient way to calc sines. */ + *out++ = (float) sin( phase ); /* mono */ + } + + if( data->sleepFor > 0 ) + { + Pa_Sleep( data->sleepFor ); + } + + data->phase = phase; + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + int i; + paTestData data = {0}; + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", + SAMPLE_RATE, FRAMES_PER_BUFFER ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + err = Pa_OpenStream( + &stream, + paNoDevice,/* default input device */ + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + Pa_GetDefaultOutputDeviceID(), /* default output device */ + 1, /* mono output */ + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + +/* Gradually increase sleep time. */ + for( i=0; i<10000; i+= 1000 ) + { + printf("Sleep for %d milliseconds in audio callback.\n", i ); + data.sleepFor = i; + Pa_Sleep( ((i<1000) ? 1000 : i) ); + } + + printf("Suffer for 10 seconds.\n"); + Pa_Sleep( 10000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} From ca0feff1b0bb4b7fc94a09016ca9eef4374e3a0e Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 21:45:10 +0000 Subject: [PATCH 025/814] Add watchdog test that causes user thread starvation by overusing CPU. --- pa_tests/patest_toomanysines.c | 169 +++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 pa_tests/patest_toomanysines.c diff --git a/pa_tests/patest_toomanysines.c b/pa_tests/patest_toomanysines.c new file mode 100644 index 0000000..d2c7020 --- /dev/null +++ b/pa_tests/patest_toomanysines.c @@ -0,0 +1,169 @@ +/* + * $Id$ + * Play more sine waves than we can handle in real time as a stress test, + * + * Authors: + * Ross Bencina + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" + +#define MAX_SINES (500) +#define MAX_LOAD (1.2) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +typedef struct paTestData +{ + int numSines; + double phases[MAX_SINES]; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int j; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( i=0; inumSines; j++ ) + { + /* Advance phase of next oscillator. */ + phase = data->phases[j]; + phase += phaseInc; + if( phase > TWOPI ) phase -= TWOPI; + + phaseInc *= 1.02; + if( phaseInc > 0.5 ) phaseInc *= 0.5; + + /* This is not a very efficient way to calc sines. */ + output += (float) sin( phase ); + data->phases[j] = phase; + } + + + *out++ = (float) (output / data->numSines); + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + int numStress; + paTestData data = {0}; + double load; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d. MAX_LOAD = %f\n", + SAMPLE_RATE, FRAMES_PER_BUFFER, MAX_LOAD ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + err = Pa_OpenStream( + &stream, + paNoDevice,/* default input device */ + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + Pa_GetDefaultOutputDeviceID(), /* default output device */ + 1, /* mono output */ + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + /* Determine number of sines required to get to 50% */ + do + { + data.numSines++; + Pa_Sleep( 200 ); + + load = Pa_GetCPULoad( stream ); + printf("numSines = %d, CPU load = %f\n", data.numSines, load ); + } + while( load < 0.5 ); + + /* Calculate target stress value then ramp up to that level*/ + numStress = (int) (2.0 * data.numSines * MAX_LOAD ); + for( ; data.numSines < numStress; data.numSines++ ) + { + Pa_Sleep( 200 ); + load = Pa_GetCPULoad( stream ); + printf("STRESSING: numSines = %d, CPU load = %f\n", data.numSines, load ); + } + + printf("Suffer for 10 seconds.\n"); + Pa_Sleep( 10000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} From 98aa447859b153d852bbffa30769531f2db5dcc2 Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 21:45:45 +0000 Subject: [PATCH 026/814] Cleaned up some comments. --- pa_tests/patest_wire.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pa_tests/patest_wire.c b/pa_tests/patest_wire.c index 59a33a3..c24d225 100644 --- a/pa_tests/patest_wire.c +++ b/pa_tests/patest_wire.c @@ -69,7 +69,6 @@ static int wireCallback( void *inputBuffer, void *outputBuffer, SAMPLE *out = (SAMPLE*)outputBuffer; SAMPLE *in = (SAMPLE*)inputBuffer; unsigned int i; - int finished = 0; (void) outTime; /* This may get called with NULL inputBuffer during initial setup. */ @@ -98,11 +97,12 @@ int main(void) { PortAudioStream *stream; PaError err; - int numDevices = Pa_CountDevices(); + err = Pa_Initialize(); if( err != paNoError ) goto error; - printf("PortAudio Test: input device = %d\n", Pa_GetDefaultInputDeviceID() ); - printf("PortAudio Test: output device = %d\n", Pa_GetDefaultOutputDeviceID() ); + + printf("PortAudio Test: input device ID = %d\n", Pa_GetDefaultInputDeviceID() ); + printf("PortAudio Test: output device ID = %d\n", Pa_GetDefaultOutputDeviceID() ); err = Pa_OpenStream( &stream, Pa_GetDefaultInputDeviceID(), /* default output device */ @@ -120,14 +120,19 @@ int main(void) wireCallback, NULL ); /* no data */ if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); if( err != paNoError ) goto error; + printf("Full duplex sound test in progress.\n"); - printf("Hit ENTER to exit test.\n"); + printf("Hit ENTER to exit test.\n"); fflush(stdout); getchar(); + + printf("Closing stream.\n"); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); + printf("Full duplex sound test complete.\n"); fflush(stdout); return 0; error: From 83bb63cf86dc9f3ff2ed0a11e5ab769909ff99be Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 21:46:18 +0000 Subject: [PATCH 027/814] Fix messages, init toggle variable. --- pa_tests/patest_leftright.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pa_tests/patest_leftright.c b/pa_tests/patest_leftright.c index 7e19b17..d718aef 100644 --- a/pa_tests/patest_leftright.c +++ b/pa_tests/patest_leftright.c @@ -98,6 +98,7 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, return finished; } + /*******************************************************************/ int main(void); int main(void) @@ -107,17 +108,21 @@ int main(void) paTestData data; int i; int timeout; - printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + printf("Play different tone sine waves that alternate between left and right channel.\n"); + printf("The low tone should be on the left channel.\n"); + /* initialise sinusoidal wavetable */ for( i=0; i 0 ) { - printf("Countdown = %d, Toggle = %d\n", data.countDown, data.toggle ); - fflush( stdout ); - Pa_Sleep( 1000/4 ); + Pa_Sleep( 300 ); timeout -= 1; } From 024eb0bf88373694a0a0f82e3e388dee43fb243a Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 21:59:11 +0000 Subject: [PATCH 028/814] Added bug note about unsupported sample rates. --- pa_mac_core/notes.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pa_mac_core/notes.txt b/pa_mac_core/notes.txt index 094a99c..7e8835b 100644 --- a/pa_mac_core/notes.txt +++ b/pa_mac_core/notes.txt @@ -20,6 +20,9 @@ BuiltIn audio is typically one CoreAudio device. User formats other than the native paFloat32 are not yet supported. +If you request a non-supported sample rate then you just get a +supported rate with no error messages. + DEVICE MAPPING CoreAudio devices can support both input and output. But the sample From 1914d1c217aadaa294b473e11eb40c4a47525da9 Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 22:01:35 +0000 Subject: [PATCH 029/814] Fix typo in comment: s/bug/big/ --- pa_tests/patest_latency.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pa_tests/patest_latency.c b/pa_tests/patest_latency.c index a081b29..3096c8c 100644 --- a/pa_tests/patest_latency.c +++ b/pa_tests/patest_latency.c @@ -1,6 +1,6 @@ /* * $Id$ - * Hear the latency caused by bug buffers. + * Hear the latency caused by big buffers. * Play a sine wave and change frequency based on letter input. * * Author: Phil Burk , and Darren Gibbs From 85f1b75729e6ffbcd2713646e4aeb27db604c4c2 Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 22:05:01 +0000 Subject: [PATCH 030/814] Do all memory allocations through a tracker so we can debug memory leaks. --- pa_win_wmme/pa_win_wmme.c | 88 ++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/pa_win_wmme/pa_win_wmme.c b/pa_win_wmme/pa_win_wmme.c index 2b3dea2..13f6d83 100644 --- a/pa_win_wmme/pa_win_wmme.c +++ b/pa_win_wmme/pa_win_wmme.c @@ -67,6 +67,8 @@ #include "pa_trace.h" /************************************************* Constants ********/ +#define PA_TRACK_MEMORY (0) + #define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ #define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ /* Switches for debugging. */ @@ -159,6 +161,8 @@ static int sDefaultOutputDeviceID = paNoDevice; static int sPaHostError = 0; static const char sMapperSuffixInput[] = " - Input"; static const char sMapperSuffixOutput[] = " - Output"; +static int sNumAllocations = 0; + /************************************************* Macros ********/ /* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ #define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) @@ -170,6 +174,9 @@ PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc ); static PaError PaHost_BackgroundManager( internalPortAudioStream *past ); +static void *PaHost_AllocateTrackedMemory( long numBytes ); +static void PaHost_FreeTrackedMemory( void *addr ); + /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { @@ -212,7 +219,7 @@ static PaError Pa_QueryDevices( void ) /* PLB20010402 - was allocating too much memory. */ /* numBytes = sNumDevices * sizeof(PaDeviceInfo); // PLB20010402 */ numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */ - sDevicePtrs = (PaDeviceInfo **) GlobalAlloc( GPTR, numBytes ); /* MEM */ + sDevicePtrs = (PaDeviceInfo **) PaHost_AllocateTrackedMemory( numBytes ); /* MEM */ if( sDevicePtrs == NULL ) return paInsufficientMemory; return paNoError; } @@ -251,13 +258,13 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { return sDevicePtrs[ id ]; } - deviceInfo = (PaDeviceInfo *)GlobalAlloc( GPTR, sizeof(PaDeviceInfo) ); /* MEM */ + deviceInfo = (PaDeviceInfo *)PaHost_AllocateTrackedMemory( sizeof(PaDeviceInfo) ); /* MEM */ if( deviceInfo == NULL ) return NULL; deviceInfo->structVersion = 1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->numSampleRates = 0; - sampleRates = (double*)GlobalAlloc( GPTR, MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */ + sampleRates = (double*)PaHost_AllocateTrackedMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */ deviceInfo->sampleRates = sampleRates; deviceInfo->nativeSampleFormats = paInt16; /* should query for higher bit depths below */ if( id < sNumInputDevices ) @@ -271,13 +278,13 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) /* Append I/O suffix to WAVE_MAPPER device. */ if( inputMmID == WAVE_MAPPER ) { - s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */ + s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */ strcpy( s, wic.szPname ); strcat( s, sMapperSuffixInput ); } else { - s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 ); /* MEM */ + s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 ); /* MEM */ strcpy( s, wic.szPname ); } deviceInfo->name = s; @@ -328,13 +335,13 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) /* Append I/O suffix to WAVE_MAPPER device. */ if( outputMmID == WAVE_MAPPER ) { - s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */ + s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */ strcpy( s, woc.szPname ); strcat( s, sMapperSuffixOutput ); } else { - s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 ); /* MEM */ + s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 ); /* MEM */ strcpy( s, woc.szPname ); } deviceInfo->name = s; @@ -377,8 +384,8 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) sDevicePtrs[ id ] = deviceInfo; return deviceInfo; error: - GlobalFree( sampleRates ); /* MEM */ - GlobalFree( deviceInfo ); /* MEM */ + PaHost_FreeTrackedMemory( sampleRates ); /* MEM */ + PaHost_FreeTrackedMemory( deviceInfo ); /* MEM */ return NULL; } @@ -448,6 +455,11 @@ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) */ PaError PaHost_Init( void ) { + +#if PA_TRACK_MEMORY + PRINT(("PaHost_Init: sNumAllocations = %d\n", sNumAllocations )); +#endif + #if PA_SIMULATE_UNDERFLOW PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); #endif @@ -793,7 +805,7 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) goto error; } /* Allocate an array to hold the buffer pointers. */ - pahsc->pahsc_InputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ + pahsc->pahsc_InputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ if( pahsc->pahsc_InputBuffers == NULL ) { result = paInsufficientMemory; @@ -802,7 +814,7 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) /* Allocate each buffer. */ for( i=0; ipahsc_NumHostBuffers; i++ ) { - pahsc->pahsc_InputBuffers[i].lpData = (char *)GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostInputBuffer ); /* MEM */ + pahsc->pahsc_InputBuffers[i].lpData = (char *)PaHost_AllocateTrackedMemory( pahsc->pahsc_BytesPerHostInputBuffer ); /* MEM */ if( pahsc->pahsc_InputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; @@ -878,7 +890,7 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) goto error; } /* Allocate an array to hold the buffer pointers. */ - pahsc->pahsc_OutputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ + pahsc->pahsc_OutputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ if( pahsc->pahsc_OutputBuffers == NULL ) { result = paInsufficientMemory; @@ -887,7 +899,7 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) /* Allocate each buffer. */ for( i=0; ipahsc_NumHostBuffers; i++ ) { - pahsc->pahsc_OutputBuffers[i].lpData = (char *) GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostOutputBuffer ); /* MEM */ + pahsc->pahsc_OutputBuffers[i].lpData = (char *) PaHost_AllocateTrackedMemory( pahsc->pahsc_BytesPerHostOutputBuffer ); /* MEM */ if( pahsc->pahsc_OutputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; @@ -1317,9 +1329,9 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) for( i=0; ipahsc_NumHostBuffers; i++ ) { waveOutUnprepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) ); - GlobalFree( pahsc->pahsc_OutputBuffers[i].lpData ); /* MEM */ + PaHost_FreeTrackedMemory( pahsc->pahsc_OutputBuffers[i].lpData ); /* MEM */ } - GlobalFree( pahsc->pahsc_OutputBuffers ); /* MEM */ + PaHost_FreeTrackedMemory( pahsc->pahsc_OutputBuffers ); /* MEM */ } waveOutClose( pahsc->pahsc_HWaveOut ); } @@ -1331,9 +1343,9 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) for( i=0; ipahsc_NumHostBuffers; i++ ) { waveInUnprepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) ); - GlobalFree( pahsc->pahsc_InputBuffers[i].lpData ); /* MEM */ + PaHost_FreeTrackedMemory( pahsc->pahsc_InputBuffers[i].lpData ); /* MEM */ } - GlobalFree( pahsc->pahsc_InputBuffers ); /* MEM */ + PaHost_FreeTrackedMemory( pahsc->pahsc_InputBuffers ); /* MEM */ } waveInClose( pahsc->pahsc_HWaveIn ); } @@ -1405,16 +1417,21 @@ PaError PaHost_Term( void ) { if( sDevicePtrs[i] != NULL ) { - GlobalFree( (char*)sDevicePtrs[i]->name ); /* MEM */ - GlobalFree( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */ - GlobalFree( sDevicePtrs[i] ); /* MEM */ + PaHost_FreeTrackedMemory( (char*)sDevicePtrs[i]->name ); /* MEM */ + PaHost_FreeTrackedMemory( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */ + PaHost_FreeTrackedMemory( sDevicePtrs[i] ); /* MEM */ } } - GlobalFree( sDevicePtrs ); /* MEM */ + PaHost_FreeTrackedMemory( sDevicePtrs ); /* MEM */ sDevicePtrs = NULL; } sNumDevices = 0; } + +#if PA_TRACK_MEMORY + PRINT(("PaHost_Term: sNumAllocations = %d\n", sNumAllocations )); +#endif + return paNoError; } /*************************************************************************/ @@ -1431,8 +1448,7 @@ void Pa_Sleep( long msec ) */ void *PaHost_AllocateFastMemory( long numBytes ) { - void *addr = GlobalAlloc( GPTR, numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */ - return addr; + return PaHost_AllocateTrackedMemory( numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */ } /************************************************************************* * Free memory that could be accessed in real-time. @@ -1440,8 +1456,32 @@ void *PaHost_AllocateFastMemory( long numBytes ) */ void PaHost_FreeFastMemory( void *addr, long numBytes ) { - if( addr != NULL ) GlobalFree( addr ); /* MEM */ + PaHost_FreeTrackedMemory( addr ); /* MEM */ } + +/************************************************************************* + * Track memory allocations to avoid leaks. + */ +static void *PaHost_AllocateTrackedMemory( long numBytes ) +{ + void *addr = GlobalAlloc( GPTR, numBytes ); /* MEM */ +#if PA_TRACK_MEMORY + if( addr != NULL ) sNumAllocations += 1; +#endif + return addr; +} + +static void PaHost_FreeTrackedMemory( void *addr ) +{ + if( addr != NULL ) + { + GlobalFree( addr ); /* MEM */ +#if PA_TRACK_MEMORY + sNumAllocations -= 1; +#endif + } +} + /***********************************************************************/ PaError PaHost_StreamActive( internalPortAudioStream *past ) { From 1dbcc33442a9fa5b70ea8f4e962e47b83edced91 Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 22:06:23 +0000 Subject: [PATCH 031/814] Change from 22050 to 44100 Hz Process audio in a block for better efficiency. --- pablio/test_rw.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pablio/test_rw.c b/pablio/test_rw.c index 245e19c..7f7e886 100644 --- a/pablio/test_rw.c +++ b/pablio/test_rw.c @@ -44,9 +44,10 @@ ** full duplex audio (simultaneous record and playback). ** And some only support full duplex at lower sample rates. */ -#define SAMPLE_RATE (22050) -#define NUM_SECONDS (15) -#define SAMPLES_PER_FRAME (2) +#define SAMPLE_RATE (44100) +#define NUM_SECONDS (5) +#define SAMPLES_PER_FRAME (2) +#define FRAMES_PER_BLOCK (64) /* Select whether we will use floats or shorts. */ #if 1 @@ -62,7 +63,7 @@ int main(void); int main(void) { int i; - SAMPLE samples[SAMPLES_PER_FRAME]; + SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK]; PaError err; PABLIO_Stream *aStream; @@ -75,13 +76,12 @@ int main(void) if( err != paNoError ) goto error; /* Process samples in the foreground. */ - for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ ) + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) { - /* Read one frame of data into sample array from audio input. */ - ReadAudioStream( aStream, samples, 1 ); - /* Write that same frame of data to output. */ - /* samples[1] = (i&256) * (1.0f/256.0f); /* sawtooth */ - WriteAudioStream( aStream, samples, 1 ); + /* Read one block of data into sample array from audio input. */ + ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK ); + /* Write that same block of data to output. */ + WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK ); } CloseAudioStream( aStream ); From 446407f2d6f2f013359baec62ab484bbdc4fc798 Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 22:18:14 +0000 Subject: [PATCH 032/814] Only use Get_AFMT_S16_NE is not defined. --- pa_unix_oss/pa_unix_oss.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pa_unix_oss/pa_unix_oss.c b/pa_unix_oss/pa_unix_oss.c index 135a7c7..20ab707 100644 --- a/pa_unix_oss/pa_unix_oss.c +++ b/pa_unix_oss/pa_unix_oss.c @@ -235,7 +235,8 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) } /****************************************** END CPU UTILIZATION *******/ - +#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. @@ -247,6 +248,7 @@ static int Get_AFMT_S16_NE( void ) int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */ return isLittle ? AFMT_S16_LE : AFMT_S16_BE; } +#endif /********************************************************************* * Try to open the named device. @@ -286,7 +288,7 @@ static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice * goto error; } if( format & AFMT_U8 ) pad->pad_Info.nativeSampleFormats |= paUInt8; - if( format & Get_AFMT_S16_NE() ) pad->pad_Info.nativeSampleFormats |= paInt16; + 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. @@ -825,13 +827,13 @@ static PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleR /* Set format, channels, and rate in this order to keep OSS happy. */ /* Set data format. FIXME - handle more native formats. */ - tmp = Get_AFMT_S16_NE(); + 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 != Get_AFMT_S16_NE() ) + if( tmp != AFMT_S16_NE ) { ERR_RPT(("Pa_SetupDeviceFormat: HW does not support AFMT_S16_NE\n" )); return paHostError; From 8d8702a9fee7dbcb31523ec6b383bd632966bdeb Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 22 Feb 2002 22:18:30 +0000 Subject: [PATCH 033/814] Add more tests. --- pa_unix_oss/Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pa_unix_oss/Makefile b/pa_unix_oss/Makefile index 9f118e1..f501563 100644 --- a/pa_unix_oss/Makefile +++ b/pa_unix_oss/Makefile @@ -3,15 +3,18 @@ LIBS = -lm -lpthread CDEFINES = -I../pa_common -CFLAGS = -g +CFLAGS = -g -Wall PASRC = ../pa_common/pa_lib.c pa_unix_oss.c PAINC = ../pa_common/portaudio.h # Tests that work. TESTC = $(PASRC) ../pa_tests/patest_sine.c +#TESTC = $(PASRC) ../pa_tests/patest_longsine.c #TESTC = $(PASRC) ../pa_tests/patest_sine_time.c #TESTC = $(PASRC) ../pa_tests/patest_maxsines.c -#TESTC = $(PASRC) ../pa_tests/patest_stop.c +#TESTC = $(PASRC) ../pa_tests/patest_toomanysines.c +#TESTC = $(PASRC) ../pa_tests/patest_underflow.c +#TESTC = $(PASRC) ../pa_tests/patest_hang.c #TESTC = $(PASRC) ../pa_tests/patest_sync.c #TESTC = $(PASRC) ../pa_tests/patest_pink.c #TESTC = $(PASRC) ../pa_tests/patest_leftright.c @@ -25,6 +28,8 @@ TESTC = $(PASRC) ../pa_tests/patest_sine.c #TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Tests that do not yet work. +# OSS doesn't let us make obscenely huge buffers so the test will seem to fail. But its OK. +#TESTC = $(PASRC) ../pa_tests/patest_stop.c TESTH = $(PAINC) From fe732b4d7753569647858069a99bac39ced7620b Mon Sep 17 00:00:00 2001 From: philburk Date: Mon, 25 Feb 2002 17:19:24 +0000 Subject: [PATCH 034/814] Added more printfs and sped up test. --- pa_tests/patest_toomanysines.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pa_tests/patest_toomanysines.c b/pa_tests/patest_toomanysines.c index d2c7020..f78df8c 100644 --- a/pa_tests/patest_toomanysines.c +++ b/pa_tests/patest_toomanysines.c @@ -134,7 +134,7 @@ int main(void) do { data.numSines++; - Pa_Sleep( 200 ); + Pa_Sleep( 100 ); load = Pa_GetCPULoad( stream ); printf("numSines = %d, CPU load = %f\n", data.numSines, load ); @@ -150,13 +150,16 @@ int main(void) printf("STRESSING: numSines = %d, CPU load = %f\n", data.numSines, load ); } - printf("Suffer for 10 seconds.\n"); - Pa_Sleep( 10000 ); + printf("Suffer for 5 seconds.\n"); + Pa_Sleep( 5000 ); + printf("Stop stream.\n"); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; + Pa_Terminate(); printf("Test finished.\n"); return err; From f4158d9008baaf7532af7cddd2406eb36cece13f Mon Sep 17 00:00:00 2001 From: philburk Date: Mon, 25 Feb 2002 17:20:39 +0000 Subject: [PATCH 035/814] If watchdog detects canary getting starved, then just lower audio thread priority instead of killing it. If audio completely hung then still kill it. --- pa_unix_oss/pa_unix_oss.c | 72 +++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/pa_unix_oss/pa_unix_oss.c b/pa_unix_oss/pa_unix_oss.c index 20ab707..97f513d 100644 --- a/pa_unix_oss/pa_unix_oss.c +++ b/pa_unix_oss/pa_unix_oss.c @@ -98,17 +98,14 @@ PaDriverInfo; #include #include #include -#include "portaudio.h" -#include "pa_host.h" -#include "pa_trace.h" - #include #include #include #include #include -#include -#include +#include +#include +#include #ifdef __linux__ #include @@ -116,9 +113,9 @@ PaDriverInfo; #include /* JH20010905 */ #endif -#include -#include - +#include "portaudio.h" +#include "pa_host.h" +#include "pa_trace.h" #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) @@ -159,9 +156,12 @@ typedef struct PaHostSoundControl int pahsc_InputHandle; int pahsc_AudioPriority; /* priority of background audio thread */ pthread_t pahsc_AudioThread; /* background audio thread */ + pid_t pahsc_AudioThreadPID; /* background audio thread */ pthread_t pahsc_WatchDogThread; /* highest priority thread that protects system */ + int pahsc_WatchDogRun; /* Ask WatchDog to stop. */ pthread_t pahsc_CanaryThread; /* low priority thread that detects abuse by audio */ 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 */ @@ -542,13 +542,13 @@ PaError PaHost_Init( void ) static int PaHost_CanaryProc( PaHostSoundControl *pahsc ) { - int result; + int result = 0; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif - while( (result = usleep( WATCHDOG_INTERVAL_USEC )) == 0 ) + while( pahsc->pahsc_CanaryRun && ((result = usleep( WATCHDOG_INTERVAL_USEC )) == 0) ) { gettimeofday( &pahsc->pahsc_CanaryTime, NULL ); } @@ -563,7 +563,7 @@ static int PaHost_CanaryProc( PaHostSoundControl *pahsc ) } /******************************************************************************************* - * Monitor audio thread and kill it if it hogs the CPU. + * 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 @@ -594,19 +594,18 @@ static PaError PaHost_WatchDogProc( PaHostSoundControl *pahsc ) /* Compare watchdog time with audio and canary thread times. */ /* Sleep for a while or until thread cancelled. */ - while( (result = usleep( WATCHDOG_INTERVAL_USEC )) == 0 ) + while( pahsc->pahsc_WatchDogRun && ((result = usleep( WATCHDOG_INTERVAL_USEC )) == 0) ) { int delta; struct timeval currentTime; gettimeofday( ¤tTime, NULL ); - /* If audio thread is not advancing, then kill it. */ + /* If audio thread is not advancing, then lower its priority. */ delta = currentTime.tv_sec - pahsc->pahsc_EntryTime.tv_sec; DBUG(("PaHost_WatchDogProc: audio delta = %d\n", delta )); if( delta > WATCHDOG_MAX_SECONDS ) { - ERR_RPT(("PaHost_WatchDogProc: killing hung audio thread!\n")); goto killAudio; } @@ -614,8 +613,8 @@ static PaError PaHost_WatchDogProc( PaHostSoundControl *pahsc ) delta = currentTime.tv_sec - pahsc->pahsc_CanaryTime.tv_sec; if( delta > WATCHDOG_MAX_SECONDS ) { - ERR_RPT(("PaHost_WatchDogProc: canary died! Killing runaway audio thread!\n")); - goto killAudio; + ERR_RPT(("PaHost_WatchDogProc: canary died!\n")); + goto lowerAudio; } } @@ -625,12 +624,33 @@ static PaError PaHost_WatchDogProc( PaHostSoundControl *pahsc ) #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_CanaryThread = INVALID_THREAD; - pahsc->pahsc_WatchDogThread = INVALID_THREAD; #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ @@ -644,6 +664,8 @@ static void PaHost_StopWatchDog( PaHostSoundControl *pahsc ) /* Cancel WatchDog thread if there is one. */ if( pahsc->pahsc_WatchDogThread != INVALID_THREAD ) { + pahsc->pahsc_WatchDogRun = 0; + DBUG(("PaHost_StopWatchDog: cancel WatchDog\n")); pthread_cancel( pahsc->pahsc_WatchDogThread ); pthread_join( pahsc->pahsc_WatchDogThread, NULL ); pahsc->pahsc_WatchDogThread = INVALID_THREAD; @@ -651,7 +673,10 @@ static void PaHost_StopWatchDog( PaHostSoundControl *pahsc ) /* Cancel Canary thread if there is one. */ if( pahsc->pahsc_CanaryThread != INVALID_THREAD ) { + 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_CanaryThread = INVALID_THREAD; } @@ -668,6 +693,7 @@ static PaError PaHost_StartWatchDog( PaHostSoundControl *pahsc ) 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*/, (void*)PaHost_CanaryProc, pahsc); @@ -680,6 +706,7 @@ static PaError PaHost_StartWatchDog( PaHostSoundControl *pahsc ) } /* Launch a watchdog thread to prevent runaway audio thread. */ + pahsc->pahsc_WatchDogRun = 1; hres = pthread_create(&(pahsc->pahsc_WatchDogThread), NULL /*pthread_attr_t * attr*/, (void*)PaHost_WatchDogProc, pahsc); @@ -710,6 +737,9 @@ static PaError PaHost_BoostPriority( internalPortAudioStream *past ) 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; @@ -806,13 +836,13 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) pahsc->pahsc_LastStreamBytes += delta; pahsc->pahsc_LastPosPtr = info.bytes; } - + DBUG(("Pa_AudioThreadProc: left audio loop.\n")); + past->past_IsActive = 0; - PaHost_StopWatchDog( pahsc ); - DBUG(("leaving audio thread.\n")); error: + DBUG(("leaving audio thread.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif From 35714fdc83a9cc0d36db6d254001aa99800fb638 Mon Sep 17 00:00:00 2001 From: philburk Date: Tue, 19 Mar 2002 01:28:14 +0000 Subject: [PATCH 036/814] use smaller latency --- pa_tests/pa_minlat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pa_tests/pa_minlat.c b/pa_tests/pa_minlat.c index 356ccb9..bc9f185 100644 --- a/pa_tests/pa_minlat.c +++ b/pa_tests/pa_minlat.c @@ -41,7 +41,7 @@ #ifndef M_PI #define M_PI (3.14159265) #endif -#define DEFAULT_BUFFER_SIZE (128) +#define DEFAULT_BUFFER_SIZE (64) #define TABLE_SIZE (200) typedef struct { @@ -121,7 +121,7 @@ void main( int argc, char **argv ) paFloat32, /* 32 bit floating point output */ NULL, sampleRate, - framesPerBuffer,/* 46 msec buffers */ + framesPerBuffer, numBuffers, /* number of buffers */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ paminlatCallback, From ac7b7bb96a0d68754d3408f2406ed22037ea1c98 Mon Sep 17 00:00:00 2001 From: philburk Date: Tue, 19 Mar 2002 01:30:28 +0000 Subject: [PATCH 037/814] steadily play a different sine wave on each channel --- pa_tests/debug_multi_out.c | 102 +++++++++++++++---------------------- 1 file changed, 40 insertions(+), 62 deletions(-) diff --git a/pa_tests/debug_multi_out.c b/pa_tests/debug_multi_out.c index 4817a11..1d211e1 100644 --- a/pa_tests/debug_multi_out.c +++ b/pa_tests/debug_multi_out.c @@ -1,9 +1,8 @@ /* * $Id$ - * debug_multi.c - * Play a sine wave on each of multiple channels, + * debug_multi_out.c + * Play a different sine wave on each channels, * using the Portable Audio api. - * Hacked test for debugging PA. * * Author: Phil Burk http://www.softsynth.com * @@ -38,28 +37,24 @@ #include #include #include "portaudio.h" -#define NUM_CHANNELS (8) -// #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) -#define OUTPUT_DEVICE (18) -#define NUM_SECONDS (NUM_CHANNELS*4) + +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SAMPLE_RATE (44100) -#define FRAMES_PER_CHANNEL (SAMPLE_RATE/2) #define FRAMES_PER_BUFFER (256) -#define MIN_LATENCY_MSEC (400) -#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) +#define FREQ_INCR (300.0 / SAMPLE_RATE) +#define MAX_CHANNELS (64) + #ifndef M_PI #define M_PI (3.14159265) #endif -#define TABLE_SIZE (800) + typedef struct { - float sine[TABLE_SIZE]; - int phase; - int liveChannel; - int count; - unsigned int sampsToGo; + int numChannels; + double phases[MAX_CHANNELS]; } paTestData; + /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). @@ -70,38 +65,25 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; - int i, j; + int frameIndex, channelIndex; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; - if( data->sampsToGo < framesPerBuffer ) + for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) { - finished = 1; - } - else - { - for( i=0; i<(int)framesPerBuffer; i++ ) + for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) { - for( j=0; jliveChannel) ? data->sine[data->phase] : 0.0f; - /* Play each channel at a higher frequency. */ - data->phase += 1 + data->liveChannel; - if( data->phase >= TABLE_SIZE ) data->phase -= TABLE_SIZE; - } - /* Switch channels every so often. */ - if( --data->count <= 0 ) - { - data->count = FRAMES_PER_CHANNEL; - data->liveChannel += 1; - if( data->liveChannel >= NUM_CHANNELS ) data->liveChannel = 0; - } + /* Output sine wave on every channel. */ + *out++ = (float) sin(data->phases[channelIndex]); + + /* Play each channel at a higher frequency. */ + data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); + if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); } - data->sampsToGo -= framesPerBuffer; } - return finished; + + return 0; } /*******************************************************************/ int main(void); @@ -109,21 +91,18 @@ int main(void) { PortAudioStream *stream; PaError err; - paTestData data; - int i; - int totalSamps; - printf("PortAudio Test: output sine wave. %d buffers\n", NUM_BUFFERS ); - /* initialise sinusoidal wavetable */ - for( i=0; imaxOutputChannels; + if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; + printf("Number of Channels = %d\n", data.numChannels ); + err = Pa_OpenStream( &stream, paNoDevice, /* default input device */ @@ -131,27 +110,26 @@ int main(void) paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, - NUM_CHANNELS, + data.numChannels, paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ - NUM_BUFFERS, /* number of buffers, if zero then use default minimum */ + 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); if( err != paNoError ) goto error; - printf("Is callback being called?\n"); - for( i=0; i Date: Thu, 21 Mar 2002 00:30:03 +0000 Subject: [PATCH 038/814] Contains sample format conversion routines, eg. paInt32 to paInt16. --- pa_common/pa_convert.c | 402 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 pa_common/pa_convert.c diff --git a/pa_common/pa_convert.c b/pa_common/pa_convert.c new file mode 100644 index 0000000..377a955 --- /dev/null +++ b/pa_common/pa_convert.c @@ -0,0 +1,402 @@ +/* + * pa_conversions.c + * portaudio + * + * Created by Phil Burk on Mon Mar 18 2002. + * + */ +#include + +#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; ipast_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; +} From fc4ad21da35a220918c5332e65d7cf5ee1aafb7c Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 21 Mar 2002 00:31:38 +0000 Subject: [PATCH 039/814] Fixed typo. --- pa_common/portaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pa_common/portaudio.h b/pa_common/portaudio.h index 8c5eae5..35c2bcc 100644 --- a/pa_common/portaudio.h +++ b/pa_common/portaudio.h @@ -397,7 +397,7 @@ PaError Pa_AbortStream( PortAudioStream *stream ); PaError Pa_StreamActive( PortAudioStream *stream ); /* - Pa_StreamTime() returns the current output time in samples for the 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). From cf24fdd1c000a59d42f558ff91ce75d5222fa490 Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 21 Mar 2002 00:32:50 +0000 Subject: [PATCH 040/814] Added support for conversion nroutines in pa_convert.c. SHifted Dither value right by one to account for high pass filter. --- pa_common/pa_host.h | 56 ++++++++++++++++++++++++++------ pa_common/pa_lib.c | 78 ++++++++++----------------------------------- 2 files changed, 63 insertions(+), 71 deletions(-) diff --git a/pa_common/pa_host.h b/pa_common/pa_host.h index 9a35261..b077f83 100644 --- a/pa_common/pa_host.h +++ b/pa_common/pa_host.h @@ -36,6 +36,8 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ + +#include "portaudio.h" #ifdef __cplusplus extern "C" @@ -59,6 +61,12 @@ extern "C" 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) /************************************************************************************/ @@ -76,7 +84,9 @@ typedef struct internalPortAudioStream int past_NumOutputChannels; PaDeviceID past_InputDeviceID; PaDeviceID past_OutputDeviceID; + PaSampleFormat past_NativeInputSampleFormat; PaSampleFormat past_InputSampleFormat; + PaSampleFormat past_NativeOutputSampleFormat; PaSampleFormat past_OutputSampleFormat; void *past_DeviceData; PortAudioCallback *past_Callback; @@ -99,11 +109,19 @@ typedef struct internalPortAudioStream 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; /************************************************************************************/ -/****************** Prototypes ******************************************************/ +/******** These functions must be provided by a platform implementation. ************/ /************************************************************************************/ PaError PaHost_Init( void ); @@ -120,22 +138,42 @@ PaError PaHost_StartEngine( internalPortAudioStream *past ); PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ); PaError PaHost_StreamActive( internalPortAudioStream *past ); -long Pa_CallConvertInt16( internalPortAudioStream *past, - short *nativeInputBuffer, - short *nativeOutputBuffer ); - -long Pa_CallConvertFloat32( internalPortAudioStream *past, - float *nativeInputBuffer, - float *nativeOutputBuffer ); - 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 ******************/ +/**********************************************************************/ + 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<past_Magic = PA_MAGIC; /* Set ID to catch bugs. */ past->past_FramesPerUserBuffer = framesPerBuffer; - past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */ + past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() MUST CHECK FOR ZERO! */ past->past_Callback = callback; past->past_UserData = userData; past->past_OutputSampleFormat = outputSampleFormat; @@ -248,7 +248,7 @@ PaError Pa_OpenStream( #else past->past_SampleRate = sampleRate; #endif - /* Allocate single Input buffer. */ + /* 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 ) @@ -481,10 +481,11 @@ double Pa_GetCPULoad( PortAudioStream* stream) /************************************************************* ** 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 DITHER_BITS (15) -#define DITHER_SCALE (1.0f / ((1<>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS)); + /* 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; @@ -513,8 +518,6 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, short *nativeOutputBuffer ) { long temp; - long bytesEmpty = 0; - long bytesFilled = 0; int userResult; unsigned int i; void *inputBuffer = NULL; @@ -576,7 +579,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, for( i=0; i> 8; /* PLB20010820 */ + temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); inBufPtr[i] = (char)(temp >> 8); } @@ -602,7 +605,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, for( i=0; i> 8; /* PLB20010820 */ + temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */ } @@ -669,7 +672,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, /* If you dither then you have to clip because dithering could push the signal out of range! */ for( i=0; i 0x7FFF) ? 0x7FFF : temp)); @@ -693,7 +696,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, for( i=0; i> 1) + Pa_TriangularDither(); + temp = (outBufPtr[i] >> 1) + PaConvert_TriangularDither(); temp = temp >> 15; *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); } @@ -730,55 +733,6 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, return userResult; } -/************************************************************************* -** Called by host code. -** Convert input from Float32, call user code, then convert output -** to Float32 format for native use. -** Assumes host native format is Float32. -** Returns result from user callback. -** FIXME - Unimplemented for formats other than paFloat32!!!! -*/ -long Pa_CallConvertFloat32( internalPortAudioStream *past, - float *nativeInputBuffer, - float *nativeOutputBuffer ) -{ - long bytesEmpty = 0; - long bytesFilled = 0; - int userResult; - void *inputBuffer = NULL; - void *outputBuffer = NULL; - - /* Get native data from DirectSound. */ - if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) ) - { - inputBuffer = nativeInputBuffer; /* FIXME */ - } - - /* 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 == paFloat32) ? - 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. */ /* FIXME */ - return userResult; -} - /*************************************************************************/ PaError Pa_Initialize( void ) { From b47db2718119737753a0f3f71236f024b4d56fea Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 21 Mar 2002 00:39:42 +0000 Subject: [PATCH 041/814] Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file. Return error if opened in mono mode cuz not supported. Add support for Pa_GetCPULoad(); Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!) Check for invalid sample rates and return an error. Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally. Better error checking for invalid channel counts and invalid devices. --- pa_mac_core/notes.txt | 11 +- pa_mac_core/pa_mac_core.c | 334 ++++++++++++++++++++++++-------------- 2 files changed, 218 insertions(+), 127 deletions(-) diff --git a/pa_mac_core/notes.txt b/pa_mac_core/notes.txt index 7e8835b..c79b90e 100644 --- a/pa_mac_core/notes.txt +++ b/pa_mac_core/notes.txt @@ -2,14 +2,16 @@ Notes on Core Audio Implementation of PortAudio by Phil Burk and Darren Gibbs -Document last updated Feb 7, 2002 +Document last updated March 20, 2002 WHAT WORKS Output with very low latency, <10 msec. Half duplex input or output. Full duplex on the same CoreAudio device. -The paFLoat32 sample format. +The paFLoat32, paInt16, paInt8, paUInt8 sample formats. +Pa_GetCPULoad() +Pa_StreamTime() KNOWN BUGS OR LIMITATIONS @@ -18,10 +20,7 @@ devices. Note that some CoreAudio devices like the Roland UH30 look like one device but are actually two different CoreAudio devices. The BuiltIn audio is typically one CoreAudio device. -User formats other than the native paFloat32 are not yet supported. - -If you request a non-supported sample rate then you just get a -supported rate with no error messages. +Mono doesn't work. DEVICE MAPPING diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c index 43fab18..f384382 100644 --- a/pa_mac_core/pa_mac_core.c +++ b/pa_mac_core/pa_mac_core.c @@ -39,29 +39,32 @@ 12.7.2001 - Gord Peters - Tweaks to compile on PA V17 and OS X 10.1 2.7.2002 - Darren and Phil - fixed isInput so GetProperty works better, fixed device queries for numChannels and sampleRates, - one CoreAudio device now maps to separate input and output PaDevices, - audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices). + one CoreAudio device now maps to separate input and output PaDevices, + audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices). 2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7 - + 3.19.2002 - Phil Burk - Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file. + Return error if opened in mono mode cuz not supported. + Add support for Pa_GetCPULoad(); + Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!) + Check for invalid sample rates and return an error. + Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally. + Better error checking for invalid channel counts and invalid devices. TODO: -O- conversion for other user formats besides paFloat32 +O- how do mono output? O- FIFO between input and output callbacks if different devices, like in pa_mac.c -O- debug mono output -O- error check for unsupported sample rates -O- BUG: if ask for 22050 when only 44100 supported then get 44100 and no error message - */ +*/ + #include #include #include #include + #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" /************************************************* Constants ********/ -/* Switches for debugging. */ -#define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ /* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ #define PA_TRACE_RUN (0) @@ -75,8 +78,8 @@ O- BUG: if ask for 22050 when only 44100 supported then get 44100 and no error m #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ -// define value of isInput passed to CodeAudio routines -#define IS_INPUT (true) +// define value of isInput passed to CoreAudio routines +#define IS_INPUT (true) #define IS_OUTPUT (false) /************************************************************** @@ -87,24 +90,15 @@ typedef struct PaHostSoundControl { AudioDeviceID pahsc_AudioDeviceID; // Must be the same for input and output for now. /* Input -------------- */ - int pahsc_BytesPerHostInputBuffer; - int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */ + int pahsc_BytesPerUserNativeInputBuffer; /* native buffer size in bytes per user chunk */ /* Output -------------- */ - int pahsc_BytesPerHostOutputBuffer; - int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */ - /* Run Time -------------- */ - PaTimestamp pahsc_FramesPlayed; - long pahsc_LastPosition; /* used to track frames played. */ - /* For measuring CPU utilization. */ - // LARGE_INTEGER pahsc_EntryCount; - // LARGE_INTEGER pahsc_LastExitCount; + int pahsc_BytesPerUserNativeOutputBuffer; /* native buffer size in bytes per user chunk */ /* Init Time -------------- */ int pahsc_FramesPerHostBuffer; - int pahsc_UserBuffersPerHostBuffer; - - // CRITICAL_SECTION pahsc_StreamLock; /* Mutext to prevent threads from colliding. */ - int pahsc_StreamLockInited; - + int pahsc_UserBuffersPerHostBuffer; + /* For measuring CPU utilization. */ + struct timeval pahsc_EntryTime; + double pahsc_InverseMicrosPerBuffer; /* 1/Microseconds of real-time audio per user buffer. */ } PaHostSoundControl; @@ -136,10 +130,13 @@ static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs static const char sMapperSuffixInput[] = " - Input"; static const char sMapperSuffixOutput[] = " - Output"; -/************************************************* Macros ********/ +/* We index the input devices first, then the output devices. */ +#define LOWEST_INPUT_DEVID (0) +#define HIGHEST_INPUT_DEVID (sNumInputDevices - 1) +#define LOWEST_OUTPUT_DEVID (sNumInputDevices) +#define HIGHEST_OUTPUT_DEVID (sNumPaDevices - 1) -/* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ -#define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) +/************************************************* Macros ********/ /************************************************* Prototypes **********/ @@ -159,46 +156,44 @@ 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. */ - // QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); + 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 ) { -#if 0 - // LARGE_INTEGER CurrentCount = { 0, 0 }; - // LONGLONG InsideCount; - // LONGLONG TotalCount; - /* - ** Measure CPU utilization during this callback. Note that this calculation - ** assumes that we had the processor the whole time. - */ -#define LOWPASS_COEFFICIENT_0 (0.9) + 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( QueryPerformanceCounter( &CurrentCount ) ) + if( gettimeofday( ¤tTime, NULL ) == 0 ) { - if( past->past_IfLastExitValid ) - { - InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; - TotalCount = CurrentCount.QuadPart - pahsc->pahsc_LastExitCount.QuadPart; - /* Low pass filter the result because sometimes we get called several times in a row. - * That can cause the TotalCount to be very low which can cause the usage to appear - * unnaturally high. So we must filter numerator and denominator separately!!! - */ - past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + - (LOWPASS_COEFFICIENT_1 * InsideCount)); - past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + - (LOWPASS_COEFFICIENT_1 * TotalCount)); - past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; - } - pahsc->pahsc_LastExitCount = CurrentCount; - past->past_IfLastExitValid = 1; + usecsElapsed = SubtractTime_AminusB( ¤tTime, &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); } -#endif } +/****************************************** END CPU UTILIZATION *******/ /************************************************************************/ static PaDeviceID Pa_QueryDefaultInputDevice( void ) @@ -211,12 +206,13 @@ static PaDeviceID Pa_QueryDefaultInputDevice( void ) // get the default output device for the HAL // it is required to pass the size of the data to be returned - count = sizeof(AudioDeviceID); + count = sizeof(tempDeviceID); err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &tempDeviceID); if (err != noErr) goto Bail; + // scan input devices to see which one matches this device defaultDeviceID = paNoDevice; - for( i=0; inumSampleRates == 0 ) goto error; // Get data format info from the device. - err = deviceDataFormatFromID(devID, &formatDesc, isInput ); + outSize = sizeof(formatDesc); + err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc); + // If no channels supported, then not a very good device. if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error; @@ -543,9 +535,8 @@ static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDev break; } - // Get the device name - deviceInfo->name = deviceNameFromID( devID, isInput ); + deviceInfo->name = PaHost_DeviceNameFromID( devID, isInput ); return 1; error: @@ -630,9 +621,6 @@ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) PaError PaHost_Init( void ) { -#if PA_SIMULATE_UNDERFLOW - PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); -#endif return Pa_MaybeQueryDevices(); } @@ -644,8 +632,8 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL AudioBufferList* outOutputData ) { PaError result = 0; - char *inBufPtr; - char *outBufPtr; + char *inputNativeBufferfPtr; + char *outputNativeBufferfPtr; int gotInput = 0; int gotOutput = 0; int i; @@ -656,13 +644,6 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL past->past_NumCallbacks += 1; -#if PA_SIMULATE_UNDERFLOW - if(gUnderCallbackCounter++ == UNDER_SLEEP_AT) - { - Sleep(UNDER_SLEEP_FOR); - } -#endif - #if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks ); #endif @@ -673,16 +654,16 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL gotOutput = 0; if( past->past_NumOutputChannels > 0 ) { - outBufPtr = (char*)outOutputData->mBuffers[0].mData, + outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData, gotOutput = 1; } /* If we are using input, then we need a full input buffer. */ gotInput = 0; - inBufPtr = NULL; + inputNativeBufferfPtr = NULL; if( past->past_NumInputChannels > 0 ) { - inBufPtr = (char*)inInputData->mBuffers[0].mData, + inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData, gotInput = 1; } @@ -697,17 +678,17 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL { /* Clear remainder of wave buffer if we are waiting for stop. */ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); - memset( outBufPtr, 0, pahsc->pahsc_BytesPerUserOutputBuffer ); + memset( outputNativeBufferfPtr, 0, pahsc->pahsc_BytesPerUserNativeOutputBuffer ); } } else { - /* Convert 16 bit native data to user data and call user routine. */ - result = Pa_CallConvertFloat32( past, (float *) inBufPtr, (float *) outBufPtr ); + /* Convert 32 bit native data to user data and call user routine. */ + result = PaConvert_Process( past, inputNativeBufferfPtr, outputNativeBufferfPtr ); if( result != 0) done = 1; } - if( gotInput ) inBufPtr += pahsc->pahsc_BytesPerUserInputBuffer; - if( gotOutput) outBufPtr += pahsc->pahsc_BytesPerUserOutputBuffer; + if( gotInput ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer; + if( gotOutput) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer; } Pa_EndUsageCalculation( past ); @@ -731,7 +712,7 @@ OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, past = (internalPortAudioStream *) contextPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; - // Just Curious: printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers); +// printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers); /* Has someone asked us to abort by calling Pa_AbortStream()? */ if( past->past_StopNow ) @@ -748,6 +729,12 @@ OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, } else { + /* use time stamp from CoreAudio if valid */ + if( inOutputTime->mFlags & kAudioTimeStampSampleTimeValid) + { + past->past_FrameCount = inOutputTime->mSampleTime; + } + /* Process full input buffer and fill up empty output buffers. */ if( (result = Pa_TimeSlice( past, inInputData, outOutputData )) != 0) { @@ -786,21 +773,43 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) int bytesPerInputFrame; pahsc = (PaHostSoundControl *) past->past_DeviceData; - + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID)); - if( (past->past_InputDeviceID < 0) || (past->past_InputDeviceID >= sNumPaDevices) ) + if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) || + (past->past_InputDeviceID > HIGHEST_INPUT_DEVID) ) { return paInvalidDeviceId; } hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID]; - // calculate buffer sizes in bytes - bytesPerInputFrame = Pa_GetSampleSize(past->past_InputSampleFormat) * past->past_NumInputChannels; - pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame; - pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerInputFrame; + if( past->past_NumInputChannels != hostDeviceInfo->paInfo.maxInputChannels ) + { +#if 1 + return paInvalidChannelCount; // FIXME - how support mono? +#else +FIXME - should this be set on a stream basis? Is it possible to change? + /* Attempt to set number of channels. */ + AudioStreamBasicDescription formatDesc; + OSStatus err; + memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); + formatDesc.mChannelsPerFrame = past->past_NumInputChannels; + err = AudioDeviceSetProperty(pahsc->pahsc_AudioDeviceID, 0, 0, + IS_INPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); + + if (err != kAudioHardwareNoError) + { + result = paInvalidChannelCount; + goto error; + } +#endif + } + + // calculate native buffer sizes in bytes + bytesPerInputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels; + pahsc->pahsc_BytesPerUserNativeInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame; + bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerInputFrame; // Change the bufferSize of the device! Is this per device or just for our stream? - bytesPerHostBuffer = pahsc->pahsc_BytesPerHostInputBuffer; dataSize = sizeof(UInt32); err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT, kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); @@ -811,6 +820,9 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) goto error; } + // setup conversion procedure + result = PaConvert_SetupInput( past, paFloat32 ); + return result; error: @@ -827,24 +839,45 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) UInt32 dataSize; OSStatus err = noErr; int bytesPerOutputFrame; - + pahsc = (PaHostSoundControl *) past->past_DeviceData; - + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); - if( (past->past_OutputDeviceID < 0) || (past->past_OutputDeviceID >= sNumPaDevices) ) + if( (past->past_OutputDeviceID < LOWEST_OUTPUT_DEVID) || + (past->past_OutputDeviceID > HIGHEST_OUTPUT_DEVID) ) { return paInvalidDeviceId; } hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID]; + + if( past->past_NumOutputChannels != hostDeviceInfo->paInfo.maxOutputChannels ) + { +#if 1 + return paInvalidChannelCount; // FIXME - how support mono? +#else + /* Attempt to set number of channels. */ + AudioStreamBasicDescription formatDesc; + OSStatus err; + memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); + formatDesc.mChannelsPerFrame = past->past_NumOutputChannels; + err = AudioDeviceSetProperty(pahsc->pahsc_AudioDeviceID, 0, 0, + IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); + + if (err != kAudioHardwareNoError) + { + result = paInvalidChannelCount; + goto error; + } +#endif + } // calculate buffer sizes in bytes - bytesPerOutputFrame = Pa_GetSampleSize(past->past_OutputSampleFormat) * past->past_NumOutputChannels; - pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame; - pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerOutputFrame; + bytesPerOutputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels; + pahsc->pahsc_BytesPerUserNativeOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame; + bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerOutputFrame; // Change the bufferSize of the device! Is this per device or just for our stream? - bytesPerHostBuffer = pahsc->pahsc_BytesPerHostOutputBuffer; - dataSize = sizeof(UInt32); + dataSize = sizeof(bytesPerHostBuffer); err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT, kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); if( err != noErr ) @@ -853,7 +886,10 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) result = paHostError; goto error; } - + + // setup conversion procedure + result = PaConvert_SetupOutput( past, paFloat32 ); + return result; error: @@ -931,8 +967,11 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate); - PRINT(("PortAudio on OSX - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); + PRINT(("PortAudio on OS X - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); } + + /* Setup constants for CPU load measurement. */ + pahsc->pahsc_InverseMicrosPerBuffer = past->past_SampleRate / (1000000.0 * past->past_FramesPerUserBuffer); /* ------------------ OUTPUT */ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) @@ -950,6 +989,22 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; } + /* Attempt to set device sample rate. */ + { + AudioStreamBasicDescription formatDesc; + OSStatus err; + memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); + formatDesc.mSampleRate = past->past_SampleRate; + err = AudioDeviceSetProperty(pahsc->pahsc_AudioDeviceID, 0, 0, + IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); + + if (err != kAudioHardwareNoError) + { + result = paInvalidSampleRate; + goto error; + } + } + return result; error: @@ -979,9 +1034,7 @@ PaError PaHost_StartEngine( internalPortAudioStream *past ) past->past_StopSoon = 0; past->past_StopNow = 0; past->past_IsActive = 1; - pahsc->pahsc_FramesPlayed = 0.0; - pahsc->pahsc_LastPosition = 0; - + // Associate an IO proc with the device and pass a pointer to the audio data context err = AudioDeviceAddIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc, past); if (err != noErr) goto error; @@ -1061,6 +1114,38 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) return paNoError; } +/************************************************************************* +** 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") + +#if 1 +int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond ) +{ + int minBuffers; + int denominator; + int minLatencyMsec = PA_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; + } + + denominator = 1000.0 * framesPerBuffer; + minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator ); + if( minBuffers < 1 ) minBuffers = 1; + return minBuffers; +} +#else /************************************************************************* ** Determine minimum number of buffers required for this host based ** on minimum latency. @@ -1081,6 +1166,7 @@ int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) return minUserBuffers; } +#endif /************************************************************************* ** Cleanup device info. @@ -1151,11 +1237,17 @@ PaError PaHost_StreamActive( internalPortAudioStream *past ) /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { + AudioTimeStamp timeStamp; + PaTimestamp streamTime; PaHostSoundControl *pahsc; internalPortAudioStream *past = (internalPortAudioStream *) stream; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; + + AudioDeviceGetCurrentTime(pahsc->pahsc_AudioDeviceID, &timeStamp); + + streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ? + timeStamp.mSampleTime : past->past_FrameCount; - // FIXME PaHost_UpdateStreamTime( pahsc ); - return pahsc->pahsc_FramesPlayed; + return streamTime; } From 3e603eba3e7dbfda815e2c24d863f19e9528b293 Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 21 Mar 2002 00:44:35 +0000 Subject: [PATCH 042/814] New tests written when debugging pa_mac_core --- pa_tests/debug_convert.c | 131 ++++++++++++++++++++++ pa_tests/debug_dither_calc.c | 55 +++++++++ pa_tests/debug_sine_amp.c | 157 ++++++++++++++++++++++++++ pa_tests/debug_sine_formats.c | 202 ++++++++++++++++++++++++++++++++++ 4 files changed, 545 insertions(+) create mode 100644 pa_tests/debug_convert.c create mode 100644 pa_tests/debug_dither_calc.c create mode 100644 pa_tests/debug_sine_amp.c create mode 100644 pa_tests/debug_sine_formats.c diff --git a/pa_tests/debug_convert.c b/pa_tests/debug_convert.c new file mode 100644 index 0000000..a17b556 --- /dev/null +++ b/pa_tests/debug_convert.c @@ -0,0 +1,131 @@ +/* + * $Id$ + * Convert tagged values. + * + * Author: Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +//#define OUTPUT_DEVICE (11) +#define NUM_SECONDS (8) +#define SLEEP_DUR (800) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) + +#define NUM_BUFFERS (0) + +typedef struct +{ + unsigned int framesToGo; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *out = (short*)outputBuffer; + int i; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + if( data->framesToGo < framesPerBuffer ) finished = 1; + + for( i=0; i +#include +#include "portaudio.h" +#include "pa_host.h" + +/*******************************************************************/ +int main(void); +int main(void) +{ + long max,min; + int i; + + for( i=0; i<10000; i++ ) + { + long dither = PaConvert_TriangularDither(); + // printf("dither = 0x%08X\n", dither ); + if( dither < min ) min = dither; + else if( dither > max ) max = dither; + } + printf("min = 0x%08X = %d, max = 0x%08X = %d\n", min, min, max, max ); +} diff --git a/pa_tests/debug_sine_amp.c b/pa_tests/debug_sine_amp.c new file mode 100644 index 0000000..ceaf572 --- /dev/null +++ b/pa_tests/debug_sine_amp.c @@ -0,0 +1,157 @@ +/* + * $Id$ + * Play a different sine wave on each channels, + * using the Portable Audio api. + * Allos amplitude to be set interactively. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" + +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#define FREQ_INCR (300.0 / SAMPLE_RATE) +#define MAX_CHANNELS (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +typedef struct +{ + int numChannels; + double phases[MAX_CHANNELS]; + float amplitude; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + int frameIndex, channelIndex; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) + { + for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) + { + /* Output sine wave on every channel. */ + *out++ = (float) ( data->amplitude * sin(data->phases[channelIndex]) ); + + /* Play each channel at a higher frequency. */ + data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); + if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); + } + } + + return 0; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + char pad[256]; + PortAudioStream *stream; + PaError err; + const PaDeviceInfo *pdi; + paTestData data = {0}; + printf("PortAudio Test: output sine wave on each channel.\n" ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE ); + data.numChannels = pdi->maxOutputChannels; + if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; + printf("Number of Channels = %d\n", data.numChannels ); + data.amplitude = 1.0; + + err = Pa_OpenStream( + &stream, + paNoDevice, /* default input device */ + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + OUTPUT_DEVICE, + data.numChannels, + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + do + { + printf("Current amplitude = %f\n", data.amplitude ); + printf("Enter new amplitude or 'q' to quit.\n"); + fflush(stdout); + gets( pad ); + if( pad[0] != 'q' ) + { + // I tried to use atof but it seems to be broken on Mac OS X 10.1 + float amp; + sscanf( pad, "%f", & ); + data.amplitude = amp; + } + } while( pad[0] != 'q' ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + Pa_CloseStream( stream ); + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/pa_tests/debug_sine_formats.c b/pa_tests/debug_sine_formats.c new file mode 100644 index 0000000..a1fce56 --- /dev/null +++ b/pa_tests/debug_sine_formats.c @@ -0,0 +1,202 @@ +/* + * $Id$ + * patest_sine_formats.c + * Play a sine wave using the Portable Audio api for several seconds. + * Test various data formats. + * + * Author: Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: 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. + * + */ +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (10) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) + +#define LEFT_FREQ (SAMPLE_RATE/512.0) /* So we hit 1.0 */ +#define RIGHT_FREQ (500.0) + +#define AMPLITUDE (1.0) + +/* Select ONE format for testing. */ +#define TEST_UINT8 (1) +#define TEST_INT8 (0) +#define TEST_INT16 (0) +#define TEST_FLOAT32 (0) + +#if TEST_UINT8 +#define TEST_FORMAT paUInt8 +typedef unsigned char SAMPLE_t; +#define SAMPLE_ZERO (0x80) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) +#define FORMAT_NAME "Unsigned 8 Bit" + +#elif TEST_INT8 +#define TEST_FORMAT paInt8 +typedef char SAMPLE_t; +#define SAMPLE_ZERO (0) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) +#define FORMAT_NAME "Signed 8 Bit" + +#elif TEST_INT16 +#define TEST_FORMAT paInt16 +typedef short SAMPLE_t; +#define SAMPLE_ZERO (0) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x))) +#define FORMAT_NAME "Signed 16 Bit" + +#elif TEST_FLOAT32 +#define TEST_FORMAT paFloat32 +typedef float SAMPLE_t; +#define SAMPLE_ZERO (0.0) +#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x)) +#define FORMAT_NAME "Float 32 Bit" +#endif + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + + +typedef struct +{ + double left_phase; + double right_phase; + unsigned int framesToGo; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE_t *out = (SAMPLE_t *)outputBuffer; + SAMPLE_t sample; + int i; + int framesToCalc; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + if( data->framesToGo < framesPerBuffer ) + { + framesToCalc = data->framesToGo; + data->framesToGo = 0; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + data->framesToGo -= framesPerBuffer; + } + + for( i=0; ileft_phase += (LEFT_FREQ / SAMPLE_RATE); + if( data->left_phase > 1.0) data->left_phase -= 1.0; + sample = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); /**/ + *out++ = sample; +/* *out++ = sample; /**/ +/* *out++ = 0; /**/ + + data->right_phase += (RIGHT_FREQ / SAMPLE_RATE); + if( data->right_phase > 1.0) data->right_phase -= 1.0; + *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); /**/ +/* *out++ = 0; /* */ + } + /* zero remainder of final buffer */ + for( ; i<(int)framesPerBuffer; i++ ) + { + *out++ = SAMPLE_ZERO; /* left */ + *out++ = SAMPLE_ZERO; /* right */ + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + paTestData data; + int totalSamps; + + printf("PortAudio Test: output " FORMAT_NAME "\n"); + + + data.left_phase = data.right_phase = 0.0; + data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + err = Pa_OpenStream( + &stream, + paNoDevice,/* default input device */ + 0, /* no input */ + TEST_FORMAT, + NULL, + Pa_GetDefaultOutputDeviceID(), /* default output device */ + 2, /* stereo output */ + TEST_FORMAT, + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS ); + while( Pa_StreamActive( stream ) ) Pa_Sleep(10); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + + printf("PortAudio Test Finished: " FORMAT_NAME "\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} From f3b86fe9d53f4be642b131222d560fa451064771 Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 21 Mar 2002 00:54:06 +0000 Subject: [PATCH 043/814] Initialize default device IDs. --- pa_mac_core/pa_mac_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c index f384382..20eb070 100644 --- a/pa_mac_core/pa_mac_core.c +++ b/pa_mac_core/pa_mac_core.c @@ -202,7 +202,7 @@ static PaDeviceID Pa_QueryDefaultInputDevice( void ) UInt32 count; int i; AudioDeviceID tempDeviceID = kAudioDeviceUnknown; - PaDeviceID defaultDeviceID; + PaDeviceID defaultDeviceID = paNoDevice; // get the default output device for the HAL // it is required to pass the size of the data to be returned @@ -232,7 +232,7 @@ static PaDeviceID Pa_QueryDefaultOutputDevice( void ) UInt32 count; int i; AudioDeviceID tempDeviceID = kAudioDeviceUnknown; - PaDeviceID defaultDeviceID; + PaDeviceID defaultDeviceID = paNoDevice; // get the default output device for the HAL // it is required to pass the size of the data to be returned From e763432f49d5963ab4d63d383fe3ce205ca5b650 Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 21 Mar 2002 00:58:45 +0000 Subject: [PATCH 044/814] Minor tweaks while debugging pa_mac_core.c --- pa_tests/debug_multi_out.c | 1 + pa_tests/debug_sine.c | 2 +- pa_tests/paqa_errs.c | 25 +++++++++++++ pa_tests/patest_dither.c | 1 + pa_tests/patest_latency.c | 3 +- pa_tests/patest_maxsines.c | 17 +++++---- pa_tests/patest_record.c | 53 +++++++++++++++++++--------- pa_tests/patest_sine_formats.c | 13 +++---- pa_tests/patest_sine_time.c | 64 +++++++++++++++++++++++++++------- 9 files changed, 133 insertions(+), 46 deletions(-) diff --git a/pa_tests/debug_multi_out.c b/pa_tests/debug_multi_out.c index 1d211e1..d230833 100644 --- a/pa_tests/debug_multi_out.c +++ b/pa_tests/debug_multi_out.c @@ -125,6 +125,7 @@ int main(void) if( err != paNoError ) goto error; printf("Hit ENTER to stop sound.\n"); + fflush(stdout); getchar(); err = Pa_StopStream( stream ); diff --git a/pa_tests/debug_sine.c b/pa_tests/debug_sine.c index b79405d..86610d3 100644 --- a/pa_tests/debug_sine.c +++ b/pa_tests/debug_sine.c @@ -43,7 +43,7 @@ #define SLEEP_DUR (800) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) -#if 1 +#if 0 #define MIN_LATENCY_MSEC (200) #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #else diff --git a/pa_tests/paqa_errs.c b/pa_tests/paqa_errs.c index 37e75d7..e5ffc62 100644 --- a/pa_tests/paqa_errs.c +++ b/pa_tests/paqa_errs.c @@ -270,6 +270,31 @@ static int TestBadOpens( void ) QaCallback, &myData ) ) == paInvalidFlag) ); + +#if 0 /* FIXME - this is legal for some implementations. */ + HOPEFOR( ( /* Use input device as output device. */ + (result = Pa_OpenStream( + &stream, + paNoDevice, 0, paFloat32, NULL, + Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidDeviceId) ); + + HOPEFOR( ( /* Use output device as input device. */ + (result = Pa_OpenStream( + &stream, + Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, + paNoDevice, 0, paFloat32, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, + paClipOff, + QaCallback, + &myData ) + ) == paInvalidDeviceId) ); +#endif + if( stream != NULL ) Pa_CloseStream( stream ); return result; } diff --git a/pa_tests/patest_dither.c b/pa_tests/patest_dither.c index 8878161..1aa0d38 100644 --- a/pa_tests/patest_dither.c +++ b/pa_tests/patest_dither.c @@ -2,6 +2,7 @@ * $Id$ * patest_dither.c * Attempt to hear difference between dithered and non-dithered signal. + * This only has an effect if the native format is 16 bit. * * Author: Phil Burk http://www.softsynth.com * diff --git a/pa_tests/patest_latency.c b/pa_tests/patest_latency.c index 3096c8c..66820bc 100644 --- a/pa_tests/patest_latency.c +++ b/pa_tests/patest_latency.c @@ -115,7 +115,7 @@ int main(void) /* initialise sinusoidal wavetable */ for( i=0; iphases[j] = phase; } - - *out++ = (float) (output / data->numSines); + outSample = (float) (output / data->numSines); + *out++ = outSample; /* Left */ + *out++ = outSample; /* Right */ } return finished; } @@ -111,16 +113,16 @@ int main(void) if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, - paNoDevice,/* default input device */ + paNoDevice, 0, /* no input */ - paFloat32, /* 32 bit floating point input */ + paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ - 1, /* mono output */ + 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ + FRAMES_PER_BUFFER, 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, @@ -136,8 +138,9 @@ int main(void) load = Pa_GetCPULoad( stream ); printf("numSines = %d, CPU load = %f\n", data.numSines, load ); + fflush( stdout ); } - while( load < 0.8 ); + while( (load < 0.8) && (data.numSines < MAX_SINES) ); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; diff --git a/pa_tests/patest_record.c b/pa_tests/patest_record.c index 47ccec1..11d8791 100644 --- a/pa_tests/patest_record.c +++ b/pa_tests/patest_record.c @@ -42,24 +42,34 @@ /* #define SAMPLE_RATE (17932) /* Test failure to open with this value. */ #define SAMPLE_RATE (44100) #define NUM_SECONDS (5) +#define NUM_CHANNELS (2) +/* #define DITHER_FLAG (paDitherOff) /**/ +#define DITHER_FLAG (0) /**/ /* Select sample format. */ #if 0 #define PA_SAMPLE_TYPE paFloat32 typedef float SAMPLE; +#define SAMPLE_SILENCE (0.0f) #elif 0 #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; +#define SAMPLE_SILENCE (0) +#elif 0 +#define PA_SAMPLE_TYPE paInt8 +typedef char SAMPLE; +#define SAMPLE_SILENCE (0) #else #define PA_SAMPLE_TYPE paUInt8 typedef unsigned char SAMPLE; +#define SAMPLE_SILENCE (128) + #endif typedef struct { int frameIndex; /* Index into sample array. */ int maxFrameIndex; - int samplesPerFrame; SAMPLE *recordedSamples; } paTestData; @@ -73,7 +83,7 @@ static int recordCallback( void *inputBuffer, void *outputBuffer, { paTestData *data = (paTestData*)userData; SAMPLE *rptr = (SAMPLE*)inputBuffer; - SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; + SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; long framesToCalc; long i; int finished; @@ -96,8 +106,8 @@ static int recordCallback( void *inputBuffer, void *outputBuffer, { for( i=0; iframeIndex += framesToCalc; @@ -121,7 +131,7 @@ static int playCallback( void *inputBuffer, void *outputBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; - SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; + SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; SAMPLE *wptr = (SAMPLE*)outputBuffer; unsigned int i; int finished; @@ -135,12 +145,12 @@ static int playCallback( void *inputBuffer, void *outputBuffer, for( i=0; iframeIndex += framesLeft; finished = 1; @@ -150,7 +160,7 @@ static int playCallback( void *inputBuffer, void *outputBuffer, for( i=0; iframeIndex += framesPerBuffer; finished = 0; @@ -174,8 +184,7 @@ int main(void) data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */ data.frameIndex = 0; - data.samplesPerFrame = 2; - numSamples = totalFrames * data.samplesPerFrame; + numSamples = totalFrames * NUM_CHANNELS; numBytes = numSamples * sizeof(SAMPLE); data.recordedSamples = (SAMPLE *) malloc( numBytes ); @@ -193,7 +202,7 @@ int main(void) err = Pa_OpenStream( &stream, Pa_GetDefaultInputDeviceID(), - data.samplesPerFrame, /* stereo input */ + NUM_CHANNELS, /* stereo input */ PA_SAMPLE_TYPE, NULL, paNoDevice, @@ -203,7 +212,7 @@ int main(void) SAMPLE_RATE, 1024, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ + 0, //paDitherOff, /* flags */ recordCallback, &data ); if( err != paNoError ) goto error; @@ -234,10 +243,20 @@ int main(void) } average += val; } - printf("sample max amplitude = %d\n", max ); + average = average / numSamples; - printf("sample average = %d\n", average ); + if( PA_SAMPLE_TYPE == paFloat32 ) + { + printf("sample max amplitude = %f\n", max ); + printf("sample average = %f\n", average ); + } + else + { + printf("sample max amplitude = %d\n", max ); + printf("sample average = %d\n", average ); + } + /* Write recorded data to a file. */ #if 0 { @@ -249,7 +268,7 @@ int main(void) } else { - fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid ); + fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid ); fclose( fid ); printf("Wrote data to 'recorded.raw'\n"); } @@ -266,7 +285,7 @@ int main(void) PA_SAMPLE_TYPE, NULL, Pa_GetDefaultOutputDeviceID(), - data.samplesPerFrame, /* stereo output */ + NUM_CHANNELS, /* stereo output */ PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, diff --git a/pa_tests/patest_sine_formats.c b/pa_tests/patest_sine_formats.c index 09abb7b..ea92603 100644 --- a/pa_tests/patest_sine_formats.c +++ b/pa_tests/patest_sine_formats.c @@ -40,7 +40,7 @@ #define NUM_SECONDS (20) #define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (256) +#define FRAMES_PER_BUFFER (512) #define LEFT_FREQ (SAMPLE_RATE/256.0) /* So we hit 1.0 */ #define RIGHT_FREQ (500.0) #define AMPLITUDE (1.0) @@ -57,25 +57,22 @@ typedef unsigned char SAMPLE_t; #define SAMPLE_ZERO (0x80) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) #define FORMAT_NAME "Unsigned 8 Bit" -#endif -#if TEST_INT8 +#elif TEST_INT8 #define TEST_FORMAT paInt8 typedef char SAMPLE_t; #define SAMPLE_ZERO (0) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) #define FORMAT_NAME "Signed 8 Bit" -#endif -#if TEST_INT16 +#elif TEST_INT16 #define TEST_FORMAT paInt16 typedef short SAMPLE_t; #define SAMPLE_ZERO (0) -#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767.0 * (x))) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x))) #define FORMAT_NAME "Signed 16 Bit" -#endif -#if TEST_FLOAT32 +#elif TEST_FLOAT32 #define TEST_FORMAT paFloat32 typedef float SAMPLE_t; #define SAMPLE_ZERO (0.0) diff --git a/pa_tests/patest_sine_time.c b/pa_tests/patest_sine_time.c index 9b9cf3b..9c3f0af 100644 --- a/pa_tests/patest_sine_time.c +++ b/pa_tests/patest_sine_time.c @@ -43,16 +43,18 @@ #define NUM_SECONDS (8) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (64) +#define NUM_BUFFERS (0) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { - float sine[TABLE_SIZE]; - int left_phase; - int right_phase; - int framesToGo; + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + int framesToGo; + volatile PaTimestamp outTime; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. @@ -71,6 +73,8 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; + data->outTime = outTime; + if( data->framesToGo < framesPerBuffer ) { framesToCalc = data->framesToGo; @@ -100,23 +104,44 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, } return finished; } +/*******************************************************************/ +static void ReportStreamTime( PortAudioStream *stream, paTestData *data ); +static void ReportStreamTime( PortAudioStream *stream, paTestData *data ) +{ + PaTimestamp streamTime, latency, outTime; + + streamTime = Pa_StreamTime( stream ); + outTime = data->outTime; + if( outTime < 0.0 ) + { + printf("Stream time = %8.1f\n", streamTime ); + } + else + { + latency = outTime - streamTime; + printf("Stream time = %8.1f, outTime = %8.1f, latency = %8.1f\n", + streamTime, outTime, latency ); + } + fflush(stdout); +} + /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; - paTestData data; + paTestData DATA; int i; int totalSamps; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); /* initialise sinusoidal wavetable */ for( i=0; i Date: Thu, 21 Mar 2002 08:36:34 +0000 Subject: [PATCH 045/814] ATtempt to set sample rate separately for input and output. --- pa_mac_core/pa_mac_core.c | 57 ++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c index 20eb070..b7a33b0 100644 --- a/pa_mac_core/pa_mac_core.c +++ b/pa_mac_core/pa_mac_core.c @@ -761,6 +761,23 @@ static int PaHost_CalcTimeOut( internalPortAudioStream *past ) return timeOut; } #endif + + +/*******************************************************************/ +/* Attempt to set device sample rate. */ +static PaError PaHost_SetSampleRate( AudioDeviceID devID, Boolean isInput, double sampleRate ) +{ + AudioStreamBasicDescription formatDesc; + OSStatus err; + memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); + formatDesc.mSampleRate = sampleRate; + err = AudioDeviceSetProperty( devID, 0, 0, + isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); + + if (err != kAudioHardwareNoError) return paInvalidSampleRate; + else return paNoError; +} + /*******************************************************************/ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) { @@ -782,6 +799,10 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) } hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID]; + /* Try to set sample rate. */ + result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_INPUT, past->past_SampleRate ); + if( result != paNoError ) return result; + if( past->past_NumInputChannels != hostDeviceInfo->paInfo.maxInputChannels ) { #if 1 @@ -793,10 +814,10 @@ FIXME - should this be set on a stream basis? Is it possible to change? OSStatus err; memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); formatDesc.mChannelsPerFrame = past->past_NumInputChannels; - err = AudioDeviceSetProperty(pahsc->pahsc_AudioDeviceID, 0, 0, + + err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); - - if (err != kAudioHardwareNoError) + if (err != kAudioHardwareNoError) { result = paInvalidChannelCount; goto error; @@ -849,7 +870,11 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) return paInvalidDeviceId; } hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID]; - + + /* Try to set sample rate. */ + result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_OUTPUT, past->past_SampleRate ); + if( result != paNoError ) return result; + if( past->past_NumOutputChannels != hostDeviceInfo->paInfo.maxOutputChannels ) { #if 1 @@ -860,10 +885,10 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) OSStatus err; memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); formatDesc.mChannelsPerFrame = past->past_NumOutputChannels; - err = AudioDeviceSetProperty(pahsc->pahsc_AudioDeviceID, 0, 0, + err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); - if (err != kAudioHardwareNoError) + if (err != kAudioHardwareNoError) { result = paInvalidChannelCount; goto error; @@ -976,33 +1001,17 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) /* ------------------ OUTPUT */ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) { + pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; result = PaHost_OpenOutputStream( past ); if( result < 0 ) goto error; - pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; } /* ------------------ INPUT */ if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) ) { + pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; result = PaHost_OpenInputStream( past ); if( result < 0 ) goto error; - pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; - } - - /* Attempt to set device sample rate. */ - { - AudioStreamBasicDescription formatDesc; - OSStatus err; - memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); - formatDesc.mSampleRate = past->past_SampleRate; - err = AudioDeviceSetProperty(pahsc->pahsc_AudioDeviceID, 0, 0, - IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); - - if (err != kAudioHardwareNoError) - { - result = paInvalidSampleRate; - goto error; - } } return result; From 782c78c1a3c5e15f62e32916d4f9b8a878c7fe44 Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 21 Mar 2002 18:26:46 +0000 Subject: [PATCH 046/814] Play a different sine frequency on all channels. Good for testing multi-channel output. --- pa_tests/patest_multi_sine.c | 144 +++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 pa_tests/patest_multi_sine.c diff --git a/pa_tests/patest_multi_sine.c b/pa_tests/patest_multi_sine.c new file mode 100644 index 0000000..01ea2a1 --- /dev/null +++ b/pa_tests/patest_multi_sine.c @@ -0,0 +1,144 @@ +/* + * $Id$ + * patest_multi_out.c + * Play a different sine wave on each channels, + * using the Portable Audio api. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include "portaudio.h" + +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#define FREQ_INCR (300.0 / SAMPLE_RATE) +#define MAX_CHANNELS (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +typedef struct +{ + int numChannels; + double phases[MAX_CHANNELS]; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + int frameIndex, channelIndex; + int finished = 0; + (void) outTime; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) + { + for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) + { + /* Output sine wave on every channel. */ + *out++ = (float) sin(data->phases[channelIndex]); + + /* Play each channel at a higher frequency. */ + data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); + if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); + } + } + + return 0; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PortAudioStream *stream; + PaError err; + const PaDeviceInfo *pdi; + paTestData data = {0}; + printf("PortAudio Test: output sine wave on each channel.\n" ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE ); + data.numChannels = pdi->maxOutputChannels; + if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; + printf("Number of Channels = %d\n", data.numChannels ); + + err = Pa_OpenStream( + &stream, + paNoDevice, /* default input device */ + 0, /* no input */ + paFloat32, /* 32 bit floating point input */ + NULL, + OUTPUT_DEVICE, + data.numChannels, + paFloat32, /* 32 bit floating point output */ + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Hit ENTER to stop sound.\n"); + getchar(); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + Pa_CloseStream( stream ); + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} From e4861f46646d6de697e65d8f4ffae95e7e5f6a38 Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 21 Mar 2002 18:35:05 +0000 Subject: [PATCH 047/814] detect Win XP versus NT, 9x fix DBUG typo removed redundant problematic init of LARGE_INTEGER CurrentCount --- pa_win_wmme/pa_win_wmme.c | 78 ++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/pa_win_wmme/pa_win_wmme.c b/pa_win_wmme/pa_win_wmme.c index 13f6d83..70388da 100644 --- a/pa_win_wmme/pa_win_wmme.c +++ b/pa_win_wmme/pa_win_wmme.c @@ -49,6 +49,7 @@ PLB20010816 - pass process instead of thread to SetPriorityClass() PLB20010927 - use number of frames instead of real-time for CPULoad calculation. JM20020118 - prevent hung thread when buffers underflow. + PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount */ #include @@ -70,12 +71,15 @@ #define PA_TRACK_MEMORY (0) #define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ -#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ /* Switches for debugging. */ #define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ + /* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ #define PA_TRACE_RUN (0) #define PA_TRACE_START_STOP (1) + +#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ + #if PA_USE_HIGH_LATENCY #define PA_MIN_MSEC_PER_HOST_BUFFER (100) #define PA_MAX_MSEC_PER_HOST_BUFFER (300) /* Do not exceed unless user buffer exceeds */ @@ -90,11 +94,13 @@ #define PA_WIN_9X_LATENCY (200) #endif #define MIN_TIMEOUT_MSEC (1000) + /* ** Use higher latency for NT because it is even worse at real-time ** operation than Win9x. */ #define PA_WIN_NT_LATENCY (PA_WIN_9X_LATENCY * 2) +#define PA_WIN_WDM_LATENCY (PA_WIN_9X_LATENCY) #if PA_SIMULATE_UNDERFLOW static gUnderCallbackCounter = 0; @@ -104,7 +110,7 @@ static gUnderCallbackCounter = 0; #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) */ +#define DBUG(x) /* PRINT(x) /**/ #define DBUGX(x) /* PRINT(x) */ /************************************************* Definitions ********/ /************************************************************** @@ -187,7 +193,7 @@ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) } static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { - LARGE_INTEGER CurrentCount = { 0, 0 }; + LARGE_INTEGER CurrentCount; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* @@ -270,7 +276,7 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) if( id < sNumInputDevices ) { /* input device */ - int inputMmID = id - 1; /* WAVE_MAPPER is -1 so we start with WAVE_MAPPER */ + int inputMmID = PaDeviceIdToWinId(id); WAVEINCAPS wic; if( waveInGetDevCaps( inputMmID, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR ) goto error; @@ -328,7 +334,7 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) else if( id - sNumInputDevices < sNumOutputDevices ) { /* output device */ - int outputMmID = id - sNumInputDevices - 1; + int outputMmID = PaDeviceIdToWinId(id); WAVEOUTCAPS woc; if( waveOutGetDevCaps( outputMmID, &woc, sizeof( WAVEOUTCAPS ) ) != MMSYSERR_NOERROR ) goto error; @@ -348,13 +354,42 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) deviceInfo->maxOutputChannels = woc.wChannels; /* Sometimes a device can return a rediculously large number of channels. ** This happened with an SBLive card on a Windows ME box. - ** If that happens, then force it to 2 channels. PLB20010413 + ** It also happens on Win XP! */ if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) ) { - ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels )); +#if 1 deviceInfo->maxOutputChannels = 2; +#else + /* If channel max is goofy, then query for max channels. PLB20020228 + ** This doesn't seem to help. Disable code for now. Remove it later. + */ + ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d!", deviceInfo->maxOutputChannels )); + deviceInfo->maxOutputChannels = 0; + /* Attempt to find the correct maximum by querying the device. */ + for( i=2; i<16; i += 2 ) + { + WAVEFORMATEX wfx; + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nSamplesPerSec = 44100; + wfx.wBitsPerSample = 16; + wfx.cbSize = 0; /* ignored */ + wfx.nChannels = (WORD) i; + wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); + wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); + if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) + { + deviceInfo->maxOutputChannels = i; + } + else + { + break; + } + } +#endif + ERR_RPT((" Changed to %d.\n", deviceInfo->maxOutputChannels )); } + /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on the format flags. */ if( woc.dwFormats & WAVE_FORMAT_1M16 ||woc.dwFormats & WAVE_FORMAT_1S16 ) @@ -1103,8 +1138,8 @@ PaError PaHost_StartOutput( internalPortAudioStream *past ) goto error; } } - DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr)); error: + DBUG(("PaHost_StartOutput: wave returned mr = 0x%X.\n", mr)); return result; } /*************************************************************************/ @@ -1129,7 +1164,7 @@ PaError PaHost_StartInput( internalPortAudioStream *past ) } pahsc->pahsc_CurrentInputBuffer = 0; mr = waveInStart( pahsc->pahsc_HWaveIn ); - DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", hr)); + DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mr)); if( mr != MMSYSERR_NOERROR ) { result = paHostError; @@ -1374,7 +1409,6 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { char envbuf[PA_ENV_BUF_SIZE]; - DWORD hostVersion; DWORD hresult; int minLatencyMsec = 0; double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; @@ -1387,12 +1421,28 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) } else { - /* Set minimal latency based on whether NT or Win95. + /* Set minimal latency based on whether NT or other OS. * NT has higher latency. */ - hostVersion = GetVersion(); - /* High bit clear if NT */ - minLatencyMsec = ( (hostVersion & 0x80000000) == 0 ) ? PA_WIN_NT_LATENCY : PA_WIN_9X_LATENCY ; + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof( osvi ); + GetVersionEx( &osvi ); + DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); + DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); + DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); + /* Check for NT */ + if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) + { + minLatencyMsec = PA_WIN_NT_LATENCY; + } + else if(osvi.dwMajorVersion >= 5) + { + minLatencyMsec = PA_WIN_WDM_LATENCY; + } + else + { + minLatencyMsec = PA_WIN_9X_LATENCY; + } #if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); #endif From 1f71752e8b70c498c5355491720fdb3fecbe02f9 Mon Sep 17 00:00:00 2001 From: philburk Date: Tue, 26 Mar 2002 18:04:22 +0000 Subject: [PATCH 048/814] put ( void ) in prototype for Pa_CountDevices( void ) --- pa_common/portaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pa_common/portaudio.h b/pa_common/portaudio.h index 35c2bcc..fe05829 100644 --- a/pa_common/portaudio.h +++ b/pa_common/portaudio.h @@ -131,7 +131,7 @@ typedef unsigned long PaSampleFormat; typedef int PaDeviceID; #define paNoDevice -1 -int Pa_CountDevices(); +int Pa_CountDevices( void ); typedef struct { From e66425d00c2ee098989663b4adfea30b9fff5894 Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 28 Mar 2002 18:15:43 +0000 Subject: [PATCH 049/814] Use Interpolating sine lookup to eliminate differences in math lib performance between hosts. --- pa_tests/patest_maxsines.c | 56 ++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/pa_tests/patest_maxsines.c b/pa_tests/patest_maxsines.c index 646a77f..4a5c26b 100644 --- a/pa_tests/patest_maxsines.c +++ b/pa_tests/patest_maxsines.c @@ -40,20 +40,44 @@ #include "portaudio.h" #define MAX_SINES (500) +#define MAX_USAGE (0.8) #define SAMPLE_RATE (44100) +#define FREQ_TO_PHASE_INC(freq) (freq/(float)SAMPLE_RATE) + +#define MIN_PHASE_INC FREQ_TO_PHASE_INC(200.0f) +#define MAX_PHASE_INC (MIN_PHASE_INC * (1 << 5)) + #define FRAMES_PER_BUFFER (512) #ifndef M_PI #define M_PI (3.14159265) #endif #define TWOPI (M_PI * 2.0) +#define TABLE_SIZE (512) + typedef struct paTestData { int numSines; + float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */ double phases[MAX_SINES]; } paTestData; +/* Convert phase between and 1.0 to sine value + * using linear interpolation. + */ +float LookupSine( paTestData *data, float phase ); +float LookupSine( paTestData *data, float phase ) +{ + float fIndex = phase*TABLE_SIZE; + int index = (int) fIndex; + float fract = fIndex - index; + float lo = data->sine[index]; + float hi = data->sine[index+1]; + float val = lo + fract*(hi-lo); + return val; +} + /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). @@ -65,33 +89,39 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; float outSample; + float scaler; + int numForScale; unsigned long i; int j; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; +/* Detemine amplitude scaling factor */ + numForScale = data->numSines; + if( numForScale < 8 ) numForScale = 8; /* prevent pops at beginning */ + scaler = 1.0f / numForScale; + for( i=0; inumSines; j++ ) { /* Advance phase of next oscillator. */ phase = data->phases[j]; phase += phaseInc; - if( phase > TWOPI ) phase -= TWOPI; + if( phase >= 1.0 ) phase -= 1.0; - phaseInc *= 1.02; - if( phaseInc > 0.5 ) phaseInc *= 0.5; - - /* This is not a very efficient way to calc sines. */ - output += (float) sin( phase ); + output += LookupSine(data, phase); data->phases[j] = phase; + + phaseInc *= 1.02; + if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC; } - outSample = (float) (output / data->numSines); + outSample = (float) (output * scaler); *out++ = outSample; /* Left */ *out++ = outSample; /* Right */ } @@ -102,12 +132,19 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, int main(void); int main(void) { + int i; PortAudioStream *stream; PaError err; paTestData data = {0}; double load; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; i Date: Fri, 29 Mar 2002 21:23:53 +0000 Subject: [PATCH 050/814] Change doubles to floats to improve type consistency. --- pa_tests/patest_maxsines.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pa_tests/patest_maxsines.c b/pa_tests/patest_maxsines.c index 4a5c26b..7745be8 100644 --- a/pa_tests/patest_maxsines.c +++ b/pa_tests/patest_maxsines.c @@ -59,7 +59,7 @@ typedef struct paTestData { int numSines; float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */ - double phases[MAX_SINES]; + float phases[MAX_SINES]; } paTestData; @@ -105,8 +105,8 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, for( i=0; inumSines; j++ ) { /* Advance phase of next oscillator. */ @@ -117,7 +117,7 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, output += LookupSine(data, phase); data->phases[j] = phase; - phaseInc *= 1.02; + phaseInc *= 1.02f; if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC; } From 1f3da172ac47625220c36713588a6eb53c43cf85 Mon Sep 17 00:00:00 2001 From: philburk Date: Sat, 30 Mar 2002 01:47:38 +0000 Subject: [PATCH 051/814] Fixed Pa_GetCPULoad() --- pa_mac_core/pa_mac_core.c | 48 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c index b7a33b0..760aa28 100644 --- a/pa_mac_core/pa_mac_core.c +++ b/pa_mac_core/pa_mac_core.c @@ -49,7 +49,8 @@ Check for invalid sample rates and return an error. Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally. Better error checking for invalid channel counts and invalid devices. - + 3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers. + TODO: O- how do mono output? O- FIFO between input and output callbacks if different devices, like in pa_mac.c @@ -75,8 +76,8 @@ O- FIFO between input and output callbacks if different devices, like in pa_mac. #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) */ -#define DBUGX(x) /* PRINT(x) */ +#define DBUG(x) /* PRINT(x) /**/ +#define DBUGX(x) /* PRINT(x) /**/ // define value of isInput passed to CoreAudio routines #define IS_INPUT (true) @@ -97,8 +98,8 @@ typedef struct PaHostSoundControl int pahsc_FramesPerHostBuffer; int pahsc_UserBuffersPerHostBuffer; /* For measuring CPU utilization. */ - struct timeval pahsc_EntryTime; - double pahsc_InverseMicrosPerBuffer; /* 1/Microseconds of real-time audio per user buffer. */ + struct timeval pahsc_EntryTime; + double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */ } PaHostSoundControl; @@ -187,7 +188,7 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { usecsElapsed = SubtractTime_AminusB( ¤tTime, &pahsc->pahsc_EntryTime ); /* Use inverse because it is faster than the divide. */ - newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerBuffer; + newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer; past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + (LOWPASS_COEFFICIENT_1 * newUsage); @@ -632,10 +633,8 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL AudioBufferList* outOutputData ) { PaError result = 0; - char *inputNativeBufferfPtr; - char *outputNativeBufferfPtr; - int gotInput = 0; - int gotOutput = 0; + char *inputNativeBufferfPtr = NULL; + char *outputNativeBufferfPtr = NULL; int i; int buffersProcessed = 0; int done = 0; @@ -651,20 +650,15 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL Pa_StartUsageCalculation( past ); /* If we are using output, then we need an empty output buffer. */ - gotOutput = 0; if( past->past_NumOutputChannels > 0 ) { - outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData, - gotOutput = 1; + outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData; } /* If we are using input, then we need a full input buffer. */ - gotInput = 0; - inputNativeBufferfPtr = NULL; if( past->past_NumInputChannels > 0 ) { - inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData, - gotInput = 1; + inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData; } buffersProcessed += 1; @@ -674,7 +668,7 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL { if( done ) { - if( gotOutput ) + if( outputNativeBufferfPtr ) { /* Clear remainder of wave buffer if we are waiting for stop. */ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); @@ -687,8 +681,8 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL result = PaConvert_Process( past, inputNativeBufferfPtr, outputNativeBufferfPtr ); if( result != 0) done = 1; } - if( gotInput ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer; - if( gotOutput) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer; + if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer; + if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer; } Pa_EndUsageCalculation( past ); @@ -996,7 +990,7 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) } /* Setup constants for CPU load measurement. */ - pahsc->pahsc_InverseMicrosPerBuffer = past->past_SampleRate / (1000000.0 * past->past_FramesPerUserBuffer); + pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer); /* ------------------ OUTPUT */ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) @@ -1202,12 +1196,14 @@ PaError PaHost_Term( void ) /*************************************************************************/ void Pa_Sleep( long msec ) { - /* struct timeval timeout; - timeout.tv_sec = msec / 1000; - timeout.tv_usec = (msec % 1000) * 1000; - select( 0, NULL, NULL, NULL, &timeout ); - */ +#if 0 + struct timeval timeout; + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + select( 0, NULL, NULL, NULL, &timeout ); +#else usleep( msec * 1000 ); +#endif } /************************************************************************* From bd907d6139c0f7f7633beda515e78a8d0452c593 Mon Sep 17 00:00:00 2001 From: stephane Date: Tue, 9 Apr 2002 08:36:09 +0000 Subject: [PATCH 052/814] Correct error code management in PaHost_Term, removes various compiler warning --- pa_asio/pa_asio.cpp | 343 ++++++++++++++++++++++---------------------- 1 file changed, 174 insertions(+), 169 deletions(-) diff --git a/pa_asio/pa_asio.cpp b/pa_asio/pa_asio.cpp index 70cd383..6fef65f 100644 --- a/pa_asio/pa_asio.cpp +++ b/pa_asio/pa_asio.cpp @@ -40,19 +40,20 @@ 08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when the stream is stopped : Stephane Letz 08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when - the stream is stopped : Stephane Letz + the stream is stopped : Stephane Letz 10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that - respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz + respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz 10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz 10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil 10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk 10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz 11-06-01 Rename functions : Stephane Letz 11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz - 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk - 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz + 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk + 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz - 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows: Stephane Letz + 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz + 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz TO DO : @@ -211,51 +212,51 @@ static bool swap = false; #endif // Prototypes -void bufferSwitch(long index, ASIOBool processNow); -ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); -void sampleRateChanged(ASIOSampleRate sRate); -long asioMessages(long selector, long value, void* message, double* opt); +static void bufferSwitch(long index, ASIOBool processNow); +static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); +static void sampleRateChanged(ASIOSampleRate sRate); +static long asioMessages(long selector, long value, void* message, double* opt); static void Pa_StartUsageCalculation( internalPortAudioStream *past ); static void Pa_EndUsageCalculation( internalPortAudioStream *past ); -void Pa_ASIO_Convert_Inter_Input( +static void Pa_ASIO_Convert_Inter_Input( ASIOBufferInfo* nativeBuffer, void* inputBuffer, - short NumInputChannels, - short NumOuputChannels, - short framePerBuffer, - short hostFrameOffset, - short userFrameOffset, + long NumInputChannels, + long NumOuputChannels, + long framePerBuffer, + long hostFrameOffset, + long userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, - short index); + long index); -void Pa_ASIO_Convert_Inter_Output( +static void Pa_ASIO_Convert_Inter_Output( ASIOBufferInfo* nativeBuffer, void* outputBuffer, - short NumInputChannels, - short NumOuputChannels, - short framePerBuffer, - short hostFrameOffset, - short userFrameOffset, + long NumInputChannels, + long NumOuputChannels, + long framePerBuffer, + long hostFrameOffset, + long userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, - short index); + long index); - void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, +static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, ASIOSampleType nativeFormat, - short NumInputChannels, - short NumOuputChannels, - int index, - int hostFrameOffset, - int frames); + long NumInputChannels, + long NumOuputChannels, + long index, + long hostFrameOffset, + long frames); -void Pa_ASIO_Callback_Input(long index); -void Pa_ASIO_Callback_Output(long index, long framePerBuffer); -void Pa_ASIO_Callback_End(); -void Pa_ASIO_Clear_User_Buffers(); +static void Pa_ASIO_Callback_Input(long index); +static void Pa_ASIO_Callback_Output(long index, long framePerBuffer); +static void Pa_ASIO_Callback_End(); +static void Pa_ASIO_Clear_User_Buffers(); // Some external references extern AsioDrivers* asioDrivers ; @@ -283,7 +284,7 @@ unsigned long get_sys_reference_time(); #endif -bool Pa_ASIO_loadAsioDriver(char *name) +static bool Pa_ASIO_loadAsioDriver(char *name) { #ifdef WINDOWS CoInitialize(0); @@ -294,11 +295,11 @@ bool Pa_ASIO_loadAsioDriver(char *name) // Utilities for alignement buffer size computation -int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);} -int PPCM (int a, int b) {return (a*b) / PGCD (a,b);} +static int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);} +static int PPCM (int a, int b) {return (a*b) / PGCD (a,b);} // Takes the size of host buffer and user buffer : returns the number of frames needed for buffer alignement -int Pa_ASIO_CalcFrameShift (int M, int N) +static int Pa_ASIO_CalcFrameShift (int M, int N) { int res = 0; for (int i = M; i < PPCM (M,N) ; i+=M) { res = max (res, i%N); } @@ -518,7 +519,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) //---------------------------------------------------------------------------------- // TAKEN FROM THE ASIO SDK: -void sampleRateChanged(ASIOSampleRate sRate) +static void sampleRateChanged(ASIOSampleRate sRate) { // do whatever you need to do if the sample rate changed // usually this only happens during external sync. @@ -610,13 +611,13 @@ long asioMessages(long selector, long value, void* message, double* opt) #endif -ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow) +static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow) { // the actual processing callback. // Beware that this is normally in a seperate thread, hence be sure that you take care // about thread synchronization. This is omitted here for simplicity. - static processedSamples = 0; + // static processedSamples = 0; int result = 0; // store the timeInfo for later use @@ -760,7 +761,7 @@ inline static long Pa_TriangularDither( void ) // TO BE COMPLETED WITH ALL SUPPORTED PA SAMPLE TYPES //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Input_Int16_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Input_Int16_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -780,7 +781,7 @@ inline static long Pa_TriangularDither( void ) } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Input_Int32_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap) +static void Input_Int32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap) { long temp; int i,j; @@ -800,17 +801,17 @@ inline static long Pa_TriangularDither( void ) //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE TESTED - void Input_Float32_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap) +static void Input_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap) { - long temp; + unsigned long temp; int i,j; for( j=0; j>16; + *userBufPtr = (short)(temp>>16); userBufPtr += NumInputChannels; } } @@ -928,7 +929,7 @@ inline static long Pa_TriangularDither( void ) temp = (temp >> 1) + Pa_TriangularDither(); temp = temp >> 15; temp = (short) ClipShort(temp); - *userBufPtr = temp; + *userBufPtr = (short)temp; userBufPtr += NumInputChannels; } } @@ -938,19 +939,19 @@ inline static long Pa_TriangularDither( void ) //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE TESTED - void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) +static void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) { - long temp; + unsigned long temp; int i,j; if( flags & paDitherOff ) { for( j=0; j> 16); if (swap) temp = SwapShort(temp); - asioBufPtr[i] = temp; + asioBufPtr[i] = (short)temp; userBufPtr += NumOuputChannels; } } @@ -1392,7 +1394,7 @@ inline static long Pa_TriangularDither( void ) temp = temp >> 15; temp = (short) ClipShort(temp); if (swap) temp = SwapShort(temp); - asioBufPtr[i] = temp; + asioBufPtr[i] = (short)temp; userBufPtr += NumOuputChannels; } } @@ -1400,7 +1402,7 @@ inline static long Pa_TriangularDither( void ) } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) +static void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) { long temp; int i,j; @@ -1422,7 +1424,7 @@ inline static long Pa_TriangularDither( void ) //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE CHECKED - void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) +static void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) { long temp; int i,j; @@ -1442,7 +1444,7 @@ inline static long Pa_TriangularDither( void ) } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,bool swap) +static void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,bool swap) { long temp; int i,j; @@ -1455,14 +1457,14 @@ inline static long Pa_TriangularDither( void ) { temp = *userBufPtr; if (swap) temp = SwapShort(temp); - asioBufPtr[i] = temp; + asioBufPtr[i] = (short)temp; userBufPtr += NumOuputChannels; } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1483,7 +1485,7 @@ inline static long Pa_TriangularDither( void ) //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE CHECKED - void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1501,7 +1503,7 @@ inline static long Pa_TriangularDither( void ) } } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1514,14 +1516,14 @@ inline static long Pa_TriangularDither( void ) { temp = (short)(*userBufPtr)<<8; if (swap) temp = SwapShort(temp); - asioBufPtr[i] = temp; + asioBufPtr[i] = (short)temp; userBufPtr += NumOuputChannels; } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1543,7 +1545,7 @@ inline static long Pa_TriangularDither( void ) //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE CHECKED - void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1562,7 +1564,7 @@ inline static long Pa_TriangularDither( void ) } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1575,14 +1577,14 @@ inline static long Pa_TriangularDither( void ) { temp = ((short)((*userBufPtr) - 0x80)) << 8; if (swap) temp = SwapShort(temp); - asioBufPtr[i] = temp; + asioBufPtr[i] = (short)temp; userBufPtr += NumOuputChannels; } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1604,7 +1606,7 @@ inline static long Pa_TriangularDither( void ) //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE CHECKED - void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) +static void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1623,7 +1625,7 @@ inline static long Pa_TriangularDither( void ) } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, int frames, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset) +static void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset) { int i,j; @@ -1634,7 +1636,7 @@ inline static long Pa_TriangularDither( void ) } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, int frames, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset) +static void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset) { int i,j; @@ -1646,7 +1648,7 @@ inline static long Pa_TriangularDither( void ) //------------------------------------------------------------------------------------------------------------------------------------------------------- -void Pa_ASIO_Adaptor_Init() +static void Pa_ASIO_Adaptor_Init() { if (asioDriverInfo.past->past_FramesPerUserBuffer <= asioDriverInfo.past_FramesPerHostBuffer) { asioDriverInfo.pahsc_hostOutputBufferFrameOffset = asioDriverInfo.pahsc_OutputBufferOffset; @@ -1662,7 +1664,7 @@ void Pa_ASIO_Adaptor_Init() //------------------------------------------------------------------------------------------------------------------------------------------------------- // FIXME : optimization for Input only or output only modes (really necessary ??) -void Pa_ASIO_Callback_Input( long index) +static void Pa_ASIO_Callback_Input( long index) { internalPortAudioStream *past = asioDriverInfo.past; long framesInputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer; // number of frames available into the host input buffer @@ -1760,7 +1762,7 @@ void Pa_ASIO_Callback_Input( long index) } //------------------------------------------------------------------------------------------------------------------------------------------------------- -void Pa_ASIO_Callback_Output(long index, long framePerBuffer) +static void Pa_ASIO_Callback_Output(long index, long framePerBuffer) { internalPortAudioStream *past = asioDriverInfo.past; @@ -1787,14 +1789,14 @@ void Pa_ASIO_Callback_Output(long index, long framePerBuffer) } } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Pa_ASIO_Callback_End() +static void Pa_ASIO_Callback_End() { /* Empty ASIO ouput : write offset */ asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0; } //------------------------------------------------------------------------------------------------------------------------------------------------------- -void Pa_ASIO_Clear_User_Buffers() +static void Pa_ASIO_Clear_User_Buffers() { if( asioDriverInfo.past->past_InputBuffer != NULL ) { @@ -1807,13 +1809,13 @@ void Pa_ASIO_Clear_User_Buffers() } //------------------------------------------------------------------------------------------------------------------------------------------------------- - void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, + static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, ASIOSampleType nativeFormat, - short NumInputChannels, - short NumOuputChannels, - int index, - int hostFrameOffset, - int frames) + long NumInputChannels, + long NumOuputChannels, + long index, + long hostFrameOffset, + long frames) { switch (nativeFormat) { @@ -1853,18 +1855,18 @@ void Pa_ASIO_Clear_User_Buffers() //--------------------------------------------------------------------------------------- -void Pa_ASIO_Convert_Inter_Input( +static void Pa_ASIO_Convert_Inter_Input( ASIOBufferInfo* nativeBuffer, void* inputBuffer, - short NumInputChannels, - short NumOuputChannels, - short framePerBuffer, - short hostFrameOffset, - short userFrameOffset, + long NumInputChannels, + long NumOuputChannels, + long framePerBuffer, + long hostFrameOffset, + long userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, - short index) + long index) { if((NumInputChannels > 0) && (nativeBuffer != NULL)) @@ -1878,22 +1880,22 @@ void Pa_ASIO_Convert_Inter_Input( switch (nativeFormat) { case ASIOSTInt16LSB: - Input_Int16_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap); + Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap); break; case ASIOSTInt16MSB: - Input_Int16_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTInt32LSB: - Input_Int32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); + Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); break; case ASIOSTInt32MSB: - Input_Int32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture - Input_Float32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); + Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); break; case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture - Input_Float32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTInt24LSB: // used for 20 bits as well @@ -2133,20 +2135,20 @@ void Pa_ASIO_Convert_Inter_Input( //--------------------------------------------------------------------------------------- -void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer, +static void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer, void* outputBuffer, - short NumInputChannels, - short NumOuputChannels, - short framePerBuffer, - short hostFrameOffset, - short userFrameOffset, + long NumInputChannels, + long NumOuputChannels, + long framePerBuffer, + long hostFrameOffset, + long userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, - short index) + long index) { - if((NumOuputChannels > 0) && (nativeBuffer != NULL)) + if((NumOuputChannels > 0) && (nativeBuffer != NULL)) { /* Convert from PA format to native format */ @@ -2427,7 +2429,7 @@ static PaError Pa_ASIO_loadDevice (long device) } //--------------------------------------------------- -static int GetHighestBitPosition( unsigned long n ) +static int GetHighestBitPosition (unsigned long n) { int pos = -1; while( n != 0 ) @@ -2438,10 +2440,10 @@ static int GetHighestBitPosition( unsigned long n ) return pos; } -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------ static int GetFirstMultiple(long min, long val ){ return ((min + val - 1) / val) * val; } -//----------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------ static int GetFirstPossibleDivisor(long max, long val ) { for (int i = 2; i < 20; i++) {if (((val%i) == 0) && ((val/i) <= max)) return (val/i); } @@ -2563,26 +2565,29 @@ PaError PaHost_Term( void ) int i; PaDeviceInfo *dev; double *rates; - PaError result = paNoError; - - /* Free allocated sample rate arrays and names*/ - for( i=0; isampleRates; - if((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double)); - dev->sampleRates = NULL; - if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32); - dev->name = NULL; - } - - sNumDevices = 0; - - /* Dispose : if not done by Pa_CloseStream */ - if(ASIODisposeBuffers() != ASE_OK) result = paHostError; - if(ASIOExit() != ASE_OK) result = paHostError; - - /* remove the loaded ASIO driver */ - asioDrivers->removeCurrentDriver(); + PaError result = paNoError; + + if (sNumDevices > 0) { + + /* Free allocated sample rate arrays and names*/ + for( i=0; isampleRates; + if((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double)); + dev->sampleRates = NULL; + if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32); + dev->name = NULL; + } + + sNumDevices = 0; + + /* Dispose : if not done by Pa_CloseStream */ + if(ASIODisposeBuffers() != ASE_OK) result = paHostError; + if(ASIOExit() != ASE_OK) result = paHostError; + + /* remove the loaded ASIO driver */ + asioDrivers->removeCurrentDriver(); + } return result; } From c406a816c8746136d980b3b4addb59c57ecfbffa Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 10 Apr 2002 18:18:36 +0000 Subject: [PATCH 053/814] renamed PaHostSoundControl to PaWMMEStreamData removed pahsc_ from stream data fields renamed pahsc to wmmeStreamData renamed past to stream or internalStream (ad-hoc at this stage) changed trace text in PaHost_BackgroundManager() to display correct function name replaced / 1000.0 with * 0.001 in 2 places consistentified pre-function comment formatting added one line break after variable declarations in function bodies added check for valid past_DeviceData to Pa_StreamTime() added PaHost_GetStreamRepresentation, PaHost_GetWMMEStreamData and updated error checking code to use them factored Pa_InitializeCpuUsageScalar into separate module factored PaHost_AllocateWMMEStreamData/PaHost_FreeWMMEStreamData --- pa_win_wmme/pa_win_wmme.c | 982 +++++++++++++++++++++----------------- 1 file changed, 543 insertions(+), 439 deletions(-) diff --git a/pa_win_wmme/pa_win_wmme.c b/pa_win_wmme/pa_win_wmme.c index 70388da..1e21d58 100644 --- a/pa_win_wmme/pa_win_wmme.c +++ b/pa_win_wmme/pa_win_wmme.c @@ -40,6 +40,7 @@ /* Modification History: PLB = Phil Burk JM = Julien Maillard + RDB = Ross Bencina PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer) PLB20010413 - check for excessive numbers of channels PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC @@ -50,6 +51,7 @@ PLB20010927 - use number of frames instead of real-time for CPULoad calculation. JM20020118 - prevent hung thread when buffers underflow. PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount + RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init */ #include @@ -117,45 +119,45 @@ static gUnderCallbackCounter = 0; * Structure for internal host specific stream data. * This is allocated on a per stream basis. */ -typedef struct PaHostSoundControl +typedef struct PaWMMEStreamData { /* Input -------------- */ - HWAVEIN pahsc_HWaveIn; - WAVEHDR *pahsc_InputBuffers; - int pahsc_CurrentInputBuffer; - int pahsc_BytesPerHostInputBuffer; - int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */ + HWAVEIN hWaveIn; + WAVEHDR *inputBuffers; + int currentInputBuffer; + int bytesPerHostInputBuffer; + int bytesPerUserInputBuffer; /* native buffer size in bytes */ /* Output -------------- */ - HWAVEOUT pahsc_HWaveOut; - WAVEHDR *pahsc_OutputBuffers; - int pahsc_CurrentOutputBuffer; - int pahsc_BytesPerHostOutputBuffer; - int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */ + HWAVEOUT hWaveOut; + WAVEHDR *outputBuffers; + int currentOutputBuffer; + int bytesPerHostOutputBuffer; + int bytesPerUserOutputBuffer; /* native buffer size in bytes */ /* Run Time -------------- */ - PaTimestamp pahsc_FramesPlayed; - long pahsc_LastPosition; /* used to track frames played. */ + PaTimestamp framesPlayed; + long lastPosition; /* used to track frames played. */ /* For measuring CPU utilization. */ - LARGE_INTEGER pahsc_EntryCount; - double pahsc_InverseTicksPerHostBuffer; + LARGE_INTEGER entryCount; + double inverseTicksPerHostBuffer; /* Init Time -------------- */ - int pahsc_NumHostBuffers; - int pahsc_FramesPerHostBuffer; - int pahsc_UserBuffersPerHostBuffer; - CRITICAL_SECTION pahsc_StreamLock; /* Mutext to prevent threads from colliding. */ - INT pahsc_StreamLockInited; + int numHostBuffers; + int framesPerHostBuffer; + int userBuffersPerHostBuffer; + CRITICAL_SECTION streamLock; /* Mutext to prevent threads from colliding. */ + INT streamLockInited; #if PA_USE_TIMER_CALLBACK - BOOL pahsc_IfInsideCallback; /* Test for reentrancy. */ - MMRESULT pahsc_TimerID; + BOOL ifInsideCallback; /* Test for reentrancy. */ + MMRESULT timerID; #else - HANDLE pahsc_AbortEvent; - int pahsc_AbortEventInited; - HANDLE pahsc_BufferEvent; - int pahsc_BufferEventInited; - HANDLE pahsc_EngineThread; - DWORD pahsc_EngineThreadID; + HANDLE abortEvent; + int abortEventInited; + HANDLE bufferEvent; + int bufferEventInited; + HANDLE engineThread; + DWORD engineThreadID; #endif } -PaHostSoundControl; +PaWMMEStreamData; /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ static int sNumInputDevices = 0; @@ -177,41 +179,114 @@ static Pa_QueryDevices( void ); static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); -static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc ); +static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ); static PaError PaHost_BackgroundManager( internalPortAudioStream *past ); static void *PaHost_AllocateTrackedMemory( long numBytes ); static void PaHost_FreeTrackedMemory( void *addr ); -/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ -static void Pa_StartUsageCalculation( internalPortAudioStream *past ) + +/* + FIXME: PaHost_GetStreamRepresentation() should be migrated to pa_lib.c +*/ +static internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream ) { - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; - /* Query system timer for usage analysis and to prevent overuse of CPU. */ - QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); + internalPortAudioStream* result = (internalPortAudioStream*) stream; + + if( result == NULL || result->past_Magic != PA_MAGIC ) + return NULL; + else + return result; } -static void Pa_EndUsageCalculation( internalPortAudioStream *past ) +/*******************************************************************/ +static PaError PaHost_AllocateWMMEStreamData( internalPortAudioStream *stream ) +{ + PaError result = paNoError; + PaWMMEStreamData *wmmeStreamData; + + wmmeStreamData = (PaWMMEStreamData *) PaHost_AllocateFastMemory(sizeof(PaWMMEStreamData)); /* MEM */ + if( wmmeStreamData == NULL ) + { + result = paInsufficientMemory; + goto error; + } + memset( wmmeStreamData, 0, sizeof(PaWMMEStreamData) ); + stream->past_DeviceData = (void *) wmmeStreamData; + + return result; + +error: + return result; +} + +/*******************************************************************/ +static void PaHost_FreeWMMEStreamData( internalPortAudioStream *internalStream ) +{ + PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) internalStream->past_DeviceData; + + PaHost_FreeFastMemory( wmmeStreamData, sizeof(PaWMMEStreamData) ); /* MEM */ + internalStream->past_DeviceData = NULL; +} +/*************************************************************************/ +static PaWMMEStreamData* PaHost_GetWMMEStreamData( internalPortAudioStream* internalStream ) +{ + PaWMMEStreamData *result = NULL; + + if( internalStream != NULL ) + { + result = (PaWMMEStreamData *) internalStream->past_DeviceData; + } + return result; +} +/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ +/* FIXME: the cpu usage code should be factored out into a common module */ +static void Pa_InitializeCpuUsageScalar( internalPortAudioStream *stream ) +{ + PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + + LARGE_INTEGER frequency; + if( QueryPerformanceFrequency( &frequency ) == 0 ) + { + wmmeStreamData->inverseTicksPerHostBuffer = 0.0; + } + else + { + wmmeStreamData->inverseTicksPerHostBuffer = stream->past_SampleRate / + ( (double)frequency.QuadPart * stream->past_FramesPerUserBuffer * wmmeStreamData->userBuffersPerHostBuffer ); + DBUG(("inverseTicksPerHostBuffer = %g\n", wmmeStreamData->inverseTicksPerHostBuffer )); + } +} +static void Pa_StartUsageCalculation( internalPortAudioStream *stream ) +{ + PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + + if( wmmeStreamData == NULL ) return; + /* Query system timer for usage analysis and to prevent overuse of CPU. */ + QueryPerformanceCounter( &wmmeStreamData->entryCount ); +} +static void Pa_EndUsageCalculation( internalPortAudioStream *stream ) { LARGE_INTEGER CurrentCount; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; + PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + + if( wmmeStreamData == NULL ) return; /* - ** Measure CPU utilization during this callback. Note that this calculation - ** assumes that we had the processor the whole time. - */ + * Measure CPU utilization during this callback. Note that this calculation + * assumes that we had the processor the whole time. + */ #define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) if( QueryPerformanceCounter( &CurrentCount ) ) { - LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; - double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerHostBuffer; - past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + - (LOWPASS_COEFFICIENT_1 * newUsage); + LONGLONG InsideCount = CurrentCount.QuadPart - wmmeStreamData->entryCount.QuadPart; + double newUsage = InsideCount * wmmeStreamData->inverseTicksPerHostBuffer; + stream->past_Usage = (LOWPASS_COEFFICIENT_0 * stream->past_Usage) + + (LOWPASS_COEFFICIENT_1 * newUsage); } } /****************************************** END CPU UTILIZATION *******/ +/* FIXME: this function should be renamed */ static PaError Pa_QueryDevices( void ) { int numBytes; @@ -229,7 +304,7 @@ static PaError Pa_QueryDevices( void ) if( sDevicePtrs == NULL ) return paInsufficientMemory; return paNoError; } -/************************************************************************************/ +/*************************************************************************/ long Pa_GetHostError() { return sPaHostError; @@ -241,12 +316,12 @@ int Pa_CountDevices() return sNumDevices; } /************************************************************************* -** If a PaDeviceInfo structure has not already been created, -** then allocate one and fill it in for the selected device. -** -** We create one extra input and one extra output device for the WAVE_MAPPER. -** [Does anyone know how to query the default device and get its name?] -*/ + * If a PaDeviceInfo structure has not already been created, + * then allocate one and fill it in for the selected device. + * + * We create one extra input and one extra output device for the WAVE_MAPPER. + * [Does anyone know how to query the default device and get its name?] + */ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { #define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */ @@ -296,9 +371,9 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) deviceInfo->name = s; deviceInfo->maxInputChannels = wic.wChannels; /* Sometimes a device can return a rediculously large number of channels. - ** This happened with an SBLive card on a Windows ME box. - ** If that happens, then force it to 2 channels. PLB20010413 - */ + * This happened with an SBLive card on a Windows ME box. + * If that happens, then force it to 2 channels. PLB20010413 + */ if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) ) { ERR_RPT(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels )); @@ -353,17 +428,17 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) deviceInfo->name = s; deviceInfo->maxOutputChannels = woc.wChannels; /* Sometimes a device can return a rediculously large number of channels. - ** This happened with an SBLive card on a Windows ME box. - ** It also happens on Win XP! - */ + * This happened with an SBLive card on a Windows ME box. + * It also happens on Win XP! + */ if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) ) { #if 1 deviceInfo->maxOutputChannels = 2; #else /* If channel max is goofy, then query for max channels. PLB20020228 - ** This doesn't seem to help. Disable code for now. Remove it later. - */ + * This doesn't seem to help. Disable code for now. Remove it later. + */ ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d!", deviceInfo->maxOutputChannels )); deviceInfo->maxOutputChannels = 0; /* Attempt to find the correct maximum by querying the device. */ @@ -418,6 +493,7 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) } sDevicePtrs[ id ] = deviceInfo; return deviceInfo; + error: PaHost_FreeTrackedMemory( sampleRates ); /* MEM */ PaHost_FreeTrackedMemory( deviceInfo ); /* MEM */ @@ -425,15 +501,15 @@ error: return NULL; } /************************************************************************* -** Returns recommended device ID. -** On the PC, the recommended device can be specified by the user 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 ID by using -** the supplied application "pa_devs". -*/ + * Returns recommended device ID. + * On the PC, the recommended device can be specified by the user 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 ID by using + * the supplied application "pa_devs". + */ #define PA_ENV_BUF_SIZE (32) #define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE") #define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE") @@ -442,6 +518,7 @@ static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) DWORD hresult; char envbuf[PA_ENV_BUF_SIZE]; PaDeviceID recommendedID = paNoDevice; + /* Let user determine default device by setting environment variable. */ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) @@ -459,11 +536,12 @@ static PaError Pa_MaybeQueryDevices( void ) return 0; } /********************************************************************** -** Check for environment variable, else query devices and use result. -*/ + * Check for environment variable, else query devices and use result. + */ PaDeviceID Pa_GetDefaultInputDeviceID( void ) { PaError result; + result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); if( result < 0 ) { @@ -476,6 +554,7 @@ PaDeviceID Pa_GetDefaultInputDeviceID( void ) PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { PaError result; + result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); if( result < 0 ) { @@ -486,11 +565,11 @@ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) return result; } /********************************************************************** -** Initialize Host dependant part of API. -*/ + * Initialize Host dependant part of API. + */ PaError PaHost_Init( void ) { - + #if PA_TRACK_MEMORY PRINT(("PaHost_Init: sNumAllocations = %d\n", sNumAllocations )); #endif @@ -502,22 +581,22 @@ PaError PaHost_Init( void ) } /********************************************************************** -** Check WAVE buffers to see if they are done. -** Fill any available output buffers and use any available -** input buffers by calling user callback. -** -** This routine will loop until: -** user callback returns !=0 OR -** all output buffers are filled OR -** past->past_StopSoon is set OR -** an error occurs when calling WMME. -** -** Returns >0 when user requests a stop, <0 on error. -** -*/ -static PaError Pa_TimeSlice( internalPortAudioStream *past ) + * Check WAVE buffers to see if they are done. + * Fill any available output buffers and use any available + * input buffers by calling user callback. + * + * This routine will loop until: + * user callback returns !=0 OR + * all output buffers are filled OR + * past->past_StopSoon is set OR + * an error occurs when calling WMME. + * + * Returns >0 when user requests a stop, <0 on error. + * + */ +static PaError Pa_TimeSlice( internalPortAudioStream *stream ) { - PaError result = 0; + PaError result = paNoError; long bytesEmpty = 0; long bytesFilled = 0; long buffersEmpty = 0; @@ -529,17 +608,18 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past ) int i; int buffersProcessed = 0; int done = 0; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paInternalError; + PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - past->past_NumCallbacks += 1; + if( wmmeStreamData == NULL ) return paInternalError; + + stream->past_NumCallbacks += 1; #if PA_TRACE_RUN - AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks ); + AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", stream->past_NumCallbacks ); #endif /* JM20020118 - prevent hung thread when buffers underflow. */ /* while( !done ) /* BAD */ - while( !done && !past->past_StopSoon ) /* GOOD */ + while( !done && !stream->past_StopSoon ) /* GOOD */ { #if PA_SIMULATE_UNDERFLOW if(gUnderCallbackCounter++ == UNDER_SLEEP_AT) @@ -551,29 +631,29 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past ) /* If we are using output, then we need an empty output buffer. */ gotOutput = 0; outBufPtr = NULL; - if( past->past_NumOutputChannels > 0 ) + if( stream->past_NumOutputChannels > 0 ) { - if((pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ].dwFlags & WHDR_DONE) == 0) + if((wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].dwFlags & WHDR_DONE) == 0) { break; /* If none empty then bail and try again later. */ } else { - outBufPtr = pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ].lpData; + outBufPtr = wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].lpData; gotOutput = 1; } } /* Use an input buffer if one is available. */ gotInput = 0; inBufPtr = NULL; - if( ( past->past_NumInputChannels > 0 ) && - (pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ].dwFlags & WHDR_DONE) ) + if( ( stream->past_NumInputChannels > 0 ) && + (wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].dwFlags & WHDR_DONE) ) { - inBufPtr = pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ].lpData; + inBufPtr = wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].lpData; gotInput = 1; #if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: got input buffer at ", (int)inBufPtr ); - AddTraceMessage("Pa_TimeSlice: got input buffer # ", pahsc->pahsc_CurrentInputBuffer ); + AddTraceMessage("Pa_TimeSlice: got input buffer # ", wmmeStreamData->currentInputBuffer ); #endif } @@ -582,8 +662,8 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past ) buffersProcessed += 1; /* Each Wave buffer contains multiple user buffers so do them all now. */ /* Base Usage on time it took to process one host buffer. */ - Pa_StartUsageCalculation( past ); - for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) + Pa_StartUsageCalculation( stream ); + for( i=0; iuserBuffersPerHostBuffer; i++ ) { if( done ) { @@ -591,24 +671,24 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past ) { /* Clear remainder of wave buffer if we are waiting for stop. */ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); - memset( outBufPtr, 0, pahsc->pahsc_BytesPerUserOutputBuffer ); + memset( outBufPtr, 0, wmmeStreamData->bytesPerUserOutputBuffer ); } } else { /* Convert 16 bit native data to user data and call user routine. */ - result = Pa_CallConvertInt16( past, (short *) inBufPtr, (short *) outBufPtr ); + result = Pa_CallConvertInt16( stream, (short *) inBufPtr, (short *) outBufPtr ); if( result != 0) done = 1; } - if( gotInput ) inBufPtr += pahsc->pahsc_BytesPerUserInputBuffer; - if( gotOutput) outBufPtr += pahsc->pahsc_BytesPerUserOutputBuffer; + if( gotInput ) inBufPtr += wmmeStreamData->bytesPerUserInputBuffer; + if( gotOutput) outBufPtr += wmmeStreamData->bytesPerUserOutputBuffer; } - Pa_EndUsageCalculation( past ); + Pa_EndUsageCalculation( stream ); /* Send WAVE buffer to Wave Device to be refilled. */ if( gotInput ) { - mresult = waveInAddBuffer( pahsc->pahsc_HWaveIn, - &pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ], + mresult = waveInAddBuffer( wmmeStreamData->hWaveIn, + &wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ], sizeof(WAVEHDR) ); if( mresult != MMSYSERR_NOERROR ) { @@ -616,17 +696,17 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past ) result = paHostError; break; } - pahsc->pahsc_CurrentInputBuffer = (pahsc->pahsc_CurrentInputBuffer+1 >= pahsc->pahsc_NumHostBuffers) ? - 0 : pahsc->pahsc_CurrentInputBuffer+1; + wmmeStreamData->currentInputBuffer = (wmmeStreamData->currentInputBuffer+1 >= wmmeStreamData->numHostBuffers) ? + 0 : wmmeStreamData->currentInputBuffer+1; } /* Write WAVE buffer to Wave Device. */ if( gotOutput ) { #if PA_TRACE_START_STOP - AddTraceMessage( "Pa_TimeSlice: writing buffer ", pahsc->pahsc_CurrentOutputBuffer ); + AddTraceMessage( "Pa_TimeSlice: writing buffer ", wmmeStreamData->currentOutputBuffer ); #endif - mresult = waveOutWrite( pahsc->pahsc_HWaveOut, - &pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ], + mresult = waveOutWrite( wmmeStreamData->hWaveOut, + &wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ], sizeof(WAVEHDR) ); if( mresult != MMSYSERR_NOERROR ) { @@ -634,8 +714,8 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past ) result = paHostError; break; } - pahsc->pahsc_CurrentOutputBuffer = (pahsc->pahsc_CurrentOutputBuffer+1 >= pahsc->pahsc_NumHostBuffers) ? - 0 : pahsc->pahsc_CurrentOutputBuffer+1; + wmmeStreamData->currentOutputBuffer = (wmmeStreamData->currentOutputBuffer+1 >= wmmeStreamData->numHostBuffers) ? + 0 : wmmeStreamData->currentOutputBuffer+1; } } @@ -647,62 +727,62 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past ) } /*******************************************************************/ -static PaError PaHost_BackgroundManager( internalPortAudioStream *past ) +static PaError PaHost_BackgroundManager( internalPortAudioStream *stream ) { - PaError result = 0; + PaError result = paNoError; int i; - int numQueuedOutputBuffers = 0; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + int numQueuedoutputBuffers = 0; + PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; /* Has someone asked us to abort by calling Pa_AbortStream()? */ - if( past->past_StopNow ) + if( stream->past_StopNow ) { - past->past_IsActive = 0; /* Will cause thread to return. */ + stream->past_IsActive = 0; /* Will cause thread to return. */ } /* Has someone asked us to stop by calling Pa_StopStream() * OR has a user callback returned '1' to indicate finished. */ - else if( past->past_StopSoon ) + else if( stream->past_StopSoon ) { /* Poll buffer and when all have played then exit thread. */ /* Count how many output buffers are queued. */ - numQueuedOutputBuffers = 0; - if( past->past_NumOutputChannels > 0 ) + numQueuedoutputBuffers = 0; + if( stream->past_NumOutputChannels > 0 ) { - for( i=0; ipahsc_NumHostBuffers; i++ ) + for( i=0; inumHostBuffers; i++ ) { - if( !( pahsc->pahsc_OutputBuffers[ i ].dwFlags & WHDR_DONE) ) + if( !( wmmeStreamData->outputBuffers[ i ].dwFlags & WHDR_DONE) ) { #if PA_TRACE_START_STOP - AddTraceMessage( "WinMMPa_OutputThreadProc: waiting for buffer ", i ); + AddTraceMessage( "PaHost_BackgroundManager: waiting for buffer ", i ); #endif - numQueuedOutputBuffers++; + numQueuedoutputBuffers++; } } } #if PA_TRACE_START_STOP - AddTraceMessage( "WinMMPa_OutputThreadProc: numQueuedOutputBuffers ", numQueuedOutputBuffers ); + AddTraceMessage( "PaHost_BackgroundManager: numQueuedoutputBuffers ", numQueuedoutputBuffers ); #endif - if( numQueuedOutputBuffers == 0 ) + if( numQueuedoutputBuffers == 0 ) { - past->past_IsActive = 0; /* Will cause thread to return. */ + stream->past_IsActive = 0; /* Will cause thread to return. */ } } else { /* Process full input buffer and fill up empty output buffers. */ - if( (result = Pa_TimeSlice( past )) != 0) + if( (result = Pa_TimeSlice( stream )) != 0) { /* User callback has asked us to stop. */ #if PA_TRACE_START_STOP - AddTraceMessage( "WinMMPa_OutputThreadProc: TimeSlice() returned ", result ); + AddTraceMessage( "PaHost_BackgroundManager: TimeSlice() returned ", result ); #endif - past->past_StopSoon = 1; /* Request that audio play out then stop. */ + stream->past_StopSoon = 1; /* Request that audio play out then stop. */ result = paNoError; } } - PaHost_UpdateStreamTime( pahsc ); + PaHost_UpdateStreamTime( wmmeStreamData ); return result; } @@ -710,57 +790,57 @@ static PaError PaHost_BackgroundManager( internalPortAudioStream *past ) /*******************************************************************/ static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { - internalPortAudioStream *past; - PaHostSoundControl *pahsc; + internalPortAudioStream *stream; + PaWMMEStreamData *wmmeStreamData; PaError result; - past = (internalPortAudioStream *) dwUser; - if( past == NULL ) return; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; - if( pahsc->pahsc_IfInsideCallback ) + + stream = (internalPortAudioStream *) dwUser; + if( stream == NULL ) return; + wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + if( wmmeStreamData == NULL ) return; + if( wmmeStreamData->ifInsideCallback ) { - if( pahsc->pahsc_TimerID != 0 ) + if( wmmeStreamData->timerID != 0 ) { - timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */ - pahsc->pahsc_TimerID = 0; + timeKillEvent(wmmeStreamData->timerID); /* Stop callback timer. */ + wmmeStreamData->timerID = 0; } return; } - pahsc->pahsc_IfInsideCallback = 1; + wmmeStreamData->ifInsideCallback = 1; /* Manage flags and audio processing. */ - result = PaHost_BackgroundManager( past ); + result = PaHost_BackgroundManager( stream ); if( result != paNoError ) { - past->past_IsActive = 0; + stream->past_IsActive = 0; } - pahsc->pahsc_IfInsideCallback = 0; + wmmeStreamData->ifInsideCallback = 0; } #else /* PA_USE_TIMER_CALLBACK */ /*******************************************************************/ static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) { - internalPortAudioStream *past; - PaHostSoundControl *pahsc; - void *inputBuffer=NULL; + internalPortAudioStream *stream; + PaWMMEStreamData *wmmeStreamData; HANDLE events[2]; int numEvents = 0; DWORD result = 0; DWORD waitResult; DWORD numTimeouts = 0; DWORD timeOut; - past = (internalPortAudioStream *) pArg; - pahsc = (PaHostSoundControl *) past->past_DeviceData; + stream = (internalPortAudioStream *) pArg; + wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; #if PA_TRACE_START_STOP AddTraceMessage( "WinMMPa_OutputThreadProc: timeoutPeriod", timeoutPeriod ); - AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", past->past_NumUserBuffers ); + AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", stream->past_NumUserBuffers ); #endif /* Calculate timeOut as half the time it would take to play all buffers. */ - timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate); + timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( stream ) / stream->past_SampleRate); /* Get event(s) ready for wait. */ - events[numEvents++] = pahsc->pahsc_BufferEvent; - if( pahsc->pahsc_AbortEventInited ) events[numEvents++] = pahsc->pahsc_AbortEvent; + events[numEvents++] = wmmeStreamData->bufferEvent; + if( wmmeStreamData->abortEventInited ) events[numEvents++] = wmmeStreamData->abortEvent; /* Stay in this thread as long as we are "active". */ - while( past->past_IsActive ) + while( stream->past_IsActive ) { /*******************************************************************/ /******** WAIT here for an event from WMME or PA *******************/ @@ -771,21 +851,21 @@ static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) { sPaHostError = GetLastError(); result = paHostError; - past->past_IsActive = 0; + stream->past_IsActive = 0; } /* Timeout? Don't stop. Just keep polling for DONE.*/ else if( waitResult == WAIT_TIMEOUT ) { #if PA_TRACE_START_STOP - AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedOutputBuffers ); + AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedoutputBuffers ); #endif numTimeouts += 1; } /* Manage flags and audio processing. */ - result = PaHost_BackgroundManager( past ); + result = PaHost_BackgroundManager( stream ); if( result != paNoError ) { - past->past_IsActive = 0; + stream->past_IsActive = 0; } } return result; @@ -793,44 +873,46 @@ static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) #endif /*******************************************************************/ -PaError PaHost_OpenInputStream( internalPortAudioStream *past ) +PaError PaHost_OpenInputStream( internalPortAudioStream *stream ) { MMRESULT mr; PaError result = paNoError; - PaHostSoundControl *pahsc; + PaWMMEStreamData *wmmeStreamData; int i; int inputMmId; int bytesPerInputFrame; WAVEFORMATEX wfx; - const PaDeviceInfo *pad; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID)); - pad = Pa_GetDeviceInfo( past->past_InputDeviceID ); - if( pad == NULL ) return paInternalError; - switch( pad->nativeSampleFormats ) + const PaDeviceInfo *deviceInfo; + + wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_InputDeviceID)); + deviceInfo = Pa_GetDeviceInfo( stream->past_InputDeviceID ); + if( deviceInfo == NULL ) return paInternalError; + + switch( deviceInfo->nativeSampleFormats ) { case paInt32: case paFloat32: - bytesPerInputFrame = sizeof(float) * past->past_NumInputChannels; + bytesPerInputFrame = sizeof(float) * stream->past_NumInputChannels; break; default: - bytesPerInputFrame = sizeof(short) * past->past_NumInputChannels; + bytesPerInputFrame = sizeof(short) * stream->past_NumInputChannels; break; } wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = (WORD) past->past_NumInputChannels; - wfx.nSamplesPerSec = (DWORD) past->past_SampleRate; - wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * past->past_SampleRate); + wfx.nChannels = (WORD) stream->past_NumInputChannels; + wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate; + wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * stream->past_SampleRate); wfx.nBlockAlign = (WORD)bytesPerInputFrame; - wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/past->past_NumInputChannels) * 8); + wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/stream->past_NumInputChannels) * 8); wfx.cbSize = 0; - inputMmId = PaDeviceIdToWinId( past->past_InputDeviceID ); + inputMmId = PaDeviceIdToWinId( stream->past_InputDeviceID ); #if PA_USE_TIMER_CALLBACK - mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx, + mr = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, 0, 0, CALLBACK_NULL ); #else - mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx, - (DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT ); + mr = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, + (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); #endif if( mr != MMSYSERR_NOERROR ) { @@ -840,24 +922,24 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) goto error; } /* Allocate an array to hold the buffer pointers. */ - pahsc->pahsc_InputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ - if( pahsc->pahsc_InputBuffers == NULL ) + wmmeStreamData->inputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */ + if( wmmeStreamData->inputBuffers == NULL ) { result = paInsufficientMemory; goto error; } /* Allocate each buffer. */ - for( i=0; ipahsc_NumHostBuffers; i++ ) + for( i=0; inumHostBuffers; i++ ) { - pahsc->pahsc_InputBuffers[i].lpData = (char *)PaHost_AllocateTrackedMemory( pahsc->pahsc_BytesPerHostInputBuffer ); /* MEM */ - if( pahsc->pahsc_InputBuffers[i].lpData == NULL ) + wmmeStreamData->inputBuffers[i].lpData = (char *)PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostInputBuffer ); /* MEM */ + if( wmmeStreamData->inputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; goto error; } - pahsc->pahsc_InputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostInputBuffer; - pahsc->pahsc_InputBuffers[i].dwUser = i; - if( ( mr = waveInPrepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) + wmmeStreamData->inputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostInputBuffer; + wmmeStreamData->inputBuffers[i].dwUser = i; + if( ( mr = waveInPrepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mr; @@ -865,57 +947,61 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) } } return result; + error: return result; } /*******************************************************************/ -PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) +PaError PaHost_OpenOutputStream( internalPortAudioStream *stream ) { MMRESULT mr; PaError result = paNoError; - PaHostSoundControl *pahsc; + PaWMMEStreamData *wmmeStreamData; int i; int outputMmID; int bytesPerOutputFrame; WAVEFORMATEX wfx; - const PaDeviceInfo *pad; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); - pad = Pa_GetDeviceInfo( past->past_OutputDeviceID ); - if( pad == NULL ) return paInternalError; - switch( pad->nativeSampleFormats ) + const PaDeviceInfo *deviceInfo; + + wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_OutputDeviceID)); + + deviceInfo = Pa_GetDeviceInfo( stream->past_OutputDeviceID ); + if( deviceInfo == NULL ) return paInternalError; + + switch( deviceInfo->nativeSampleFormats ) { case paInt32: case paFloat32: - bytesPerOutputFrame = sizeof(float) * past->past_NumOutputChannels; + bytesPerOutputFrame = sizeof(float) * stream->past_NumOutputChannels; break; default: - bytesPerOutputFrame = sizeof(short) * past->past_NumOutputChannels; + bytesPerOutputFrame = sizeof(short) * stream->past_NumOutputChannels; break; } wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = (WORD) past->past_NumOutputChannels; - wfx.nSamplesPerSec = (DWORD) past->past_SampleRate; - wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * past->past_SampleRate); + wfx.nChannels = (WORD) stream->past_NumOutputChannels; + wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate; + wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * stream->past_SampleRate); wfx.nBlockAlign = (WORD)bytesPerOutputFrame; - wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/past->past_NumOutputChannels) * 8); + wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/stream->past_NumOutputChannels) * 8); wfx.cbSize = 0; - outputMmID = PaDeviceIdToWinId( past->past_OutputDeviceID ); + outputMmID = PaDeviceIdToWinId( stream->past_OutputDeviceID ); #if PA_USE_TIMER_CALLBACK - mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx, + mr = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, 0, 0, CALLBACK_NULL ); #else - pahsc->pahsc_AbortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); - if( pahsc->pahsc_AbortEvent == NULL ) + wmmeStreamData->abortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if( wmmeStreamData->abortEvent == NULL ) { result = paHostError; sPaHostError = GetLastError(); goto error; } - pahsc->pahsc_AbortEventInited = 1; - mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx, - (DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT ); + wmmeStreamData->abortEventInited = 1; + mr = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, + (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); #endif if( mr != MMSYSERR_NOERROR ) { @@ -925,24 +1011,24 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) goto error; } /* Allocate an array to hold the buffer pointers. */ - pahsc->pahsc_OutputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ - if( pahsc->pahsc_OutputBuffers == NULL ) + wmmeStreamData->outputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */ + if( wmmeStreamData->outputBuffers == NULL ) { result = paInsufficientMemory; goto error; } /* Allocate each buffer. */ - for( i=0; ipahsc_NumHostBuffers; i++ ) + for( i=0; inumHostBuffers; i++ ) { - pahsc->pahsc_OutputBuffers[i].lpData = (char *) PaHost_AllocateTrackedMemory( pahsc->pahsc_BytesPerHostOutputBuffer ); /* MEM */ - if( pahsc->pahsc_OutputBuffers[i].lpData == NULL ) + wmmeStreamData->outputBuffers[i].lpData = (char *) PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostOutputBuffer ); /* MEM */ + if( wmmeStreamData->outputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; goto error; } - pahsc->pahsc_OutputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostOutputBuffer; - pahsc->pahsc_OutputBuffers[i].dwUser = i; - if( (mr = waveOutPrepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) + wmmeStreamData->outputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostOutputBuffer; + wmmeStreamData->outputBuffers[i].dwUser = i; + if( (mr = waveOutPrepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mr; @@ -950,53 +1036,55 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) } } return result; + error: return result; } /*******************************************************************/ -PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) +PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *stream ) { - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer; + PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + return wmmeStreamData->numHostBuffers * wmmeStreamData->framesPerHostBuffer; } /******************************************************************* -* Determine number of WAVE Buffers -* and how many User Buffers we can put into each WAVE buffer. -*/ -static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) + * Determine number of WAVE Buffers + * and how many User Buffers we can put into each WAVE buffer. + */ +static void PaHost_CalcNumHostBuffers( internalPortAudioStream *stream ) { - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; unsigned int minNumBuffers; - int minFramesPerHostBuffer; - int maxFramesPerHostBuffer; + int minframesPerHostBuffer; + int maxframesPerHostBuffer; int minTotalFrames; int userBuffersPerHostBuffer; int framesPerHostBuffer; int numHostBuffers; + /* Calculate minimum and maximum sizes based on timing and sample rate. */ - minFramesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); - minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; - DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); - maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); - maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7; - DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer )); + minframesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001); + minframesPerHostBuffer = (minframesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: minframesPerHostBuffer = %d\n", minframesPerHostBuffer )); + maxframesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001); + maxframesPerHostBuffer = (maxframesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: maxframesPerHostBuffer = %d\n", maxframesPerHostBuffer )); /* Determine number of user buffers based on minimum latency. */ - minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); - past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; - DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); - minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; + minNumBuffers = Pa_GetMinNumBuffers( stream->past_FramesPerUserBuffer, stream->past_SampleRate ); + stream->past_NumUserBuffers = ( minNumBuffers > stream->past_NumUserBuffers ) ? minNumBuffers : stream->past_NumUserBuffers; + DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", stream->past_NumUserBuffers )); + minTotalFrames = stream->past_NumUserBuffers * stream->past_FramesPerUserBuffer; /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ - if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) + if( (int) stream->past_FramesPerUserBuffer < minframesPerHostBuffer ) { userBuffersPerHostBuffer = - (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / - past->past_FramesPerUserBuffer; + (minframesPerHostBuffer + stream->past_FramesPerUserBuffer - 1) / + stream->past_FramesPerUserBuffer; } else { userBuffersPerHostBuffer = 1; } - framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* Make sure we have anough WAVE buffers. */ @@ -1005,156 +1093,148 @@ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; } else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) && - ((int) past->past_FramesPerUserBuffer < (maxFramesPerHostBuffer/2) ) ) + ((int) stream->past_FramesPerUserBuffer < (maxframesPerHostBuffer/2) ) ) { /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) { userBuffersPerHostBuffer += 1; - framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* If we have gone too far, back up one. */ - if( (framesPerHostBuffer > maxFramesPerHostBuffer) || + if( (framesPerHostBuffer > maxframesPerHostBuffer) || (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) ) { userBuffersPerHostBuffer -= 1; - framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; break; } } } - pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; - pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; - pahsc->pahsc_NumHostBuffers = numHostBuffers; - DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); - DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); - DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); - DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); + wmmeStreamData->userBuffersPerHostBuffer = userBuffersPerHostBuffer; + wmmeStreamData->framesPerHostBuffer = framesPerHostBuffer; + wmmeStreamData->numHostBuffers = numHostBuffers; + DBUG(("PaHost_CalcNumHostBuffers: userBuffersPerHostBuffer = %d\n", wmmeStreamData->userBuffersPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: numHostBuffers = %d\n", wmmeStreamData->numHostBuffers )); + DBUG(("PaHost_CalcNumHostBuffers: framesPerHostBuffer = %d\n", wmmeStreamData->framesPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", stream->past_NumUserBuffers )); } /*******************************************************************/ -PaError PaHost_OpenStream( internalPortAudioStream *past ) +PaError PaHost_OpenStream( internalPortAudioStream *stream ) { PaError result = paNoError; - PaHostSoundControl *pahsc; - /* Allocate and initialize host data. */ - pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */ - if( pahsc == NULL ) - { - result = paInsufficientMemory; - goto error; - } - memset( pahsc, 0, sizeof(PaHostSoundControl) ); - past->past_DeviceData = (void *) pahsc; + PaWMMEStreamData *wmmeStreamData; + + result = PaHost_AllocateWMMEStreamData( stream ); + if( result != paNoError ) return result; + + wmmeStreamData = PaHost_GetWMMEStreamData( stream ); + /* Figure out how user buffers fit into WAVE buffers. */ - PaHost_CalcNumHostBuffers( past ); + PaHost_CalcNumHostBuffers( stream ); { - int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate); - DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); + int msecLatency = (int) ((PaHost_GetTotalBufferFrames(stream) * 1000) / stream->past_SampleRate); + DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(stream), msecLatency )); } - InitializeCriticalSection( &pahsc->pahsc_StreamLock ); - pahsc->pahsc_StreamLockInited = 1; + InitializeCriticalSection( &wmmeStreamData->streamLock ); + wmmeStreamData->streamLockInited = 1; #if (PA_USE_TIMER_CALLBACK == 0) - pahsc->pahsc_BufferEventInited = 0; - pahsc->pahsc_BufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - if( pahsc->pahsc_BufferEvent == NULL ) + wmmeStreamData->bufferEventInited = 0; + wmmeStreamData->bufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( wmmeStreamData->bufferEvent == NULL ) { result = paHostError; sPaHostError = GetLastError(); goto error; } - pahsc->pahsc_BufferEventInited = 1; + wmmeStreamData->bufferEventInited = 1; #endif /* (PA_USE_TIMER_CALLBACK == 0) */ /* ------------------ OUTPUT */ - pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels * sizeof(short); - pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer; - if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) + wmmeStreamData->bytesPerUserOutputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumOutputChannels * sizeof(short); + wmmeStreamData->bytesPerHostOutputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserOutputBuffer; + if( (stream->past_OutputDeviceID != paNoDevice) && (stream->past_NumOutputChannels > 0) ) { - result = PaHost_OpenOutputStream( past ); + result = PaHost_OpenOutputStream( stream ); if( result < 0 ) goto error; } /* ------------------ INPUT */ - pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels * sizeof(short); - pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer; - if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) ) + wmmeStreamData->bytesPerUserInputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumInputChannels * sizeof(short); + wmmeStreamData->bytesPerHostInputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserInputBuffer; + if( (stream->past_InputDeviceID != paNoDevice) && (stream->past_NumInputChannels > 0) ) { - result = PaHost_OpenInputStream( past ); + result = PaHost_OpenInputStream( stream ); if( result < 0 ) goto error; } - /* Calculate scalar used in CPULoad calculation. */ - { - LARGE_INTEGER frequency; - if( QueryPerformanceFrequency( &frequency ) == 0 ) - { - pahsc->pahsc_InverseTicksPerHostBuffer = 0.0; - } - else - { - pahsc->pahsc_InverseTicksPerHostBuffer = past->past_SampleRate / - ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer * pahsc->pahsc_UserBuffersPerHostBuffer ); - DBUG(("pahsc_InverseTicksPerHostBuffer = %g\n", pahsc->pahsc_InverseTicksPerHostBuffer )); - } - } + + Pa_InitializeCpuUsageScalar( stream ); + return result; + error: - PaHost_CloseStream( past ); + PaHost_CloseStream( stream ); return result; } /*************************************************************************/ -PaError PaHost_StartOutput( internalPortAudioStream *past ) +PaError PaHost_StartOutput( internalPortAudioStream *stream ) { - MMRESULT mr; - PaHostSoundControl *pahsc; PaError result = paNoError; + MMRESULT mr; int i; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( past->past_OutputDeviceID != paNoDevice ) + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); + + if( wmmeStreamData == NULL ) return paInternalError; + + if( stream->past_OutputDeviceID != paNoDevice ) { - if( (mr = waveOutPause( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR ) + if( (mr = waveOutPause( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mr; goto error; } - for( i=0; ipahsc_NumHostBuffers; i++ ) + for( i=0; inumHostBuffers; i++ ) { - ZeroMemory( pahsc->pahsc_OutputBuffers[i].lpData, pahsc->pahsc_OutputBuffers[i].dwBufferLength ); - mr = waveOutWrite( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) ); + ZeroMemory( wmmeStreamData->outputBuffers[i].lpData, wmmeStreamData->outputBuffers[i].dwBufferLength ); + mr = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); if( mr != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mr; goto error; } - past->past_FrameCount += pahsc->pahsc_FramesPerHostBuffer; + stream->past_FrameCount += wmmeStreamData->framesPerHostBuffer; } - pahsc->pahsc_CurrentOutputBuffer = 0; - if( (mr = waveOutRestart( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR ) + wmmeStreamData->currentOutputBuffer = 0; + if( (mr = waveOutRestart( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mr; goto error; } } + error: DBUG(("PaHost_StartOutput: wave returned mr = 0x%X.\n", mr)); return result; } /*************************************************************************/ -PaError PaHost_StartInput( internalPortAudioStream *past ) +PaError PaHost_StartInput( internalPortAudioStream *internalStream ) { PaError result = paNoError; MMRESULT mr; int i; - PaHostSoundControl *pahsc; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( past->past_InputDeviceID != paNoDevice ) + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); + + if( wmmeStreamData == NULL ) return paInternalError; + + if( internalStream->past_InputDeviceID != paNoDevice ) { - for( i=0; ipahsc_NumHostBuffers; i++ ) + for( i=0; inumHostBuffers; i++ ) { - mr = waveInAddBuffer( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) ); + mr = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); if( mr != MMSYSERR_NOERROR ) { result = paHostError; @@ -1162,8 +1242,8 @@ PaError PaHost_StartInput( internalPortAudioStream *past ) goto error; } } - pahsc->pahsc_CurrentInputBuffer = 0; - mr = waveInStart( pahsc->pahsc_HWaveIn ); + wmmeStreamData->currentInputBuffer = 0; + mr = waveInStart( wmmeStreamData->hWaveIn ); DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mr)); if( mr != MMSYSERR_NOERROR ) { @@ -1172,149 +1252,155 @@ PaError PaHost_StartInput( internalPortAudioStream *past ) goto error; } } + error: return result; } /*************************************************************************/ -PaError PaHost_StartEngine( internalPortAudioStream *past ) +PaError PaHost_StartEngine( internalPortAudioStream *stream ) { PaError result = paNoError; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); #if PA_USE_TIMER_CALLBACK int resolution; int bufsPerTimerCallback; int msecPerBuffer; #endif /* PA_USE_TIMER_CALLBACK */ - past->past_StopSoon = 0; - past->past_StopNow = 0; - past->past_IsActive = 1; - pahsc->pahsc_FramesPlayed = 0.0; - pahsc->pahsc_LastPosition = 0; + if( wmmeStreamData == NULL ) return paInternalError; + + stream->past_StopSoon = 0; + stream->past_StopNow = 0; + stream->past_IsActive = 1; + wmmeStreamData->framesPlayed = 0.0; + wmmeStreamData->lastPosition = 0; #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result ); #endif #if PA_USE_TIMER_CALLBACK /* Create timer that will wake us up so we can fill the DSound buffer. */ - bufsPerTimerCallback = pahsc->pahsc_NumHostBuffers/4; + bufsPerTimerCallback = wmmeStreamData->numHostBuffers/4; if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; msecPerBuffer = (1000 * bufsPerTimerCallback * - pahsc->pahsc_UserBuffersPerHostBuffer * - past->past_FramesPerUserBuffer ) / (int) past->past_SampleRate; + wmmeStreamData->userBuffersPerHostBuffer * + internalStream->past_FramesPerUserBuffer ) / (int) internalStream->past_SampleRate; if( msecPerBuffer < 10 ) msecPerBuffer = 10; else if( msecPerBuffer > 100 ) msecPerBuffer = 100; resolution = msecPerBuffer/4; - pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution, + wmmeStreamData->timerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback, - (DWORD) past, TIME_PERIODIC ); - if( pahsc->pahsc_TimerID == 0 ) + (DWORD) stream, TIME_PERIODIC ); + if( wmmeStreamData->timerID == 0 ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #else /* PA_USE_TIMER_CALLBACK */ - ResetEvent( pahsc->pahsc_AbortEvent ); + ResetEvent( wmmeStreamData->abortEvent ); /* Create thread that waits for audio buffers to be ready for processing. */ - pahsc->pahsc_EngineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, past, 0, &pahsc->pahsc_EngineThreadID ); - if( pahsc->pahsc_EngineThread == NULL ) + wmmeStreamData->engineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, stream, 0, &wmmeStreamData->engineThreadID ); + if( wmmeStreamData->engineThread == NULL ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StartEngine: thread ", (int) pahsc->pahsc_EngineThread ); + AddTraceMessage( "PaHost_StartEngine: thread ", (int) wmmeStreamData->engineThread ); #endif /* I used to pass the thread which was failing. I now pass GetCurrentProcess(). - ** This fix could improve latency for some applications. It could also result in CPU - ** starvation if the callback did too much processing. - ** I also added result checks, so we might see more failures at initialization. - ** Thanks to Alberto di Bene for spotting this. - */ + * This fix could improve latency for some applications. It could also result in CPU + * starvation if the callback did too much processing. + * I also added result checks, so we might see more failures at initialization. + * Thanks to Alberto di Bene for spotting this. + */ if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */ { result = paHostError; sPaHostError = GetLastError();; goto error; } - if( !SetThreadPriority( pahsc->pahsc_EngineThread, THREAD_PRIORITY_HIGHEST ) ) + if( !SetThreadPriority( wmmeStreamData->engineThread, THREAD_PRIORITY_HIGHEST ) ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #endif + error: return result; } - /*************************************************************************/ -PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) +PaError PaHost_StopEngine( internalPortAudioStream *internalStream, int abort ) { int timeOut; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); + + if( wmmeStreamData == NULL ) return paNoError; /* Tell background thread to stop generating more data and to let current data play out. */ - past->past_StopSoon = 1; + internalStream->past_StopSoon = 1; /* If aborting, tell background thread to stop NOW! */ - if( abort ) past->past_StopNow = 1; + if( abort ) internalStream->past_StopNow = 1; /* Calculate timeOut longer than longest time it could take to play all buffers. */ - timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate); + timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( internalStream ) / internalStream->past_SampleRate); if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; #if PA_USE_TIMER_CALLBACK - if( (past->past_OutputDeviceID != paNoDevice) && - past->past_IsActive && - (pahsc->pahsc_TimerID != 0) ) + if( (internalStream->past_OutputDeviceID != paNoDevice) && + internalStream->past_IsActive && + (wmmeStreamData->timerID != 0) ) { /* Wait for IsActive to drop. */ - while( (past->past_IsActive) && (timeOut > 0) ) + while( (internalStream->past_IsActive) && (timeOut > 0) ) { Sleep(10); timeOut -= 10; } - timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */ - pahsc->pahsc_TimerID = 0; + timeKillEvent( wmmeStreamData->timerID ); /* Stop callback timer. */ + wmmeStreamData->timerID = 0; } #else /* PA_USE_TIMER_CALLBACK */ #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StopEngine: thread ", (int) pahsc->pahsc_EngineThread ); + AddTraceMessage( "PaHost_StopEngine: thread ", (int) wmmeStreamData->engineThread ); #endif - if( (past->past_OutputDeviceID != paNoDevice) && - (past->past_IsActive) && - (pahsc->pahsc_EngineThread != NULL) ) + if( (internalStream->past_OutputDeviceID != paNoDevice) && + (internalStream->past_IsActive) && + (wmmeStreamData->engineThread != NULL) ) { DWORD got; /* Tell background thread to stop generating more data and to let current data play out. */ DBUG(("PaHost_StopEngine: waiting for background thread.\n")); - got = WaitForSingleObject( pahsc->pahsc_EngineThread, timeOut ); + got = WaitForSingleObject( wmmeStreamData->engineThread, timeOut ); if( got == WAIT_TIMEOUT ) { ERR_RPT(("PaHost_StopEngine: timed out while waiting for background thread to finish.\n")); return paTimedOut; } - CloseHandle( pahsc->pahsc_EngineThread ); - pahsc->pahsc_EngineThread = NULL; + CloseHandle( wmmeStreamData->engineThread ); + wmmeStreamData->engineThread = NULL; } #endif /* PA_USE_TIMER_CALLBACK */ - past->past_IsActive = 0; + internalStream->past_IsActive = 0; return paNoError; } /*************************************************************************/ -PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) +PaError PaHost_StopInput( internalPortAudioStream *stream, int abort ) { MMRESULT mr; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; - (void) abort; - if( pahsc->pahsc_HWaveIn != NULL ) + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); + + if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ + (void) abort; /* FIXME: what is this? */ + + if( wmmeStreamData->hWaveIn != NULL ) { - mr = waveInReset( pahsc->pahsc_HWaveIn ); + mr = waveInReset( wmmeStreamData->hWaveIn ); if( mr != MMSYSERR_NOERROR ) { sPaHostError = mr; @@ -1324,19 +1410,20 @@ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) return paNoError; } /*************************************************************************/ -PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) +PaError PaHost_StopOutput( internalPortAudioStream *internalStream, int abort ) { MMRESULT mr; - PaHostSoundControl *pahsc; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; - (void) abort; + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); + + if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ + (void) abort; /* FIXME: what is this? */ + #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); + AddTraceMessage( "PaHost_StopOutput: hWaveOut ", (int) wmmeStreamData->hWaveOut ); #endif - if( pahsc->pahsc_HWaveOut != NULL ) + if( wmmeStreamData->hWaveOut != NULL ) { - mr = waveOutReset( pahsc->pahsc_HWaveOut ); + mr = waveOutReset( wmmeStreamData->hWaveOut ); if( mr != MMSYSERR_NOERROR ) { sPaHostError = mr; @@ -1346,65 +1433,67 @@ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) return paNoError; } /*******************************************************************/ -PaError PaHost_CloseStream( internalPortAudioStream *past ) +PaError PaHost_CloseStream( internalPortAudioStream *stream ) { - int i; - PaHostSoundControl *pahsc; - if( past == NULL ) return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; + int i; + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); + + if( stream == NULL ) return paBadStreamPtr; + if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return no error? */ + #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); + AddTraceMessage( "PaHost_CloseStream: hWaveOut ", (int) wmmeStreamData->hWaveOut ); #endif /* Free data and device for output. */ - if( pahsc->pahsc_HWaveOut ) + if( wmmeStreamData->hWaveOut ) { - if( pahsc->pahsc_OutputBuffers ) + if( wmmeStreamData->outputBuffers ) { - for( i=0; ipahsc_NumHostBuffers; i++ ) + for( i=0; inumHostBuffers; i++ ) { - waveOutUnprepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) ); - PaHost_FreeTrackedMemory( pahsc->pahsc_OutputBuffers[i].lpData ); /* MEM */ + waveOutUnprepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); + PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers[i].lpData ); /* MEM */ } - PaHost_FreeTrackedMemory( pahsc->pahsc_OutputBuffers ); /* MEM */ + PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers ); /* MEM */ } - waveOutClose( pahsc->pahsc_HWaveOut ); + waveOutClose( wmmeStreamData->hWaveOut ); } /* Free data and device for input. */ - if( pahsc->pahsc_HWaveIn ) + if( wmmeStreamData->hWaveIn ) { - if( pahsc->pahsc_InputBuffers ) + if( wmmeStreamData->inputBuffers ) { - for( i=0; ipahsc_NumHostBuffers; i++ ) + for( i=0; inumHostBuffers; i++ ) { - waveInUnprepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) ); - PaHost_FreeTrackedMemory( pahsc->pahsc_InputBuffers[i].lpData ); /* MEM */ + waveInUnprepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); + PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers[i].lpData ); /* MEM */ } - PaHost_FreeTrackedMemory( pahsc->pahsc_InputBuffers ); /* MEM */ + PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers ); /* MEM */ } - waveInClose( pahsc->pahsc_HWaveIn ); + waveInClose( wmmeStreamData->hWaveIn ); } #if (PA_USE_TIMER_CALLBACK == 0) - if( pahsc->pahsc_AbortEventInited ) CloseHandle( pahsc->pahsc_AbortEvent ); - if( pahsc->pahsc_BufferEventInited ) CloseHandle( pahsc->pahsc_BufferEvent ); + if( wmmeStreamData->abortEventInited ) CloseHandle( wmmeStreamData->abortEvent ); + if( wmmeStreamData->bufferEventInited ) CloseHandle( wmmeStreamData->bufferEvent ); #endif - if( pahsc->pahsc_StreamLockInited ) - DeleteCriticalSection( &pahsc->pahsc_StreamLock ); - PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */ - past->past_DeviceData = NULL; + if( wmmeStreamData->streamLockInited ) + DeleteCriticalSection( &wmmeStreamData->streamLock ); + + PaHost_FreeWMMEStreamData( stream ); + return paNoError; } /************************************************************************* -** 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 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. -*/ + * 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 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. + */ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { @@ -1413,6 +1502,7 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) int minLatencyMsec = 0; double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; int minBuffers; + /* Let user determine minimal latency by setting environment variable. */ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) @@ -1454,11 +1544,12 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) return minBuffers; } /************************************************************************* -** Cleanup device info. -*/ + * Cleanup device info. + */ PaError PaHost_Term( void ) { int i; + if( sNumDevices > 0 ) { if( sDevicePtrs != NULL ) @@ -1490,6 +1581,7 @@ void Pa_Sleep( long msec ) Sleep( msec ); } /************************************************************************* +FIXME: the following memory allocation routines should not be declared here * 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. @@ -1514,11 +1606,12 @@ void PaHost_FreeFastMemory( void *addr, long numBytes ) */ static void *PaHost_AllocateTrackedMemory( long numBytes ) { - void *addr = GlobalAlloc( GPTR, numBytes ); /* MEM */ + void *result = GlobalAlloc( GPTR, numBytes ); /* MEM */ + #if PA_TRACK_MEMORY - if( addr != NULL ) sNumAllocations += 1; + if( result != NULL ) sNumAllocations += 1; #endif - return addr; + return result; } static void PaHost_FreeTrackedMemory( void *addr ) @@ -1533,30 +1626,37 @@ static void PaHost_FreeTrackedMemory( void *addr ) } /***********************************************************************/ -PaError PaHost_StreamActive( internalPortAudioStream *past ) +PaError PaHost_StreamActive( internalPortAudioStream *internalStream ) { - PaHostSoundControl *pahsc; - if( past == NULL ) return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paInternalError; - return (PaError) past->past_IsActive; + //internalPortAudioStream *internalStream = PaHost_GetStreamRepresentation( stream ); + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); + + if( internalStream == NULL ) return paBadStreamPtr; + if( wmmeStreamData == NULL ) return paInternalError; + + /* + FIXME: why are we dereferencing wmmeStreamData here at all? + */ + + return (PaError) internalStream->past_IsActive; } /************************************************************************* * This must be called periodically because mmtime.u.sample * is a DWORD and can wrap and lose sync after a few hours. */ -static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc ) +static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ) { MMRESULT mr; MMTIME mmtime; mmtime.wType = TIME_SAMPLES; - if( pahsc->pahsc_HWaveOut != NULL ) + + if( wmmeStreamData->hWaveOut != NULL ) { - mr = waveOutGetPosition( pahsc->pahsc_HWaveOut, &mmtime, sizeof(mmtime) ); + mr = waveOutGetPosition( wmmeStreamData->hWaveOut, &mmtime, sizeof(mmtime) ); } else { - mr = waveInGetPosition( pahsc->pahsc_HWaveIn, &mmtime, sizeof(mmtime) ); + mr = waveInGetPosition( wmmeStreamData->hWaveIn, &mmtime, sizeof(mmtime) ); } if( mr != MMSYSERR_NOERROR ) { @@ -1565,19 +1665,23 @@ static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc ) } /* This data has two variables and is shared by foreground and background. */ /* So we need to make it thread safe. */ - EnterCriticalSection( &pahsc->pahsc_StreamLock ); - pahsc->pahsc_FramesPlayed += ((long)mmtime.u.sample) - pahsc->pahsc_LastPosition; - pahsc->pahsc_LastPosition = (long)mmtime.u.sample; - LeaveCriticalSection( &pahsc->pahsc_StreamLock ); + EnterCriticalSection( &wmmeStreamData->streamLock ); + wmmeStreamData->framesPlayed += ((long)mmtime.u.sample) - wmmeStreamData->lastPosition; + wmmeStreamData->lastPosition = (long)mmtime.u.sample; + LeaveCriticalSection( &wmmeStreamData->streamLock ); return paNoError; } /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { - PaHostSoundControl *pahsc; - internalPortAudioStream *past = (internalPortAudioStream *) stream; - if( past == NULL ) return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - PaHost_UpdateStreamTime( pahsc ); - return pahsc->pahsc_FramesPlayed; + internalPortAudioStream *internalStream = PaHost_GetStreamRepresentation( stream ); + PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); + + if( internalStream == NULL ) return paBadStreamPtr; + if( wmmeStreamData == NULL ) return paInternalError; + + PaHost_UpdateStreamTime( wmmeStreamData ); + return wmmeStreamData->framesPlayed; } +/*************************************************************************/ + From 365a8e2444173dfc13a2a21c9eb17a573b2625fc Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 12 Apr 2002 18:07:20 +0000 Subject: [PATCH 054/814] Use getrusage() instead of gettimeofday() for CPU Load calculation. --- pa_mac_core/pa_mac_core.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c index 760aa28..e608402 100644 --- a/pa_mac_core/pa_mac_core.c +++ b/pa_mac_core/pa_mac_core.c @@ -50,6 +50,7 @@ Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally. Better error checking for invalid channel counts and invalid devices. 3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers. + 3.31.2002 - Phil Burk - Use getrusage() instead of gettimeofday() for CPU Load calculation. TODO: O- how do mono output? @@ -59,6 +60,7 @@ O- FIFO between input and output callbacks if different devices, like in pa_mac. #include #include #include +#include #include #include "portaudio.h" @@ -98,7 +100,7 @@ typedef struct PaHostSoundControl int pahsc_FramesPerHostBuffer; int pahsc_UserBuffersPerHostBuffer; /* For measuring CPU utilization. */ - struct timeval pahsc_EntryTime; + struct rusage pahsc_EntryRusage; double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */ } PaHostSoundControl; @@ -156,8 +158,8 @@ 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 ); + /* Query user CPU timer for usage analysis and to prevent overuse of CPU. */ + getrusage( RUSAGE_SELF, &pahsc->pahsc_EntryRusage ); } static long SubtractTime_AminusB( struct timeval *timeA, struct timeval *timeB ) @@ -174,7 +176,7 @@ static long SubtractTime_AminusB( struct timeval *timeA, struct timeval *timeB ) */ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { - struct timeval currentTime; + struct rusage currentRusage; long usecsElapsed; double newUsage; @@ -183,10 +185,11 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; - - if( gettimeofday( ¤tTime, NULL ) == 0 ) + + if( getrusage( RUSAGE_SELF, ¤tRusage ) == 0 ) { - usecsElapsed = SubtractTime_AminusB( ¤tTime, &pahsc->pahsc_EntryTime ); + usecsElapsed = SubtractTime_AminusB( ¤tRusage.ru_utime, &pahsc->pahsc_EntryRusage.ru_utime ); + /* Use inverse because it is faster than the divide. */ newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer; From 48e580a679ecee2b69e14a406ed526a0dc91dffd Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 12 Apr 2002 23:32:47 +0000 Subject: [PATCH 055/814] Important patch for the ASIO SDK. --- pa_asio/readme_asio_sdk_patch.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 pa_asio/readme_asio_sdk_patch.txt diff --git a/pa_asio/readme_asio_sdk_patch.txt b/pa_asio/readme_asio_sdk_patch.txt new file mode 100755 index 0000000..c0fdca7 --- /dev/null +++ b/pa_asio/readme_asio_sdk_patch.txt @@ -0,0 +1,25 @@ +There is a bug in the ASIO SDK that causes the Macintosh version to often fail during initialization. Here is a patch that you can apply. + +In codefragments.cpp replace getFrontProcessDirectory function with +the following one (GetFrontProcess replaced by GetCurrentProcess) + + +bool CodeFragments::getFrontProcessDirectory(void *specs) +{ + FSSpec *fss = (FSSpec *)specs; + ProcessInfoRec pif; + ProcessSerialNumber psn; + + memset(&psn,0,(long)sizeof(ProcessSerialNumber)); + // if(GetFrontProcess(&psn) == noErr) // wrong !!! + if(GetCurrentProcess(&psn) == noErr) // correct !!! + { + pif.processName = 0; + pif.processAppSpec = fss; + pif.processInfoLength = sizeof(ProcessInfoRec); + if(GetProcessInformation(&psn, &pif) == noErr) + return true; + } + return false; +} + From ec5a8371387427f8f70ee3d257c8cad3632f0785 Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 12 Apr 2002 23:33:52 +0000 Subject: [PATCH 056/814] Add Mac includes for and --- pa_asio/pa_asio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pa_asio/pa_asio.cpp b/pa_asio/pa_asio.cpp index 6fef65f..4cb7240 100644 --- a/pa_asio/pa_asio.cpp +++ b/pa_asio/pa_asio.cpp @@ -54,6 +54,7 @@ 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz + 12-04-02 Add Mac includes for and : Phil Burk TO DO : @@ -74,7 +75,10 @@ #include "asio.h" #include "asiodrivers.h" + #if MAC +#include +#include #include #else #include From 83abb2d3ff558d7e598f7cc16abcbe19e880e2ee Mon Sep 17 00:00:00 2001 From: stephane Date: Sat, 13 Apr 2002 08:42:50 +0000 Subject: [PATCH 057/814] Removes another compiler warning --- pa_asio/pa_asio.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pa_asio/pa_asio.cpp b/pa_asio/pa_asio.cpp index 4cb7240..269dc59 100644 --- a/pa_asio/pa_asio.cpp +++ b/pa_asio/pa_asio.cpp @@ -55,6 +55,7 @@ 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz 12-04-02 Add Mac includes for and : Phil Burk + 13-04-02 Removes another compiler warning : Stephane Letz TO DO : @@ -1324,7 +1325,7 @@ static void Output_Float32_Int32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE TESTED - void Output_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap) + static void Output_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap) { long temp; int i,j; From 49ef51660bca14cc61e65431067afaaeef3f4ebf Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 17 Apr 2002 05:06:14 +0000 Subject: [PATCH 058/814] updated Pa_CountDevices to not counting WAVE_MAPPER when there were no real devices --- pa_win_wmme/pa_win_wmme.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pa_win_wmme/pa_win_wmme.c b/pa_win_wmme/pa_win_wmme.c index 1e21d58..48c875e 100644 --- a/pa_win_wmme/pa_win_wmme.c +++ b/pa_win_wmme/pa_win_wmme.c @@ -52,6 +52,7 @@ JM20020118 - prevent hung thread when buffers underflow. PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init + RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices */ #include @@ -290,12 +291,21 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *stream ) static PaError Pa_QueryDevices( void ) { int numBytes; - /* Count the devices and add one extra for the WAVE_MAPPER */ - sNumInputDevices = waveInGetNumDevs() + 1; + + sNumInputDevices = waveInGetNumDevs(); + if( sNumInputDevices > 0 ) + sNumInputDevices += 1; /* add one extra for the WAVE_MAPPER */ + sDefaultInputDeviceID = 0; - sNumOutputDevices = waveOutGetNumDevs() + 1; + + sNumOutputDevices = waveOutGetNumDevs(); + if( sNumOutputDevices > 0 ) + sNumOutputDevices += 1; /* add one extra for the WAVE_MAPPER */ + sDefaultOutputDeviceID = sNumInputDevices; + sNumDevices = sNumInputDevices + sNumOutputDevices; + /* Allocate structures to hold device info. */ /* PLB20010402 - was allocating too much memory. */ /* numBytes = sNumDevices * sizeof(PaDeviceInfo); // PLB20010402 */ From 35734f8aa272b28f3a5dd5fc5c105375ef13fadf Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 17 Apr 2002 06:27:05 +0000 Subject: [PATCH 059/814] changed Pa_QueryDevices to Pa_InitializeNumDevices and added separate function Pa_AllocateDevicePtrs changed Pa_AllocateDevicePtrs to never allocate 0 bytes removed Pa_MabeQueryDevices added explicit initialization of sDevicePtrs[n] to NULL changed default input and output devices to paNoDevice when no device was available changed Pa_GetDefaultInput/OutputDeviceID to have the same behavior as when there was no environment variable when the environment variables value was out of range added #if around declaration of sNumAllocations removed unused locals bytesEmpty, bytesFilled, buffersEmpty from Pa_TimeSlice() renamed all result variables of type MMRESULT to mmresult --- pa_win_wmme/pa_win_wmme.c | 236 ++++++++++++++++++++------------------ 1 file changed, 123 insertions(+), 113 deletions(-) diff --git a/pa_win_wmme/pa_win_wmme.c b/pa_win_wmme/pa_win_wmme.c index 48c875e..ba7ca62 100644 --- a/pa_win_wmme/pa_win_wmme.c +++ b/pa_win_wmme/pa_win_wmme.c @@ -45,7 +45,7 @@ PLB20010413 - check for excessive numbers of channels PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC including condition including of memory.h, - and explicit typecasting on memory allocation + and explicit typecasting on memory allocation PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory PLB20010816 - pass process instead of thread to SetPriorityClass() PLB20010927 - use number of frames instead of real-time for CPULoad calculation. @@ -53,6 +53,7 @@ PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices + refactoring, renaming and fixed a few edge case bugs */ #include @@ -170,13 +171,19 @@ static int sDefaultOutputDeviceID = paNoDevice; static int sPaHostError = 0; static const char sMapperSuffixInput[] = " - Input"; static const char sMapperSuffixOutput[] = " - Output"; + +#if PA_TRACK_MEMORY static int sNumAllocations = 0; +#endif /************************************************* Macros ********/ /* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ #define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) /************************************************* Prototypes **********/ -static Pa_QueryDevices( void ); + +void Pa_InitializeNumDevices( void ); +PaError Pa_AllocateDevicePtrs( void ); + static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); @@ -186,19 +193,6 @@ static PaError PaHost_BackgroundManager( internalPortAudioStream *past ); static void *PaHost_AllocateTrackedMemory( long numBytes ); static void PaHost_FreeTrackedMemory( void *addr ); - -/* - FIXME: PaHost_GetStreamRepresentation() should be migrated to pa_lib.c -*/ -static internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream ) -{ - internalPortAudioStream* result = (internalPortAudioStream*) stream; - - if( result == NULL || result->past_Magic != PA_MAGIC ) - return NULL; - else - return result; -} /*******************************************************************/ static PaError PaHost_AllocateWMMEStreamData( internalPortAudioStream *stream ) { @@ -287,31 +281,56 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *stream ) } /****************************************** END CPU UTILIZATION *******/ -/* FIXME: this function should be renamed */ -static PaError Pa_QueryDevices( void ) +static void Pa_InitializeNumDevices( void ) { - int numBytes; - sNumInputDevices = waveInGetNumDevs(); if( sNumInputDevices > 0 ) + { sNumInputDevices += 1; /* add one extra for the WAVE_MAPPER */ - - sDefaultInputDeviceID = 0; + sDefaultInputDeviceID = 0; + } + else + { + sDefaultInputDeviceID = paNoDevice; + } sNumOutputDevices = waveOutGetNumDevs(); if( sNumOutputDevices > 0 ) + { sNumOutputDevices += 1; /* add one extra for the WAVE_MAPPER */ - - sDefaultOutputDeviceID = sNumInputDevices; + sDefaultOutputDeviceID = sNumInputDevices; + } + else + { + sDefaultOutputDeviceID = paNoDevice; + } sNumDevices = sNumInputDevices + sNumOutputDevices; - +} + +static PaError Pa_AllocateDevicePtrs( void ) +{ + int numBytes; + int i; + /* Allocate structures to hold device info. */ /* PLB20010402 - was allocating too much memory. */ /* numBytes = sNumDevices * sizeof(PaDeviceInfo); // PLB20010402 */ - numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */ - sDevicePtrs = (PaDeviceInfo **) PaHost_AllocateTrackedMemory( numBytes ); /* MEM */ - if( sDevicePtrs == NULL ) return paInsufficientMemory; + + if( sNumDevices > 0 ) + { + numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */ + sDevicePtrs = (PaDeviceInfo **) PaHost_AllocateTrackedMemory( numBytes ); /* MEM */ + if( sDevicePtrs == NULL ) return paInsufficientMemory; + + for( i = 0; i < sNumDevices; i++ ) + sDevicePtrs[i] = NULL; /* RDB20020417 explicitly set each ptr to NULL */ + } + else + { + sDevicePtrs = NULL; + } + return paNoError; } /*************************************************************************/ @@ -322,8 +341,10 @@ long Pa_GetHostError() /*************************************************************************/ int Pa_CountDevices() { - if( sNumDevices <= 0 ) Pa_Initialize(); - return sNumDevices; + if( PaHost_IsInitialized() ) + return sNumDevices; + else + return 0; } /************************************************************************* * If a PaDeviceInfo structure has not already been created, @@ -483,6 +504,7 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) sampleRates[ deviceInfo->numSampleRates++ ] = 22050.; if( woc.dwFormats & WAVE_FORMAT_4M16 ||woc.dwFormats & WAVE_FORMAT_4S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 44100.; + /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on opening the device successfully. */ for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ) @@ -537,39 +559,27 @@ static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) } return recommendedID; } -static PaError Pa_MaybeQueryDevices( void ) -{ - if( sNumDevices == 0 ) - { - return Pa_QueryDevices(); - } - return 0; -} /********************************************************************** * Check for environment variable, else query devices and use result. */ PaDeviceID Pa_GetDefaultInputDeviceID( void ) { - PaError result; + PaDeviceID result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); - if( result < 0 ) + if( result == paNoDevice || result < 0 || result >= sNumInputDevices ) { - result = Pa_MaybeQueryDevices(); - if( result < 0 ) return result; result = sDefaultInputDeviceID; } return result; } PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { - PaError result; + PaDeviceID result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); - if( result < 0 ) + if( result == paNoDevice || result < sNumInputDevices || result >= sNumDevices ) { - result = Pa_MaybeQueryDevices(); - if( result < 0 ) return result; result = sDefaultOutputDeviceID; } return result; @@ -587,7 +597,11 @@ PaError PaHost_Init( void ) #if PA_SIMULATE_UNDERFLOW PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); #endif - return Pa_MaybeQueryDevices(); + + + Pa_InitializeNumDevices(); + + return Pa_AllocateDevicePtrs(); } /********************************************************************** @@ -607,10 +621,7 @@ PaError PaHost_Init( void ) static PaError Pa_TimeSlice( internalPortAudioStream *stream ) { PaError result = paNoError; - long bytesEmpty = 0; - long bytesFilled = 0; - long buffersEmpty = 0; - MMRESULT mresult; + MMRESULT mmresult; char *inBufPtr; char *outBufPtr; int gotInput = 0; @@ -697,12 +708,12 @@ static PaError Pa_TimeSlice( internalPortAudioStream *stream ) /* Send WAVE buffer to Wave Device to be refilled. */ if( gotInput ) { - mresult = waveInAddBuffer( wmmeStreamData->hWaveIn, + mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ], sizeof(WAVEHDR) ); - if( mresult != MMSYSERR_NOERROR ) + if( mmresult != MMSYSERR_NOERROR ) { - sPaHostError = mresult; + sPaHostError = mmresult; result = paHostError; break; } @@ -715,12 +726,12 @@ static PaError Pa_TimeSlice( internalPortAudioStream *stream ) #if PA_TRACE_START_STOP AddTraceMessage( "Pa_TimeSlice: writing buffer ", wmmeStreamData->currentOutputBuffer ); #endif - mresult = waveOutWrite( wmmeStreamData->hWaveOut, + mmresult = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ], sizeof(WAVEHDR) ); - if( mresult != MMSYSERR_NOERROR ) + if( mmresult != MMSYSERR_NOERROR ) { - sPaHostError = mresult; + sPaHostError = mmresult; result = paHostError; break; } @@ -885,8 +896,8 @@ static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) /*******************************************************************/ PaError PaHost_OpenInputStream( internalPortAudioStream *stream ) { - MMRESULT mr; PaError result = paNoError; + MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData; int i; int inputMmId; @@ -918,17 +929,17 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *stream ) wfx.cbSize = 0; inputMmId = PaDeviceIdToWinId( stream->past_InputDeviceID ); #if PA_USE_TIMER_CALLBACK - mr = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, + mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, 0, 0, CALLBACK_NULL ); #else - mr = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, + mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); #endif - if( mr != MMSYSERR_NOERROR ) + if( mmresult != MMSYSERR_NOERROR ) { ERR_RPT(("PortAudio: PaHost_OpenInputStream() failed!\n")); result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } /* Allocate an array to hold the buffer pointers. */ @@ -949,10 +960,10 @@ PaError PaHost_OpenInputStream( internalPortAudioStream *stream ) } wmmeStreamData->inputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostInputBuffer; wmmeStreamData->inputBuffers[i].dwUser = i; - if( ( mr = waveInPrepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) + if( ( mmresult = waveInPrepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } } @@ -964,8 +975,8 @@ error: /*******************************************************************/ PaError PaHost_OpenOutputStream( internalPortAudioStream *stream ) { - MMRESULT mr; PaError result = paNoError; + MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData; int i; int outputMmID; @@ -998,7 +1009,7 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *stream ) wfx.cbSize = 0; outputMmID = PaDeviceIdToWinId( stream->past_OutputDeviceID ); #if PA_USE_TIMER_CALLBACK - mr = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, + mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, 0, 0, CALLBACK_NULL ); #else @@ -1010,14 +1021,14 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *stream ) goto error; } wmmeStreamData->abortEventInited = 1; - mr = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, + mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); #endif - if( mr != MMSYSERR_NOERROR ) + if( mmresult != MMSYSERR_NOERROR ) { ERR_RPT(("PortAudio: PaHost_OpenOutputStream() failed!\n")); result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } /* Allocate an array to hold the buffer pointers. */ @@ -1038,10 +1049,10 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *stream ) } wmmeStreamData->outputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostOutputBuffer; wmmeStreamData->outputBuffers[i].dwUser = i; - if( (mr = waveOutPrepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) + if( (mmresult = waveOutPrepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } } @@ -1191,7 +1202,7 @@ error: PaError PaHost_StartOutput( internalPortAudioStream *stream ) { PaError result = paNoError; - MMRESULT mr; + MMRESULT mmresult; int i; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); @@ -1199,42 +1210,42 @@ PaError PaHost_StartOutput( internalPortAudioStream *stream ) if( stream->past_OutputDeviceID != paNoDevice ) { - if( (mr = waveOutPause( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) + if( (mmresult = waveOutPause( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } for( i=0; inumHostBuffers; i++ ) { ZeroMemory( wmmeStreamData->outputBuffers[i].lpData, wmmeStreamData->outputBuffers[i].dwBufferLength ); - mr = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); - if( mr != MMSYSERR_NOERROR ) + mmresult = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); + if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } stream->past_FrameCount += wmmeStreamData->framesPerHostBuffer; } wmmeStreamData->currentOutputBuffer = 0; - if( (mr = waveOutRestart( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) + if( (mmresult = waveOutRestart( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } } error: - DBUG(("PaHost_StartOutput: wave returned mr = 0x%X.\n", mr)); + DBUG(("PaHost_StartOutput: wave returned mmresult = 0x%X.\n", mmresult)); return result; } /*************************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *internalStream ) { PaError result = paNoError; - MMRESULT mr; + MMRESULT mmresult; int i; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); @@ -1244,21 +1255,21 @@ PaError PaHost_StartInput( internalPortAudioStream *internalStream ) { for( i=0; inumHostBuffers; i++ ) { - mr = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); - if( mr != MMSYSERR_NOERROR ) + mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); + if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } } wmmeStreamData->currentInputBuffer = 0; - mr = waveInStart( wmmeStreamData->hWaveIn ); - DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mr)); - if( mr != MMSYSERR_NOERROR ) + mmresult = waveInStart( wmmeStreamData->hWaveIn ); + DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult)); + if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mr; + sPaHostError = mmresult; goto error; } } @@ -1402,18 +1413,18 @@ PaError PaHost_StopEngine( internalPortAudioStream *internalStream, int abort ) /*************************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *stream, int abort ) { - MMRESULT mr; + MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ - (void) abort; /* FIXME: what is this? */ + (void) abort; /* unused parameter */ if( wmmeStreamData->hWaveIn != NULL ) { - mr = waveInReset( wmmeStreamData->hWaveIn ); - if( mr != MMSYSERR_NOERROR ) + mmresult = waveInReset( wmmeStreamData->hWaveIn ); + if( mmresult != MMSYSERR_NOERROR ) { - sPaHostError = mr; + sPaHostError = mmresult; return paHostError; } } @@ -1422,21 +1433,21 @@ PaError PaHost_StopInput( internalPortAudioStream *stream, int abort ) /*************************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *internalStream, int abort ) { - MMRESULT mr; + MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ - (void) abort; /* FIXME: what is this? */ + (void) abort; /* unused parameter */ #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StopOutput: hWaveOut ", (int) wmmeStreamData->hWaveOut ); #endif if( wmmeStreamData->hWaveOut != NULL ) { - mr = waveOutReset( wmmeStreamData->hWaveOut ); - if( mr != MMSYSERR_NOERROR ) + mmresult = waveOutReset( wmmeStreamData->hWaveOut ); + if( mmresult != MMSYSERR_NOERROR ) { - sPaHostError = mr; + sPaHostError = mmresult; return paHostError; } } @@ -1517,7 +1528,7 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { - minLatencyMsec = atoi( envbuf ); + minLatencyMsec = atoi( envbuf ); /* REVIEW: will we crash if the environment variable contains some nasty value? */ } else { @@ -1608,6 +1619,8 @@ void *PaHost_AllocateFastMemory( long numBytes ) */ void PaHost_FreeFastMemory( void *addr, long numBytes ) { + (void) numBytes; /* unused parameter */ + PaHost_FreeTrackedMemory( addr ); /* MEM */ } @@ -1638,15 +1651,7 @@ static void PaHost_FreeTrackedMemory( void *addr ) /***********************************************************************/ PaError PaHost_StreamActive( internalPortAudioStream *internalStream ) { - //internalPortAudioStream *internalStream = PaHost_GetStreamRepresentation( stream ); - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); - if( internalStream == NULL ) return paBadStreamPtr; - if( wmmeStreamData == NULL ) return paInternalError; - - /* - FIXME: why are we dereferencing wmmeStreamData here at all? - */ return (PaError) internalStream->past_IsActive; } @@ -1656,29 +1661,32 @@ PaError PaHost_StreamActive( internalPortAudioStream *internalStream ) */ static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ) { - MMRESULT mr; + MMRESULT mmresult; MMTIME mmtime; mmtime.wType = TIME_SAMPLES; if( wmmeStreamData->hWaveOut != NULL ) { - mr = waveOutGetPosition( wmmeStreamData->hWaveOut, &mmtime, sizeof(mmtime) ); + mmresult = waveOutGetPosition( wmmeStreamData->hWaveOut, &mmtime, sizeof(mmtime) ); } else { - mr = waveInGetPosition( wmmeStreamData->hWaveIn, &mmtime, sizeof(mmtime) ); + mmresult = waveInGetPosition( wmmeStreamData->hWaveIn, &mmtime, sizeof(mmtime) ); } - if( mr != MMSYSERR_NOERROR ) + + if( mmresult != MMSYSERR_NOERROR ) { - sPaHostError = mr; + sPaHostError = mmresult; return paHostError; } - /* This data has two variables and is shared by foreground and background. */ - /* So we need to make it thread safe. */ + + /* This data has two variables and is shared by foreground and background. + * So we need to make it thread safe. */ EnterCriticalSection( &wmmeStreamData->streamLock ); wmmeStreamData->framesPlayed += ((long)mmtime.u.sample) - wmmeStreamData->lastPosition; wmmeStreamData->lastPosition = (long)mmtime.u.sample; LeaveCriticalSection( &wmmeStreamData->streamLock ); + return paNoError; } /*************************************************************************/ @@ -1695,3 +1703,5 @@ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) } /*************************************************************************/ + + From 8d13d1df285cff45ab0670decaa6e99815e6ce48 Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 17 Apr 2002 06:28:18 +0000 Subject: [PATCH 060/814] added protoypes for PaHost_IsInitialized() and PaHost_GetStreamRepresentation() --- pa_common/pa_host.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pa_common/pa_host.h b/pa_common/pa_host.h index b077f83..94651a2 100644 --- a/pa_common/pa_host.h +++ b/pa_common/pa_host.h @@ -149,6 +149,11 @@ PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate, /************ 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 ); From 7f295afdc7e98a9f06a17d99a79c5c70c883fbc5 Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 17 Apr 2002 06:29:07 +0000 Subject: [PATCH 061/814] added implementation of PaHost_IsInitialized() migrated PaHost_GetStreamRepresentation() from pa_win_wmme.c --- pa_common/pa_lib.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pa_common/pa_lib.c b/pa_common/pa_lib.c index 2c7c41c..1c6e82f 100644 --- a/pa_common/pa_lib.c +++ b/pa_common/pa_lib.c @@ -478,6 +478,17 @@ double Pa_GetCPULoad( PortAudioStream* 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. @@ -754,6 +765,11 @@ PaError Pa_Terminate( void ) return result; } +int PaHost_IsInitialized() +{ + return gInitCount; +} + /*************************************************************************/ PaError Pa_GetSampleSize( PaSampleFormat format ) { From 687dfcbe4e3710bf279f7e196fe044da4bfffb21 Mon Sep 17 00:00:00 2001 From: philburk Date: Thu, 18 Apr 2002 19:40:11 +0000 Subject: [PATCH 062/814] Fixed bug where I was calling the wrong function to calculate the minimum number of user buffers. This resulted in a too conservative, ie. too high, latency. --- pa_mac/pa_mac.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/pa_mac/pa_mac.c b/pa_mac/pa_mac.c index cde9a95..265a7d4 100644 --- a/pa_mac/pa_mac.c +++ b/pa_mac/pa_mac.c @@ -42,7 +42,12 @@ PLB20010907 - Pass unused event to WaitNextEvent to prevent Mac OSX crash. Thanks Dominic Mazzoni. PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. PLB20011009 - Use NewSndCallBackUPP() for CARBON + PLB20020417 - I used to call Pa_GetMinNumBuffers() which doesn't take into account the + variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will + gove lower latency when virtual memory is turned off. + Thanks Kristoffer Jensen and Georgios Marentakis for spotting this bug. */ + /* COMPATIBILITY This Macintosh implementation is designed for use with Mac OS 7, 8 and @@ -72,6 +77,7 @@ O- Determine default devices somehow. #include #include #include + /* Mac specific includes */ #include "OSUtils.h" #include @@ -84,6 +90,7 @@ O- Determine default devices somehow. #include #include #include + #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" @@ -942,8 +949,8 @@ int Mac_IsVirtualMemoryOn( void ) } /******************************************************************* -* Determine number of WAVE Buffers -* and how many User Buffers we can put into each WAVE buffer. +* Determine number of host Buffers +* and how many User Buffers we can put into each host buffer. */ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) { @@ -954,16 +961,23 @@ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) int32 userBuffersPerHostBuffer; int32 framesPerHostBuffer; int32 numHostBuffers; - /* Calculate minimum and maximum sizes based on timing and sample rate. */ + minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer; minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); + /* Determine number of user buffers based on minimum latency. */ - minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); + /* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the + ** variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will + ** gove lower latency when virtual memory is turned off. */ + /* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */ + minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate ); + past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; - /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ + + /* We cannot make the buffers too small because they may not get serviced quickly enough. */ if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) { userBuffersPerHostBuffer = @@ -975,16 +989,17 @@ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) userBuffersPerHostBuffer = 1; } framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; - /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ + + /* Calculate number of host buffers needed. Round up to cover minTotalFrames. */ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; - /* Make sure we have anough WAVE buffers. */ + /* Make sure we have enough host buffers. */ if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) { numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; } else { - /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ + /* If we have too many host buffers, try to put more user buffers in a host buffer. */ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) { userBuffersPerHostBuffer += 1; @@ -1219,6 +1234,9 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) /*************************************************************************/ int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) { +/* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording. +** This routine doesn't have enough information to determine the best value +** and is being depracated. */ return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate ); } /*************************************************************************/ From baefbbdc4a79daeefbb9c5dcb24c96baf4300167 Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 19 Apr 2002 18:31:13 +0000 Subject: [PATCH 063/814] Change sine generation method so that sine waves don't line up with PA buffers. This was causing it to appear that audio was OK even when buffers were dropped.. --- pa_tests/pa_minlat.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/pa_tests/pa_minlat.c b/pa_tests/pa_minlat.c index bc9f185..533b8c4 100644 --- a/pa_tests/pa_minlat.c +++ b/pa_tests/pa_minlat.c @@ -38,18 +38,21 @@ #include #include #include "portaudio.h" + #ifndef M_PI #define M_PI (3.14159265) #endif +#define TWOPI (M_PI * 2.0) + #define DEFAULT_BUFFER_SIZE (64) #define TABLE_SIZE (200) typedef struct { - float sine[TABLE_SIZE]; - int left_phase; - int right_phase; + double left_phase; + double right_phase; } paTestData; + /* Very simple synthesis routine to generate two sine waves. */ static int paminlatCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, @@ -58,15 +61,25 @@ static int paminlatCallback( void *inputBuffer, void *outputBuffer, paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned int i; + double left_phaseInc = 0.02; + double right_phaseInc = 0.06; + + double left_phase = data->left_phase; + double right_phase = data->right_phase; + for( i=0; isine[data->left_phase]; /* left */ - *out++ = data->sine[data->right_phase]; /* right */ - data->left_phase += 1; - if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; - data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ - if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + left_phase += left_phaseInc; + if( left_phase > TWOPI ) left_phase -= TWOPI; + *out++ = (float) sin( left_phase ); + + right_phase += right_phaseInc; + if( right_phase > TWOPI ) right_phase -= TWOPI; + *out++ = (float) sin( right_phase ); } + + data->left_phase = left_phase; + data->right_phase = right_phase; return 0; } void main( int argc, char **argv ); @@ -75,7 +88,6 @@ void main( int argc, char **argv ) PortAudioStream *stream; PaError err; paTestData data; - int i; int go; int numBuffers = 0; int minBuffers = 0; @@ -91,12 +103,8 @@ void main( int argc, char **argv ) /* Get bufferSize from command line. */ framesPerBuffer = ( argc > 1 ) ? atol( argv[1] ) : DEFAULT_BUFFER_SIZE; printf("Frames per buffer = %d\n", framesPerBuffer ); - /* Initialise sinusoidal wavetable. */ - for( i=0; i Date: Fri, 19 Apr 2002 18:31:54 +0000 Subject: [PATCH 064/814] Detect Win XP and Win 2K properly when determining latency. --- pa_win_ds/pa_dsound.c | 52 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/pa_win_ds/pa_dsound.c b/pa_win_ds/pa_dsound.c index 96f4753..877c01d 100644 --- a/pa_win_ds/pa_dsound.c +++ b/pa_win_ds/pa_dsound.c @@ -33,6 +33,7 @@ /* Modifications * 7/19/01 Mike Berry - casts for compiling with __MWERKS__ CodeWarrior * 9/27/01 Phil Burk - use number of frames instead of real-time for CPULoad calculation. + * 4/19/02 Phil Burk - Check for Win XP for system latency calculation. */ /* Compiler flags: SUPPORT_AUDIO_CAPTURE - define this flag if you want to SUPPORT_AUDIO_CAPTURE @@ -49,10 +50,12 @@ #include "pa_host.h" #include "pa_trace.h" #include "dsound_wrapper.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 PA_USE_HIGH_LATENCY (0) #if PA_USE_HIGH_LATENCY #define PA_WIN_9X_LATENCY (500) @@ -61,6 +64,9 @@ #define PA_WIN_9X_LATENCY (140) #define PA_WIN_NT_LATENCY (280) #endif + +#define PA_WIN_WDM_LATENCY (120) + /* Trigger an underflow for testing purposes. Should normally be (0). */ #define PA_SIMULATE_UNDERFLOW (0) #if PA_SIMULATE_UNDERFLOW @@ -68,6 +74,7 @@ static gUnderCallbackCounter = 0; #define UNDER_START_GAP (10) #define UNDER_STOP_GAP (UNDER_START_GAP + 4) #endif + /************************************************* Definitions ********/ typedef struct internalPortAudioStream internalPortAudioStream; typedef struct internalPortAudioDevice @@ -78,6 +85,7 @@ typedef struct internalPortAudioDevice PaDeviceInfo pad_Info; } internalPortAudioDevice; + /* Define structure to contain all DirectSound and Windows specific data. */ typedef struct PaHostSoundControl { @@ -93,6 +101,7 @@ typedef struct PaHostSoundControl double pahsc_InverseTicksPerUserBuffer; } PaHostSoundControl; + /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ static int sNumDevices = 0; @@ -115,6 +124,7 @@ static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID, static Pa_QueryDevices( void ); static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); + /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { @@ -123,6 +133,7 @@ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) /* Query system timer for usage analysis and to prevent overuse of CPU. */ QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); } + static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { LARGE_INTEGER CurrentCount = { 0, 0 }; @@ -142,6 +153,7 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) (LOWPASS_COEFFICIENT_1 * newUsage); } } + /****************************************** END CPU UTILIZATION *******/ static PaError Pa_QueryDevices( void ) { @@ -873,6 +885,38 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) past->past_DeviceData = NULL; return paNoError; } + +/* Set minimal latency based on whether NT or Win95. + * NT has higher latency. + */ +static int PaHost_GetMinSystemLatency( void ) +{ + int minLatencyMsec; + /* Set minimal latency based on whether NT or other OS. + * NT has higher latency. + */ + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof( osvi ); + GetVersionEx( &osvi ); + DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); + DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); + DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); + /* Check for NT */ + if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) + { + minLatencyMsec = PA_WIN_NT_LATENCY; + } + else if(osvi.dwMajorVersion >= 5) + { + minLatencyMsec = PA_WIN_WDM_LATENCY; + } + else + { + minLatencyMsec = PA_WIN_9X_LATENCY; + } + return minLatencyMsec; +} + /************************************************************************* ** Determine minimum number of buffers required for this host based ** on minimum latency. Latency can be optionally set by user by setting @@ -888,7 +932,6 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { char envbuf[PA_ENV_BUF_SIZE]; - DWORD hostVersion; DWORD hresult; int minLatencyMsec = 0; double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; @@ -901,12 +944,7 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) } else { - /* Set minimal latency based on whether NT or Win95. - * NT has higher latency. - */ - hostVersion = GetVersion(); - /* High bit clear if NT */ - minLatencyMsec = ( (hostVersion & 0x80000000) == 0 ) ? PA_WIN_NT_LATENCY : PA_WIN_9X_LATENCY ; + minLatencyMsec = PaHost_GetMinSystemLatency(); #if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); #endif From 348e268d7b126de051a4699cf303dfcdbf466de4 Mon Sep 17 00:00:00 2001 From: philburk Date: Wed, 24 Apr 2002 04:58:09 +0000 Subject: [PATCH 065/814] Use new method to calculate CPU load similar to other ports. Based on num frames calculated. Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer. Added PA_MAX_USAGE_ALLOWED to prevent Mac from hanging when CPU load approaches 100%. --- pa_mac/pa_mac.c | 172 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 51 deletions(-) diff --git a/pa_mac/pa_mac.c b/pa_mac/pa_mac.c index 265a7d4..414a73b 100644 --- a/pa_mac/pa_mac.c +++ b/pa_mac/pa_mac.c @@ -44,8 +44,11 @@ PLB20011009 - Use NewSndCallBackUPP() for CARBON PLB20020417 - I used to call Pa_GetMinNumBuffers() which doesn't take into account the variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will - gove lower latency when virtual memory is turned off. + give lower latency when virtual memory is turned off. Thanks Kristoffer Jensen and Georgios Marentakis for spotting this bug. + PLB20020423 - Use new method to calculate CPU load similar to other ports. Based on num frames calculated. + Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer. + Added PA_MAX_USAGE_ALLOWED to prevent Mac form hanging when CPU load approaches 100%. */ /* @@ -100,6 +103,16 @@ O- Determine default devices somehow. #define TRUE (!FALSE) #endif +/* #define TARGET_API_MAC_CARBON (1) */ + +/* + * Define maximum CPU load that will be allowed. User callback will + * be skipped if load exceeds this limit. This is to prevent the Mac + * from hanging when the CPU is hogged by the sound thread. + * On my PowerBook G3, the mac hung when I used 94% of CPU ( usage = 0.94 ). + */ +#define PA_MAX_USAGE_ALLOWED (0.92) + /* Debugging output macros. */ #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) @@ -108,7 +121,7 @@ O- Determine default devices somehow. #define MAC_PHYSICAL_FRAMES_PER_BUFFER (512) /* Minimum number of stereo frames per SoundManager double buffer. */ #define MAC_VIRTUAL_FRAMES_PER_BUFFER (4096) /* Need this many when using Virtual Memory for recording. */ -#define PA_MIN_NUM_HOST_BUFFERS (2) +#define PA_MIN_NUM_HOST_BUFFERS (2) #define PA_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */ #define PA_MAX_DEVICE_INFO (32) @@ -133,7 +146,8 @@ MultiBuffer; typedef struct PaHostSoundControl { UInt64 pahsc_EntryCount; - UInt64 pahsc_LastExitCount; + double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */ + /* Use char instead of Boolean for atomic operation. */ volatile char pahsc_IsRecording; /* Recording in progress. Set by foreground. Cleared by background. */ volatile char pahsc_StopRecording; /* Signal sent to background. */ @@ -141,22 +155,23 @@ typedef struct PaHostSoundControl /* Input */ SPB pahsc_InputParams; SICompletionUPP pahsc_InputCompletionProc; - MultiBuffer pahsc_InputMultiBuffer; - int32 pahsc_BytesPerInputHostBuffer; + MultiBuffer pahsc_InputMultiBuffer; + int32 pahsc_BytesPerInputHostBuffer; int32 pahsc_InputRefNum; /* Output */ CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS]; int32 pahsc_BytesPerOutputHostBuffer; - SndChannelPtr pahsc_Channel; + SndChannelPtr pahsc_Channel; SndCallBackUPP pahsc_OutputCompletionProc; int32 pahsc_NumOutsQueued; int32 pahsc_NumOutsPlayed; PaTimestamp pahsc_NumFramesDone; + UInt64 pahsc_WhenFramesDoneIncremented; /* Init Time -------------- */ int32 pahsc_NumHostBuffers; int32 pahsc_FramesPerHostBuffer; int32 pahsc_UserBuffersPerHostBuffer; - int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */ + int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */ } PaHostSoundControl; @@ -184,7 +199,8 @@ static int sDefaultInputDeviceID; /************************************************************************************/ static PaError PaMac_TimeSlice( internalPortAudioStream *past, int16 *macOutputBufPtr ); static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr ); -static PaError PaMac_RecordNext( internalPortAudioStream *past );static void StartLoadCalculation( internalPortAudioStream *past ); +static PaError PaMac_RecordNext( internalPortAudioStream *past ); +static void PaMac_StartLoadCalculation( internalPortAudioStream *past ); static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate ); static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h ); static PaError PaMac_ScanInputDevices( void ); @@ -703,8 +719,8 @@ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) return sDefaultOutputDeviceID; } -/**************************************************************************/ -static void StartLoadCalculation( internalPortAudioStream *past ) +/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ +static void PaMac_StartLoadCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; UnsignedWide widePad; @@ -714,38 +730,36 @@ static void StartLoadCalculation( internalPortAudioStream *past ) pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad ); } +/****************************************************************************** +** Measure fractional CPU load based on real-time it took to calculate +** buffers worth of output. +*/ /**************************************************************************/ static void PaMac_EndLoadCalculation( internalPortAudioStream *past ) { UnsignedWide widePad; - UInt64 CurrentCount; - long InsideCount; - long TotalCount; + UInt64 currentCount; + long usecsElapsed; + double newUsage; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; + /* Measure CPU utilization during this callback. Note that this calculation ** assumes that we had the processor the whole time. */ -#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_0 (0.95) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) Microseconds( &widePad ); - CurrentCount = UnsignedWideToUInt64( widePad ); - if( past->past_IfLastExitValid ) - { - InsideCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_EntryCount); - TotalCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_LastExitCount); - /* Low pass filter the result because sometimes we get called several times in a row. - * That can cause the TotalCount to be very low which can cause the usage to appear - * unnaturally high. So we must filter numerator and denominator separately!!! - */ - past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + - (LOWPASS_COEFFICIENT_1 * InsideCount)); - past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + - (LOWPASS_COEFFICIENT_1 * TotalCount)); - past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; - } - pahsc->pahsc_LastExitCount = CurrentCount; - past->past_IfLastExitValid = 1; + currentCount = UnsignedWideToUInt64( widePad ); + + usecsElapsed = (long) U64Subtract(currentCount, pahsc->pahsc_EntryCount); + + /* Use inverse because it is faster than the divide. */ + newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer; + + past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + + (LOWPASS_COEFFICIENT_1 * newUsage); + } /*********************************************************************** @@ -836,6 +850,14 @@ static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHead sndHeader->format = kSoundNotCompressed; } +static void SetFramesDone( PaHostSoundControl *pahsc, PaTimestamp framesDone ) +{ + UnsignedWide now; + Microseconds( &now ); + pahsc->pahsc_NumFramesDone = framesDone; + pahsc->pahsc_WhenFramesDoneIncremented = UnsignedWideToUInt64( now ); +} + /***********************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { @@ -851,7 +873,8 @@ PaError PaHost_StartOutput( internalPortAudioStream *past ) past->past_IsActive = 1; pahsc->pahsc_NumOutsQueued = 0; pahsc->pahsc_NumOutsPlayed = 0; - pahsc->pahsc_NumFramesDone = 0.0; + + SetFramesDone( pahsc, 0.0 ); /* Pause channel so it does not do back ground processing while we are still filling the queue. */ pauseCommand.cmd = pauseCmd; @@ -864,7 +887,7 @@ PaError PaHost_StartOutput( internalPortAudioStream *past ) { PaMac_PlayNext( past, i ); } - + /* Resume channel now that the queue is full. */ resumeCommand.cmd = resumeCmd; resumeCommand.param1 = resumeCommand.param2 = 0; @@ -1043,6 +1066,9 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) } PaHost_CalcNumHostBuffers( past ); + + /* Setup constants for CPU load measurement. */ + pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer); /* ------------------ OUTPUT */ if( past->past_NumOutputChannels > 0 ) @@ -1316,11 +1342,37 @@ void PaHost_FreeFastMemory( void *addr, long numBytes ) /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { + PaTimestamp framesDone1; + PaTimestamp framesDone2; + UInt64 whenIncremented; + UnsignedWide now; + UInt64 now64; + long microsElapsed; + long framesElapsed; + PaHostSoundControl *pahsc; internalPortAudioStream *past = (internalPortAudioStream *) stream; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; - return pahsc->pahsc_NumFramesDone; + +/* Capture information from audio thread. + * We have to be careful that we don't get interrupted in the middle. + * So we grab the pahsc_NumFramesDone twice and make sure it didn't change. + */ + do + { + framesDone1 = pahsc->pahsc_NumFramesDone; + whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented; + framesDone2 = pahsc->pahsc_NumFramesDone; + } while( framesDone1 != framesDone2 ); + + /* Calculate how many microseconds have elapsed and convert to frames. */ + Microseconds( &now ); + now64 = UnsignedWideToUInt64( now ); + microsElapsed = U64Subtract( now64, whenIncremented ); + framesElapsed = microsElapsed * past->past_SampleRate * 0.000001; + + return pahsc->pahsc_NumFramesDone + framesElapsed; } /************************************************************************** @@ -1358,7 +1410,8 @@ pascal void PaMac_InputCompletionProc(SPBPtr recParams) */ if(past->past_NumOutputChannels == 0) { - pahsc->pahsc_NumFramesDone += pahsc->pahsc_FramesPerHostBuffer; // Advance for recording + SetFramesDone( pahsc, + pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer ); result = PaMac_CallUserLoop( past, NULL ); } @@ -1389,6 +1442,7 @@ static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPt PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; int16 *inPtr = NULL; int i; + /* Advance read index for sound input FIFO here, independantly of record/write process. */ if(past->past_NumInputChannels > 0) @@ -1403,22 +1457,33 @@ static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPt /* Call user code enough times to fill buffer. */ if( (inPtr != NULL) || (outPtr != NULL) ) { - StartLoadCalculation( past ); /* CPU usage */ - - for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) - { - result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr ); - if( result != 0) - { - /* Recording might be in another process, so tell it to stop with a flag. */ - pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording; - break; - } - /* Advance sample pointers. */ - if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels; - if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels; - } + PaMac_StartLoadCalculation( past ); /* CPU usage */ +#ifdef PA_MAX_USAGE_ALLOWED + /* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */ + if( past->past_Usage > PA_MAX_USAGE_ALLOWED ) + { + past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer; + } + else +#endif + { + + for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) + { + result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr ); + if( result != 0) + { + /* Recording might be in another process, so tell it to stop with a flag. */ + pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording; + break; + } + /* Advance sample pointers. */ + if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels; + if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels; + } + } + PaMac_EndLoadCalculation( past ); } return result; @@ -1505,8 +1570,10 @@ static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndComm pahsc = (PaHostSoundControl *) past->past_DeviceData; pahsc->pahsc_NumOutsPlayed += 1; - pahsc->pahsc_NumFramesDone += pahsc->pahsc_FramesPerHostBuffer; + SetFramesDone( pahsc, + pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer ); + PaMac_BackgroundManager( past, theCallBackCmd->param1 ); } @@ -1558,16 +1625,19 @@ static void PaMac_PlayNext ( internalPortAudioStream *past, int index ) /* If this was the last buffer, or abort requested, then just be done. */ if ( past->past_StopSoon ) goto done; + /* Load buffer with sound. */ result = PaMac_FillNextOutputBuffer ( past, index ); if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */ else if( result < 0 ) goto done; + /* Play the next buffer. */ playCmd.cmd = bufferCmd; playCmd.param1 = 0; playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ]; error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true ); if( error != noErr ) goto gotError; + /* Ask for a callback when it is done. */ callbackCmd.cmd = callBackCmd; callbackCmd.param1 = index; From fb351c801a51ec7c5460d86a04c9d8e72ff55ff5 Mon Sep 17 00:00:00 2001 From: philburk Date: Wed, 24 Apr 2002 16:19:50 +0000 Subject: [PATCH 066/814] Fixed return value in Pa_StreamTime --- pa_mac/pa_mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pa_mac/pa_mac.c b/pa_mac/pa_mac.c index 414a73b..7a8e030 100644 --- a/pa_mac/pa_mac.c +++ b/pa_mac/pa_mac.c @@ -49,6 +49,7 @@ PLB20020423 - Use new method to calculate CPU load similar to other ports. Based on num frames calculated. Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer. Added PA_MAX_USAGE_ALLOWED to prevent Mac form hanging when CPU load approaches 100%. + PLB20020424 - Fixed return value in Pa_StreamTime */ /* @@ -1372,7 +1373,7 @@ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) microsElapsed = U64Subtract( now64, whenIncremented ); framesElapsed = microsElapsed * past->past_SampleRate * 0.000001; - return pahsc->pahsc_NumFramesDone + framesElapsed; + return framesDone1 + framesElapsed; } /************************************************************************** From 09a767d44c464f0cc537a148b2d1f1283f60b69c Mon Sep 17 00:00:00 2001 From: stephane Date: Tue, 30 Apr 2002 12:33:04 +0000 Subject: [PATCH 067/814] Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling --- pa_asio/pa_asio.cpp | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/pa_asio/pa_asio.cpp b/pa_asio/pa_asio.cpp index 269dc59..a2d7d82 100644 --- a/pa_asio/pa_asio.cpp +++ b/pa_asio/pa_asio.cpp @@ -56,6 +56,7 @@ 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz 12-04-02 Add Mac includes for and : Phil Burk 13-04-02 Removes another compiler warning : Stephane Letz + 30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz TO DO : @@ -432,9 +433,13 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) int i; int numDrivers; ASIOError asioError; - - /* Allocate names */ - for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) names[i] = (char*)PaHost_AllocateFastMemory(32); + + /* Allocate names */ + for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) { + names[i] = (char*)PaHost_AllocateFastMemory(32); + /* check memory */ + if(!names[i]) return paInsufficientMemory; + } /* MUST BE CHECKED : to force fragments loading on Mac */ Pa_ASIO_loadAsioDriver("dummy"); @@ -473,9 +478,8 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) } else { - - /* Gets the name */ - dev = &(ipad[driver].pad_Info); + /* Gets the name */ + dev = &(ipad[sNumDevices].pad_Info); dev->name = names[driver]; names[driver] = 0; @@ -487,7 +491,12 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) DBUG(("PaASIO_QueryDeviceInfo: OutputChannels = %d\n", OutputChannels )); /* Make room in case device supports all rates. */ - sampleRates = (double*)PaHost_AllocateFastMemory( MAX_NUMSAMPLINGRATES * sizeof(double)); + sampleRates = (double*)PaHost_AllocateFastMemory(MAX_NUMSAMPLINGRATES * sizeof(double)); + /* check memory */ + if (!sampleRates) { + ASIOExit(); + return paInsufficientMemory; + } dev->sampleRates = sampleRates; dev->numSampleRates = 0; @@ -495,7 +504,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) { if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) { DBUG(("PortAudio : possible sample rate = %d\n", (long)possibleSampleRates[index])); - dev->numSampleRates+=1; + dev->numSampleRates += 1; *sampleRates = possibleSampleRates[index]; sampleRates++; } @@ -509,9 +518,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) dev->nativeSampleFormats = Pa_ASIO_Convert_SampleFormat(channelInfos.type); /* unload the driver */ - ASIODisposeBuffers(); ASIOExit(); - sNumDevices++; } } @@ -2560,8 +2567,9 @@ error: /***********************************************************************/ PaError PaHost_Init( void ) { - /* Have we already initialized the device info? */ - return (Pa_CountDevices() < 0 ) ? paHostError : paNoError; + /* Have we already initialized the device info? */ + PaError err = (PaError) Pa_CountDevices(); + return ( err < 0 ) ? err : paNoError; } /***********************************************************************/ @@ -2578,10 +2586,11 @@ PaError PaHost_Term( void ) for( i=0; isampleRates; - if((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double)); + if ((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double)); dev->sampleRates = NULL; - if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32); + if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32); dev->name = NULL; + } sNumDevices = 0; From 104ba1fd9bc3425bb78c0c6bc935706f012bb4b6 Mon Sep 17 00:00:00 2001 From: philburk Date: Tue, 30 Apr 2002 16:35:50 +0000 Subject: [PATCH 068/814] Checked in by Phil for Bill Eldridge Bills's mod: Made the libinstall and tests compile a bit cleaner --- Makefile.linux | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index 9f67ce6..4deee60 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -1,6 +1,8 @@ # Make PortAudio for Linux # Updated 2001/08/25 Bill Eldridge bill@rfa.org # Updated 2001/10/16, philburk@softsynth.com, s/unix_oss/unix_oss/ +# Updated 2002/04/30 Bill Eldridge bill@rfa.org +# Made the libinstall and tests compile a bit cleaner # A pretty bare makefile, that figures out all the test files # and compiles them against the library in the pa_unix_oss directory. @@ -19,23 +21,34 @@ CFLAGS = -g LIBINST = /usr/local/lib TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) +TESTO:= $(wildcard pa_tests/pa*.o pa_tests/debug*.o) LIBFILES:= ./pa_common/pa_lib.c ./pa_unix_oss/pa_unix_oss.c +#all: sharedlib libinstall tests +all: sharedlib libinstall testo testq + .c.o: -gcc -c -I./pa_common $< -o $*.o + +.o: -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio -all: sharedlib tests +#.c.o: +# -gcc -c -I./pa_common $< -o $*.o +# -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio + sharedlib: $(LIBFILES:.c=.o) gcc -shared -o ./pa_unix_oss/libportaudio.so ./pa_common/pa_lib.o ./pa_unix_oss/pa_unix_oss.o libinstall: ./pa_unix_oss/libportaudio.so @cp -f ./pa_unix_oss/libportaudio.so $(LIBINST) - @/sbin/ldconfig -v + @/sbin/ldconfig -tests: $(TESTS:.c=.o) +testo: $(TESTS:.c=.o) + +testq: $(TESTO:.o=) clean: -@rm -f $(TESTS:.c=.o) From e84dad6e88b8063151083a878a6a1b1931a4d6ae Mon Sep 17 00:00:00 2001 From: philburk Date: Tue, 30 Apr 2002 18:19:00 +0000 Subject: [PATCH 069/814] Use odd table size so it doesn't seem to work when it actually fails. --- pa_tests/pa_minlat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pa_tests/pa_minlat.c b/pa_tests/pa_minlat.c index 533b8c4..90b20df 100644 --- a/pa_tests/pa_minlat.c +++ b/pa_tests/pa_minlat.c @@ -45,7 +45,7 @@ #define TWOPI (M_PI * 2.0) #define DEFAULT_BUFFER_SIZE (64) -#define TABLE_SIZE (200) + typedef struct { double left_phase; From dc90ec9c91d6de75fec73051b06275bac78a9a5a Mon Sep 17 00:00:00 2001 From: philburk Date: Tue, 30 Apr 2002 18:57:44 +0000 Subject: [PATCH 070/814] Moved to patest_longsine.c --- pa_tests/debug_sine_wait.c | 138 ------------------------------------- 1 file changed, 138 deletions(-) delete mode 100644 pa_tests/debug_sine_wait.c diff --git a/pa_tests/debug_sine_wait.c b/pa_tests/debug_sine_wait.c deleted file mode 100644 index 863ae77..0000000 --- a/pa_tests/debug_sine_wait.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * $Id$ - * debug_sine_wait.c - * Play a sine wave using the Portable Audio api until we hit ENTER. - * - * Authors: - * Ross Bencina - * Phil Burk - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: 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. - * - */ -#include -#include -#include "portaudio.h" - -#define NUM_SECONDS (20) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (64) -#define NUM_BUFFERS (16) - -#ifndef M_PI -#define M_PI (3.14159265) -#endif - -#define TABLE_SIZE (200) -typedef struct -{ - float sine[TABLE_SIZE]; - int left_phase; - int right_phase; -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData*)userData; - float *out = (float*)outputBuffer; - unsigned long i; - int finished = 0; - (void) outTime; /* Prevent unused variable warnings. */ - (void) inputBuffer; - for( i=0; isine[data->left_phase]; /* left */ - *out++ = data->sine[data->right_phase]; /* right */ - data->left_phase += 1; - if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; - data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ - if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; - } - return finished; -} - -/*******************************************************************/ -int main(void); -int main(void) -{ - PortAudioStream *stream; - PaError err; - paTestData data; - int i; - printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); - /* initialise sinusoidal wavetable */ - for( i=0; i Date: Tue, 30 Apr 2002 21:21:30 +0000 Subject: [PATCH 071/814] Add some white space to make it readable. --- pa_tests/patest_longsine.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pa_tests/patest_longsine.c b/pa_tests/patest_longsine.c index 3d8bd4c..0e1e337 100644 --- a/pa_tests/patest_longsine.c +++ b/pa_tests/patest_longsine.c @@ -1,7 +1,7 @@ /* * $Id$ * patest_longsine.c - * Play a sine wave using the Portable Audio api forever. + * Play a sine wave using the Portable Audio api until ENTER hit. * * Author: Phil Burk http://www.softsynth.com * @@ -36,10 +36,13 @@ #include #include #include "portaudio.h" + #define SAMPLE_RATE (44100) + #ifndef M_PI #define M_PI (3.14159265) #endif + #define TABLE_SIZE (200) typedef struct { @@ -48,6 +51,7 @@ typedef struct int right_phase; } paTestData; + /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). @@ -72,6 +76,7 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, } return 0; } + /*******************************************************************/ int main(void); int main(void) @@ -81,14 +86,17 @@ int main(void) paTestData data; int i; printf("PortAudio Test: output sine wave.\n"); + /* initialise sinusoidal wavetable */ for( i=0; i Date: Thu, 2 May 2002 20:15:40 +0000 Subject: [PATCH 072/814] Reorganized code so that it is easier to test in a loop. --- pa_tests/debug_record.c | 166 ++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 64 deletions(-) diff --git a/pa_tests/debug_record.c b/pa_tests/debug_record.c index 6acd161..57b11f5 100644 --- a/pa_tests/debug_record.c +++ b/pa_tests/debug_record.c @@ -58,6 +58,7 @@ typedef struct long frameIndex; /* Index into sample array. */ long maxFrameIndex; long samplesPerFrame; + long numSamples; SAMPLE *recordedSamples; } paTestData; @@ -155,41 +156,19 @@ static int playCallback( void *inputBuffer, void *outputBuffer, } return finished; } -/*******************************************************************/ -int main(void); -int main(void) + +/****************************************************************/ +PaError TestRecording( paTestData *dataPtr ) { PortAudioStream *stream; PaError err; - paTestData data; - long totalFrames; - long numSamples; - long numBytes; - long i; - printf("patest_record.c\n"); fflush(stdout); - - data.frameIndex = 0; - data.samplesPerFrame = 2; - data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE; - - printf("totalFrames = %d\n", totalFrames ); fflush(stdout); - numSamples = totalFrames * data.samplesPerFrame; - numBytes = numSamples * sizeof(SAMPLE); - data.recordedSamples = (SAMPLE *) malloc( numBytes ); - if( data.recordedSamples == NULL ) - { - printf("Could not allocate record array.\n"); - exit(1); - } - for( i=0; isamplesPerFrame, /* stereo input */ PA_SAMPLE_TYPE, NULL, paNoDevice, @@ -201,7 +180,7 @@ int main(void) NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ recordCallback, - &data ); + dataPtr ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; @@ -214,62 +193,35 @@ int main(void) printf("Stream inactive!\n"); break; } - if( data.maxFrameIndex <= data.frameIndex ) + if( dataPtr->maxFrameIndex <= dataPtr->frameIndex ) { printf("Buffer recording complete.\n"); break; } Pa_Sleep(100); - printf("index = %d\n", data.frameIndex ); fflush(stdout); + printf("index = %d\n", dataPtr->frameIndex ); fflush(stdout); } + printf("Finished loop. Close stream.\n"); fflush(stdout); + err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; - /* Playback recorded data. */ - data.frameIndex = 0; - printf("Begin playback.\n"); fflush(stdout); - err = Pa_OpenStream( - &stream, - paNoDevice, - 0, /* NO input */ - PA_SAMPLE_TYPE, - NULL, - Pa_GetDefaultOutputDeviceID(), - data.samplesPerFrame, /* stereo output */ - PA_SAMPLE_TYPE, - NULL, - SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - playCallback, - &data ); - if( err != paNoError ) goto error; - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - printf("Waiting for playback to finish.\n"); fflush(stdout); - for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) - { - Pa_Sleep(100); - printf("index = %d\n", data.frameIndex ); - } - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error; + printf("Done.\n"); fflush(stdout); { SAMPLE max = 0; SAMPLE posVal; int i; - for( i=0; inumSamples; i++ ) { - posVal = data.recordedSamples[i]; + posVal = dataPtr->recordedSamples[i]; if( posVal < 0 ) posVal = -posVal; if( posVal > max ) max = posVal; } printf("Largest recorded sample = %d\n", max ); } /* Write recorded data to a file. */ -#if 1 +#if 0 { FILE *fid; fid = fopen("recorded.raw", "wb"); @@ -279,15 +231,101 @@ int main(void) } else { - fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid ); + fwrite( dataPtr->recordedSamples, dataPtr->samplesPerFrame * sizeof(SAMPLE), totalFrames, fid ); fclose( fid ); printf("Wrote data to 'recorded.raw'\n"); } } #endif + +error: + return err; +} + +/****************************************************************/ +PaError TestPlayback( paTestData *dataPtr ) +{ + PortAudioStream *stream; + PaError err; + int i; + + /* Playback recorded data. */ + dataPtr->frameIndex = 0; + printf("Begin playback.\n"); fflush(stdout); + err = Pa_OpenStream( + &stream, + paNoDevice, + 0, /* NO input */ + PA_SAMPLE_TYPE, + NULL, + Pa_GetDefaultOutputDeviceID(), + dataPtr->samplesPerFrame, /* stereo output */ + PA_SAMPLE_TYPE, + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + playCallback, + dataPtr ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Waiting for playback to finish.\n"); fflush(stdout); + for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) + { + Pa_Sleep(100); + printf("index = %d\n", dataPtr->frameIndex ); + } + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + +error: + return err; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err; + paTestData data; + long totalFrames; + long numBytes; + long i; + printf("patest_record.c\n"); fflush(stdout); + + data.frameIndex = 0; + data.samplesPerFrame = 2; + data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE; + + printf("totalFrames = %d\n", totalFrames ); fflush(stdout); + data.numSamples = totalFrames * data.samplesPerFrame; + + numBytes = data.numSamples * sizeof(SAMPLE); + data.recordedSamples = (SAMPLE *) malloc( numBytes ); + if( data.recordedSamples == NULL ) + { + printf("Could not allocate record array.\n"); + exit(1); + } + for( i=0; i Date: Thu, 2 May 2002 20:16:29 +0000 Subject: [PATCH 073/814] Demonstrate bug with Terratect where stream sample rates change! --- pa_tests/debug_record_reuse.c | 351 ++++++++++++++++++++++++++++++++++ pa_tests/debug_srate.c | 265 +++++++++++++++++++++++++ 2 files changed, 616 insertions(+) create mode 100644 pa_tests/debug_record_reuse.c create mode 100644 pa_tests/debug_srate.c diff --git a/pa_tests/debug_record_reuse.c b/pa_tests/debug_record_reuse.c new file mode 100644 index 0000000..46f937d --- /dev/null +++ b/pa_tests/debug_record_reuse.c @@ -0,0 +1,351 @@ +/* + * $Id$ + * debug_record_reuse.c + * Record input into an array. + * Save array to a file. + * Based on patest_record.c but with various ugly debug hacks thrown in. + * Loop twice and reuse same streams. + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + */ +#include +#include +#include +#include "portaudio.h" +#define SAMPLE_RATE (22050) +#define NUM_SECONDS (4) +#define SLEEP_DUR_MSEC (200) +#define FRAMES_PER_BUFFER (256) +#define NUM_REC_BUFS (0) + +#if 1 +#define PA_SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#else +#define PA_SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#endif + +typedef struct +{ + long frameIndex; /* Index into sample array. */ + long maxFrameIndex; + long samplesPerFrame; + long numSamples; + PortAudioStream *outputStream; + PortAudioStream *inputStream; + SAMPLE *recordedSamples; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int recordCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE *rptr = (SAMPLE*)inputBuffer; + SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; + long framesToCalc; + unsigned long i; + int finished; + unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; + + (void) outputBuffer; /* Prevent unused variable warnings. */ + (void) outTime; + + if( framesLeft < framesPerBuffer ) + { + framesToCalc = framesLeft; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + finished = 0; + } + if( inputBuffer == NULL ) + { + for( i=0; iframeIndex += framesToCalc; + return finished; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int playCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; + SAMPLE *wptr = (SAMPLE*)outputBuffer; + unsigned long i; + int finished; + unsigned int framesLeft = data->maxFrameIndex - data->frameIndex; + if( outputBuffer == NULL ) return 0; + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) outTime; + + if( framesLeft < framesPerBuffer ) + { + /* final buffer... */ + for( i=0; iframeIndex += framesLeft; + finished = 1; + } + else + { + for( i=0; iframeIndex += framesPerBuffer; + finished = 0; + } + return finished; +} + +/****************************************************************/ +PaError TestRecording( paTestData *dataPtr ) +{ + PaError err; + int i; + int lastIndex = 0; + +/* Open input stream if not already open. */ + if( dataPtr->inputStream == NULL ) + { + /* Record some audio. */ + err = Pa_OpenStream( + &dataPtr->inputStream, + Pa_GetDefaultInputDeviceID(), + dataPtr->samplesPerFrame, /* stereo input */ + PA_SAMPLE_TYPE, + NULL, + paNoDevice, + 0, + PA_SAMPLE_TYPE, + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + recordCallback, + dataPtr ); + if( err != paNoError ) goto error; + } + + dataPtr->frameIndex = 0; + + err = Pa_StartStream( dataPtr->inputStream ); + if( err != paNoError ) goto error; + + printf("Now recording!\n"); fflush(stdout); + for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) + { + int frameIndex, delta; + Pa_Sleep(SLEEP_DUR_MSEC); + + frameIndex = dataPtr->frameIndex; + if( Pa_StreamActive( dataPtr->inputStream ) <= 0) + { + printf("Stream inactive!\n"); + break; + } + if( dataPtr->maxFrameIndex <= frameIndex ) + { + printf("Buffer recording complete.\n"); + break; + } + + delta = frameIndex - lastIndex; + lastIndex = frameIndex; + printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout); + } + + err = Pa_StopStream( dataPtr->inputStream ); + if( err != paNoError ) goto error; + + printf("Done.\n"); fflush(stdout); + +error: + return err; +} + +/****************************************************************/ +PaError TestPlayback( paTestData *dataPtr ) +{ + PaError err; + int i; + int lastIndex = 0; + + /* Playback recorded data. */ + dataPtr->frameIndex = 0; + printf("Begin playback.\n"); fflush(stdout); + +/* Open output stream if not already open. */ + if( dataPtr->outputStream == NULL ) + { + err = Pa_OpenStream( + &dataPtr->outputStream, + paNoDevice, + 0, /* NO input */ + PA_SAMPLE_TYPE, + NULL, + Pa_GetDefaultOutputDeviceID(), + dataPtr->samplesPerFrame, /* stereo output */ + PA_SAMPLE_TYPE, + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + playCallback, + dataPtr ); + if( err != paNoError ) goto error; + } + + err = Pa_StartStream( dataPtr->outputStream ); + if( err != paNoError ) goto error; + + printf("Waiting for playback to finish.\n"); fflush(stdout); + for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) + { + int frameIndex, delta; + Pa_Sleep(SLEEP_DUR_MSEC); + frameIndex = dataPtr->frameIndex; + delta = frameIndex - lastIndex; + lastIndex = frameIndex; + printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout); + } + + err = Pa_StopStream( dataPtr->outputStream ); + if( err != paNoError ) goto error; + +error: + return err; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err; + paTestData data = { 0 }; + long totalFrames; + long numBytes; + long i; + printf("patest_record.c\n"); fflush(stdout); + +/* Set up test data structure and sample array. */ + data.frameIndex = 0; + data.samplesPerFrame = 2; + data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE; + + printf("totalFrames = %d\n", totalFrames ); fflush(stdout); + data.numSamples = totalFrames * data.samplesPerFrame; + + numBytes = data.numSamples * sizeof(SAMPLE); + data.recordedSamples = (SAMPLE *) malloc( numBytes ); + if( data.recordedSamples == NULL ) + { + printf("Could not allocate record array.\n"); + exit(1); + } + for( i=0; i +#include +#include +#include "portaudio.h" + +#define EWS88MT_12_REC (1) +#define EWS88MT_12_PLAY (10) +#define SBLIVE_REC (2) +#define SBLIVE_PLAY (11) + +#if 0 +#define INPUT_DEVICE_ID Pa_GetDefaultInputDeviceID() +#define OUTPUT_DEVICE_ID Pa_GetDefaultOutputDeviceID() +#else +#define INPUT_DEVICE_ID (EWS88MT_12_REC) +#define OUTPUT_DEVICE_ID (SBLIVE_PLAY) +#endif + +#define INPUT_SAMPLE_RATE (22050.0) +#define OUTPUT_SAMPLE_RATE (22050.0) +#define NUM_SECONDS (4) +#define SLEEP_DUR_MSEC (1000) +#define FRAMES_PER_BUFFER (64) +#define NUM_REC_BUFS (0) +#define SAMPLES_PER_FRAME (2) + +#define PA_SAMPLE_TYPE paInt16 +typedef short SAMPLE; + +typedef struct +{ + long frameIndex; /* Index into sample array. */ +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int recordCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData *) userData; + (void) outputBuffer; /* Prevent unused variable warnings. */ + (void) outTime; + + if( inputBuffer != NULL ) + { + data->frameIndex += framesPerBuffer; + } + return 0; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int playCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + paTestData *data = (paTestData *) userData; + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) outTime; + + if( outputBuffer != NULL ) + { + data->frameIndex += framesPerBuffer; + } + return 0; +} + +/****************************************************************/ +PaError MeasureStreamRate( PortAudioStream *stream, paTestData *dataPtr, double *ratePtr ) +{ + PaError err; + int i; + int totalFrames = 0; + int totalMSec = 0; + + dataPtr->frameIndex = 0; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) + { + int delta, endIndex; + + int startIndex = dataPtr->frameIndex; + Pa_Sleep(SLEEP_DUR_MSEC); + endIndex = dataPtr->frameIndex; + + delta = endIndex - startIndex; + totalFrames += delta; + totalMSec += SLEEP_DUR_MSEC; + + printf("index = %d, delta = %d\n", endIndex, delta ); fflush(stdout); + } + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + *ratePtr = (totalFrames * 1000.0) / totalMSec; + +error: + return err; +} + +void ReportRate( double measuredRate, double expectedRate ) +{ + double error; + + error = (measuredRate - expectedRate) / expectedRate; + error = (error < 0 ) ? -error : error; + + printf("Measured rate = %6.1f, expected rate = %6.1f\n", + measuredRate, expectedRate ); + if( error > 0.1 ) + { + printf("ERROR: unexpected rate! --------------------- ERROR!\n"); + } + else + { + printf("SUCCESS: rate within tolerance!\n"); + } +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err; + paTestData data = { 0 }; + long i; + double rate; + const PaDeviceInfo *pdi; + + PortAudioStream *outputStream; + PortAudioStream *inputStream; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + + pdi = Pa_GetDeviceInfo( INPUT_DEVICE_ID ); + printf("Input device = %s\n", pdi->name ); + pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE_ID ); + printf("Output device = %s\n", pdi->name ); + +/* Open input stream. */ + err = Pa_OpenStream( + &inputStream, + INPUT_DEVICE_ID, + SAMPLES_PER_FRAME, /* stereo input */ + PA_SAMPLE_TYPE, + NULL, + paNoDevice, + 0, + PA_SAMPLE_TYPE, + NULL, + INPUT_SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + recordCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_OpenStream( + &outputStream, + paNoDevice, + 0, /* NO input */ + PA_SAMPLE_TYPE, + NULL, + OUTPUT_DEVICE_ID, + SAMPLES_PER_FRAME, /* stereo output */ + PA_SAMPLE_TYPE, + NULL, + OUTPUT_SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + playCallback, + &data ); + if( err != paNoError ) goto error; + +/* Record and playback multiple times. */ + for( i=0; i<2; i++ ) + { + printf("Measuring INPUT ------------------------- \n"); + err = MeasureStreamRate( inputStream, &data, &rate ); + if( err != paNoError ) goto error; + ReportRate( rate, INPUT_SAMPLE_RATE ); + + printf("Measuring OUTPUT ------------------------- \n"); + err = MeasureStreamRate( outputStream, &data, &rate ); + if( err != paNoError ) goto error; + ReportRate( rate, OUTPUT_SAMPLE_RATE ); + } + +/* Clean up. */ + err = Pa_CloseStream( inputStream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( outputStream ); + if( err != paNoError ) goto error; + + if( err != paNoError ) goto error; + + Pa_Terminate(); + + printf("Test complete.\n"); fflush(stdout); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + if( err == paHostError ) + { + fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() ); + } + return -1; +} From 28558f3d967de9e28319d43d9d03bafed56b166d Mon Sep 17 00:00:00 2001 From: philburk Date: Sat, 4 May 2002 20:38:42 +0000 Subject: [PATCH 074/814] Checked in by Phil for Pieter Many fixes and changes: POLLIN for input, not POLLOUT. Open and close ALports in the audio-process-thread. Proper semaphore communication now. Hopefully stable enough now (for beta release?). --- pa_sgi/Makefile | 51 +- pa_sgi/pa_sgi.c | 1118 ++++++++++++++++++++------------------- pa_sgi/pthread-Makefile | 52 ++ pa_sgi/pthread-pa_sgi.c | 908 +++++++++++++++++++++++++++++++ 4 files changed, 1548 insertions(+), 581 deletions(-) create mode 100644 pa_sgi/pthread-Makefile create mode 100644 pa_sgi/pthread-pa_sgi.c diff --git a/pa_sgi/Makefile b/pa_sgi/Makefile index c631c9b..6548c6c 100644 --- a/pa_sgi/Makefile +++ b/pa_sgi/Makefile @@ -1,5 +1,6 @@ # Make PortAudio for Silicon Graphics IRIX (6.2) -# Pieter suurmond, august 17, 2001. (v15 pa_sgi sub-version #0.04) +# Pieter suurmond, september 23, 2001. (pa_sgi sub-version #0.21 for PA v15.) +# Based on SGI-specific sproc()-method to spawn children, not on POSIX-threads. # Instead of "-lpthread", as with linux, # just the audio- and math-library for SGI: @@ -14,36 +15,34 @@ CFLAGS = -O2 PASRC = ../pa_common/pa_lib.c pa_sgi.c PAINC = ../pa_common/portaudio.h -# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). -#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK -TESTC = $(PASRC) ../pa_tests/patest_record.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches. -#TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?). -#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK -#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. +# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). +TESTC = $(PASRC) ../pa_tests/patest_record.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_saw.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK +#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. + +# Tests that were not yet performed. +#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # test?? +#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # test?? +#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # test?? -# Tests that do not yet work. -#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default -#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default -#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-( - # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH. - # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON??? - # HMMM I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS! TESTH = $(PAINC) all: patest -#(cc may be changed to gcc) +# "cc" for the MIPSpro compiler, may be changed to "gcc": patest: $(TESTC) $(TESTH) Makefile cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest diff --git a/pa_sgi/pa_sgi.c b/pa_sgi/pa_sgi.c index 094cb4d..f67b1f0 100644 --- a/pa_sgi/pa_sgi.c +++ b/pa_sgi/pa_sgi.c @@ -1,10 +1,11 @@ /* * $Id$ - * PortAudio Portable Real-Time Audio Library + * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk. * Latest Version at: http://www.portaudio.com - * SGI IRIX implementation by Pieter Suurmond, aug 17, 2001. * - * Copyright (c) 1999-2000 Phil Burk + * Silicon Graphics IRIX implementation by Pieter Suurmond, september 23, 2001. + * pa_sgi-sub-version number 0.21, for PortAudio v15. + * This implementation uses the sproc()-method, not the POSIX method. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -28,55 +29,46 @@ * 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. - */ -/* + * Modfication History: 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. - 8/17/2001 - (v15 pa_sgi sub-version #0.04), wow, much is working now! Send this to Phil & Ross. - ID-stuff is nicer here now than in the linux_oss-alpha-version, v15. Was able to get - rid of a number of globals (like "sNumDevices" for instance). + 8/17/2001 - v15 pa_sgi sub-version #0.04 (unstable alpha release) Sent to Phil & Ross. + 9/23/2001 - #0.21 Many fixes and changes: POLLIN for input, not POLLOUT. + Open and close ALports in the audio-process-thread. + Proper semaphore communication now. + Hopefully stable enough now (for beta release?). TODO: - Test under IRIX 6.5. - - Maybe use pthread instead of (platform-specific) poll/select/pollfd-calls. - (As Gary Scavone more or less suggested(?)... But can I get enough process-control then?) - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), and maybe also the other natively supported formats? (might increase performance) - - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet, - seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?) - - Make sure that the fuzz-test doesn't let all IRIX crash (especially with higher buff-sizes). - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4. REFERENCES: - IRIX 6.2 man pages regarding SGI AL library. - - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and - may not be publically available on the internet). + - IRIS Digital MediaProgramming Guide (online books and man-pages come + with IRIX 6.2 and may not be publically available on the internet). */ #include /* Standard libraries. */ #include -#include -#include -#include -#include "portaudio.h" /* Portaudio headers. */ -#include "pa_host.h" -#include "pa_trace.h" +#include "../pa_common/portaudio.h" /* BETTER PATH !!!???? Portaudio headers. */ +#include "../pa_common/pa_host.h" +#include "../pa_common/pa_trace.h" -#include /* System specific (IRIX 6.2). */ +#include #include #include -#include -#include /* fcntl.h needed. */ -#include /* For streams, ioctl(), etc. */ -#include +#include /* For schedctl(NDPRI, NDPHIMIN). */ +#include /* fcntl.h needed. */ +#include /* For streams, ioctl(), etc. */ #include #include -#include -#include +#include /* System specific (IRIX 6.2). */ /*--------------------------------------------*/ #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) -#define DBUG(x) PRINT(x) +#define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ #define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */ @@ -84,103 +76,110 @@ REFERENCES: typedef struct internalPortAudioDevice /* IRIX specific device info: */ { - PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ - long pad_ALdevice; /* SGI-number! */ - double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ - char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ - PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ - /* int structVersion; */ - /* const char* name; */ - /* int maxInputChannels, maxOutputChannels; */ - /* int numSampleRates; Num rates, or -1 if range supprtd. */ - /* const double* sampleRates; Array of supported sample rates, */ - /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ - struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ -} -internalPortAudioDevice; + PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ + long pad_ALdevice; /* SGI-number! */ + double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ + char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ + PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ + /* int structVersion; */ + /* const char* name; */ + /* int maxInputChannels, maxOutputChannels; */ + /* int numSampleRates; Num rates, or -1 if range supprtd. */ + /* const double* sampleRates; Array of supported sample rates, */ + /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ + struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ +} internalPortAudioDevice; typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */ { - ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ - pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ - int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ - short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ - *pahsc_NativeOutputBuffer; - unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ - pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ - unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ - pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ - struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ - pahsc_LastExitTime; - long pahsc_InsideCountSum, - pahsc_TotalCountSum; -} -PaHostSoundControl; + ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */ + pahsc_ALconfigOUT; /* stucts separate for input and output ports. */ + ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ + pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ + int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ + short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ + *pahsc_NativeOutputBuffer; + unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ + pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ + unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ + pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ + struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ + pahsc_LastExitTime; + long pahsc_InsideCountSum, + pahsc_TotalCountSum; +} PaHostSoundControl; -/*----------------------------- Shared Data ------------------------------------------------------*/ -static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ -static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ +/*-------------------------------------------------------- Shared Data -------------------------------*/ +static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ +static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ +usema_t *SendSema, /* These variables are shared between the */ + *RcvSema; /* audio handling process and main process. */ +/*--------------------------*/ +long Pa_GetHostError(void) +{ + return (long)sPaHostError; +} /*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ /* (copied from source pa_linux_oss/pa_linux_oss.c) */ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { - struct itimerval itimer; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; - /* Query system timer for usage analysis and to prevent overuse of CPU. */ - getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); + struct itimerval itimer; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; +/* Query system timer for usage analysis and to prevent overuse of CPU. */ + getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); } static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) { - long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; - long usecs = secs * 1000000; - usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); - return usecs; + long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; + long usecs = secs * 1000000; + usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); + return usecs; } static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { - struct itimerval currentTime; - long insideCount; - long totalCount; /* Measure CPU utilization during this callback. */ + struct itimerval currentTime; + long insideCount; + long totalCount; /* Measure CPU utilization during this callback. */ #define LOWPASS_COEFFICIENT_0 (0.95) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if (pahsc == NULL) return; - if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) - { - if (past->past_IfLastExitValid) - { - insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); - pahsc->pahsc_InsideCountSum += insideCount; - totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); - pahsc->pahsc_TotalCountSum += totalCount; - /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ + if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) + { + if (past->past_IfLastExitValid) + { + insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); + pahsc->pahsc_InsideCountSum += insideCount; + totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); + pahsc->pahsc_TotalCountSum += totalCount; + /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ /* Low pass filter the result because sometimes we get called several times in a row. */ /* That can cause the TotalCount to be very low which can cause the usage to appear */ /* unnaturally high. So we must filter numerator and denominator separately!!! */ - if (pahsc->pahsc_InsideCountSum > 0) - { - past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); - past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); - past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; - pahsc->pahsc_InsideCountSum = 0; - pahsc->pahsc_TotalCountSum = 0; - } - } - past->past_IfLastExitValid = 1; - } - pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; - pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; - setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); - past->past_IfLastExitValid = 1; + if (pahsc->pahsc_InsideCountSum > 0) + { + past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); + past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + pahsc->pahsc_InsideCountSum = 0; + pahsc->pahsc_TotalCountSum = 0; + } + } + past->past_IfLastExitValid = 1; + } + pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; + pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; + setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); + past->past_IfLastExitValid = 1; } /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ @@ -189,56 +188,56 @@ PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL- { /* call to report via ERR_RPT(), yields a PaError-num. */ const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ - { - case AL_BAD_OUT_OF_MEM: - ERR_RPT(("%sout of memory.\n", a)); - return paInsufficientMemory; /* Known PaError. */ - case AL_BAD_CONFIG: - ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_CHANNELS: - ERR_RPT(("%schannels not 1,2 or 4.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_NO_PORTS: - ERR_RPT(("%sout of audio ports.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE: - ERR_RPT(("%swrong device number.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE_ACCESS: - ERR_RPT(("%swrong device access.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DIRECTION: - ERR_RPT(("%sinvalid direction.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_SAMPFMT: - ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_FLOATMAX: - ERR_RPT(("%smax float value is zero.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_WIDTH: - ERR_RPT(("%sunsupported samplewidth.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_QSIZE: - ERR_RPT(("%sinvalid queue size.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PVBUFFER: - ERR_RPT(("%sPVbuffer null.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_NEG: - ERR_RPT(("%snegative bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_ODD: - ERR_RPT(("%sodd bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PARAM: - ERR_RPT(("%sparameter not valid for device.\n", a)); - return paHostError; /* Generic PaError. */ - default: - ERR_RPT(("%sunknown error.\n", a)); - return paHostError; /* Generic PaError. */ - } + { + case AL_BAD_OUT_OF_MEM: + ERR_RPT(("%sout of memory.\n", a)); + return paInsufficientMemory; /* Known PaError. */ + case AL_BAD_CONFIG: + ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_CHANNELS: + ERR_RPT(("%schannels not 1,2 or 4.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_NO_PORTS: + ERR_RPT(("%sout of audio ports.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DEVICE: + ERR_RPT(("%swrong device number.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DEVICE_ACCESS: + ERR_RPT(("%swrong device access.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DIRECTION: + ERR_RPT(("%sinvalid direction.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_SAMPFMT: + ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_FLOATMAX: + ERR_RPT(("%smax float value is zero.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_WIDTH: + ERR_RPT(("%sunsupported samplewidth.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_QSIZE: + ERR_RPT(("%sinvalid queue size.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_PVBUFFER: + ERR_RPT(("%sPVbuffer null.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_BUFFERLENGTH_NEG: + ERR_RPT(("%snegative bufferlength.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_BUFFERLENGTH_ODD: + ERR_RPT(("%sodd bufferlength.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_PARAM: + ERR_RPT(("%sparameter not valid for device.\n", a)); + return paHostError; /* Generic PaError. */ + default: + ERR_RPT(("%sunknown error.\n", a)); + return paHostError; /* Generic PaError. */ + } } /*------------------------------------------------------------------------------------------*/ @@ -248,34 +247,34 @@ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT char* name, /* (for example "SGI AL") */ internalPortAudioDevice* pad) /* Result written to pad. */ { - int format; + int format; long min, max; /* To catch hardware characteristics. */ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ /*--------------------------------------------------------------------------------------*/ pad->pad_ALdevice = ALdev; /* Set the AL device number. */ pad->pad_DeviceID = id; /* Set the PA device number. */ if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ - { + { ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); return paHostError; - } + } strcpy(pad->pad_DeviceName, name); /* Write name-string. */ - pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ + pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ /*--------------------------------- natively supported sample formats: -----------------*/ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ - /* Then also choose other CallConvertXX()! */ + /* Then also choose other CallConvertXX()! */ /*--------------------------------- number of available i/o channels: ------------------*/ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) return translateSGIerror(); - pad->pad_Info.maxInputChannels = max; - DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) + pad->pad_Info.maxInputChannels = max; + DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) return translateSGIerror(); - pad->pad_Info.maxOutputChannels = max; - DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) - /*--------------------------------- supported samplerates: ----------------------*/ - pad->pad_Info.numSampleRates = 7; - pad->pad_Info.sampleRates = pad->pad_SampleRates; + pad->pad_Info.maxOutputChannels = max; + DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) + /*--------------------------------- supported samplerates: ----------------------*/ + pad->pad_Info.numSampleRates = 7; + pad->pad_Info.sampleRates = pad->pad_SampleRates; pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ pad->pad_SampleRates[1] = (double)AL_RATE_11025; pad->pad_SampleRates[2] = (double)AL_RATE_16000; @@ -290,18 +289,18 @@ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ return translateSGIerror(); if (max != (long)(0.5 + pad->pad_SampleRates[6])) - { + { weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); return paHostError; /* Or make it a warning and just carry on... */ - } - /*-------------------------------------------------------------------------------*/ - return paNoError; + } + /*-------------------------------------------------------------------------------*/ + return paNoError; } /*--------------------------------------------------------------------------------*/ int Pa_CountDevices() /* Name of this function suggests it only counts and */ -{ /* is NOT destructive, it however resets whole PA ! */ +{ /* is NOT destructive, it however resets whole PA ! */ int numDevices = 0; /* Let 's not do that here. */ internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ #if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ @@ -309,48 +308,45 @@ int Pa_CountDevices() /* Name of this function suggests it only counts and Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ #endif /* friendly to clients that forgot to initialize PA. */ while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ - { + { numDevices++; currentDevice = currentDevice->pad_Next; - } - return numDevices; + } + return numDevices; } - - /*-------------------------------------------------------------------------------*/ static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) { int numDevices = 0; internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; - internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ + internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ while (pad) /* pad may be NULL, that's ok, return 0. */ - { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ + { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ if (pad->pad_DeviceID == id) /* This the device we were looking for? */ res = pad; /* But keep on(!) counting so we don't */ numDevices++; /* have to call Pa_CountDevices() later. */ pad = pad->pad_Next; /* Advance to the next device or NULL. */ - } /* No assumptions about order of ID's in */ + } /* No assumptions about order of ID's in */ if (!res) /* the list. */ ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); if ((id < 0) || (id >= numDevices)) - { + { ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); #if 1 /* Be strict, even when found, */ res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ #endif - - } - return res; + } + return res; } /*----------------------------------------------------------------------*/ const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) { PaDeviceInfo* res = (PaDeviceInfo*)NULL; - internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ + internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ if (pad) - res = &pad->pad_Info; /* Not finding the specified ID is not */ + res = &pad->pad_Info; /* Not finding the specified ID is not */ if (!res) /* the same as &pad->pad_Info == NULL. */ ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); return res; /* So (maybe) a second/third ERR_RPT(). */ @@ -359,59 +355,55 @@ const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultInputDeviceID(void) { - return 0; /* 0 is the default device ID. */ + return 0; /* 0 is the default device ID. */ } /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultOutputDeviceID(void) { - return 0; + return 0; } -/*--------------------------------------------------------------------------------------*/ -/* Build linked list with all available audio devices on this SGI machine. */ -PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ +/*-------------------------------------------------------------------------------------------------*/ +/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */ +PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ { internalPortAudioDevice* pad; - PaError r = paNoError; - int audioLibFileID; + PaError r = paNoError; + int audioLibFileID; /* To test for the presence of audio. */ - if (sDeviceList) /* Allow re-init, only warn, no err. */ - { + if (sDeviceList) /* Allow re-init, only warn, no error. */ + { ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); return r; - } - /*------------- ADD THE SGI DEFAULT DEVICES TO THE LIST: --------------------------------------*/ + } + /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/ audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ if (audioLibFileID < 0) /* IO port. On failure, machine */ - { /* has no audio ability. */ + { /* has no audio ability. */ ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); return paHostError; - } + } close(audioLibFileID); /* Allocate fast mem to hold device info. */ - pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); - if (pad == NULL) + pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); + if (pad == NULL) return paInsufficientMemory; memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ - r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ + r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ "AL default", /* A suitable name. */ pad); /* Write args and queried info into pad. */ - if (r != paNoError) - { + if (r != paNoError) + { ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ - } + PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ + } else - sDeviceList = pad; /* First element in linked list (pad->pad_Next is already NULL). */ - /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LIST: --------------*/ - /*---------------------------------------------------------------------------------*/ - return r; + sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ + /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ + /*---------------------------------------------------------------------------------------------*/ + return r; } -/*------------------------------------------------------------------*/ -usema_t *SendSema, /* These variables are shared between the audio */ -*RcvSema; /* handling process and the main process. */ - /*--------------------------------------------------------------------------------------------*/ #define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */ #define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */ @@ -419,166 +411,186 @@ usema_t *SendSema, /* These variables are shared between the audio */ #define kPollIN 2 void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */ { /* as a separate thread. (Argument must be void*). */ - short evtLoop=1; /* Reset by parent indirectly, or at local errors. */ + short evtLoop; /* Reset by parent indirectly, or at local errors. */ PaError result; struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */ internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument.*/ - PaHostSoundControl *pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (pahsc == NULL) - { + PaHostSoundControl *pahsc; + short inputEvent, outputEvent, /* .revents members are of type short. */ + semaEvent = 0; + DBUG(("Entering sproc-thread.\n")); + if (!past) + { + sPaHostError = paInternalError; /* Or paBadStreamPtr ? */ + ERR_RPT(("argument NULL!\n")); + goto skip; + } + pahsc = (PaHostSoundControl*)past->past_DeviceData; + if (!pahsc) + { sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */ - goto skipALL; /* Sproc-ed threads MAY NOT RETURN paInternalError. */ - } - past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ - DBUG(("entering thread.\n")); + ERR_RPT(("past_DeviceData NULL!\n")); + goto skip; /* Sproc-ed threads MAY NOT RETURN paInternalError. */ + } + /*----------------------------- open AL-ports here, after sproc(): -----------------------*/ + if (past->past_NumInputChannels > 0) /* Open input port. */ + { + pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN); + if (!pahsc->pahsc_ALportIN) + { + ERR_RPT(("Failed to open AL input port.\n")); + sPaHostError = paInternalError; + goto skip; + } + DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels)); + } + if (past->past_NumOutputChannels > 0) /* Open output port. */ + { + pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT); + if (!pahsc->pahsc_ALportOUT) + { + ERR_RPT(("Failed to open AL output port.\n")); + sPaHostError = paInternalError; /* Assume pahsc_ALconfigs are the */ + goto skip; /* same for IN and OUT in case */ + } /* both ports are opened (bidir). */ + DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels)); + } + /*-----------------------------------------------------------------------*/ + past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */ - PollFD[kPollIN].events = POLLOUT; /* such as ALport not there. */ - /* .events = POLLOUT ??? ok? */ + PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */ PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT); PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */ schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */ PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */ PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */ - uspsema(SendSema); /* Blocks until the next (first)signal is received???? */ - do - { + uspsema(SendSema); /* Blocks until ... MUST be here, this uspsema(). */ + evtLoop = ((past->past_StopNow | past->past_StopSoon) == 0); + while (evtLoop) + { /*---------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ----------*/ if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */ /* For input port, fill point is number of locations in the sample queue that must be */ /* filled in order to trigger a return from select(). (or poll()) */ /* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/ - if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputBuffer)) - { /* Same amount as transferred per time. */ + if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputBuffer)) + { /* Same amount as transferred per time. */ ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n")); sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ - goto skipIO; - } + goto skip; + } if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */ /* For output port, fill point is number of locations that must be free in order to */ /* wake up from select(). (or poll()) */ - if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputBuffer)) - { + if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputBuffer)) + { ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n")); sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ - goto skipIO; - } /* poll() with timeout=-1 makes it block until a requested */ - poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */ - /* array <0, events is ignored and revents is set to 0. */ + goto skip; + } /* poll() with timeout=-1 makes it block until a requested */ + poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */ + /* array <0, events is ignored and revents is set to 0. */ /*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/ - if (PollFD[kPollSEMA].revents & POLLIN) - { - if (past->past_StopNow || past->past_StopSoon) + semaEvent = PollFD[kPollSEMA].revents & POLLIN; + if (semaEvent) + { + if (past->past_StopSoon) evtLoop = 0; - uspsema(SendSema); /* Decrements count of previously allocated semaphore SendSema. If count */ - /* is then negative, semaphore will logically block calling process until */ - /* count is incremented due to an usvsema call made by another process. */ - usvsema(RcvSema); /* Increments the count associated with RcvSema. If there are any */ - /* processes queued waiting for the semaphore the first one is awakened. */ - /* Here usvsema sends an acknowledgement to the "SendAudioCommand()". */ if (past->past_StopNow) - goto skipIO; /* Else go on for a little while... */ - } - /*------------------------------------- FREE-EVENT FROM INPUT BUFFER: ----------------------------*/ - if (PollFD[kPollIN].revents & POLLOUT) /* Don't need to check (pahsc->pahsc_NativeInputBuffer): */ - { /* if buffer was not there, ALport not there, no events! */ + goto skip; + } + /*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/ + inputEvent = PollFD[kPollIN].revents & POLLIN; + if (inputEvent) /* Don't need to check (pahsc->pahsc_NativeInputBuffer): */ + { /* if buffer was not there, ALport not there, no events! */ if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_SamplesPerInputBuffer)) - { /* Here again: number of samples instead of number of frames. */ + { /* Here again: number of samples instead of number of frames. */ ERR_RPT(("ALreadsamps() failed.\n")); sPaHostError = paInternalError; - goto skipIO; /* (Using exit(-1) would be a bit rude.) */ + goto skip; + } } - } + outputEvent = PollFD[kPollOUT].revents & POLLOUT; /*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/ - if ((PollFD[kPollIN].revents & POLLOUT) || (PollFD[kPollOUT].revents & POLLOUT)) - { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */ - /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */ - Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ - result = Pa_CallConvertInt16(past, /* user data and call user routine. */ - pahsc->pahsc_NativeInputBuffer, - pahsc->pahsc_NativeOutputBuffer); - Pa_EndUsageCalculation(past); - if (result) - { - DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); - goto skipIO; /* But it is apparently NOT an error! */ - } /* Just letting the userCallBack stop us. */ - } - /*------------------------------------- FILLED-EVENT FROM OUTPUT BUFFER: -------------------------*/ - if (PollFD[kPollOUT].revents & POLLOUT) /* Don't need to check (pahsc->pahsc_NativeOutputBuffer) */ - { /* because if filedescriptor not there, no event for it. */ + if (inputEvent | outputEvent) /* (Bitwise is ok.) */ + { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */ + /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */ + Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ + result = Pa_CallConvertInt16(past, /* user data and call user routine. */ + pahsc->pahsc_NativeInputBuffer, + pahsc->pahsc_NativeOutputBuffer); + Pa_EndUsageCalculation(past); + if (result) + { + DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); + goto skip; /* This is apparently NOT an error! */ + } /* Just letting the userCallBack stop us. */ + } + /*------------------------------------- FREE-EVENT FROM OUTPUT BUFFER: ---------------------------*/ + if (outputEvent) /* Don't need to check (pahsc->pahsc_NativeOutputBuffer) */ + { /* because if filedescriptor not there, no event for it. */ if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_SamplesPerOutputBuffer)) - { - ERR_RPT(("ALwritesamps() failed.\n")); - sPaHostError = paInternalError; /* Better use SEMAS also for messaging back to parent! */ - goto skipIO; - } + { + ERR_RPT(("ALwritesamps() failed.\n")); /* Better use SEMAS for messaging back to parent! */ + sPaHostError = paInternalError; + goto skip; + } + } + } +skip: + /*------------------------------- close AL-ports ----------------------------*/ + if (pahsc->pahsc_ALportIN) + { + if (ALcloseport(pahsc->pahsc_ALportIN)) + translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ + else /* But go on anyway... to release other stuff... */ + pahsc->pahsc_ALportIN = (ALport)0; + } + if (pahsc->pahsc_ALportOUT) + { + if (ALcloseport(pahsc->pahsc_ALportOUT)) + translateSGIerror(); + else + pahsc->pahsc_ALportOUT = (ALport)0; } - /*------------------------------------------------------------------------------------------------*/ - } - while (evtLoop); /* Set at init-time, only reset indirectly via semaphore, */ -skipIO: /* or in case of error, only within this loop. */ - DBUG(("leaving thread.\n")); /* Don't we need to cleanup semaphore-stuff / thread itself? */ -skipALL: /* (make threadPID in the struct -1 again, for instance?) */ past->past_IsActive = 0; - pahsc->pahsc_threadPID == -1; /* Signal back, so StopEngine() for example won't call KILL().... hmmm doesn't work yet! */ - /* SHIT: when this process ends, it also KILLS of the parent!!! because sigint = kill?? */ - exit(0); /* Unix process. SIGCLD is sent to parent (if prctl wa called with 0 by parent). */ -} /* if prctl was called with 9 by parent, then when this process ends, it also */ -/* KILLS off the parent!!! */ + if (semaEvent) + { + uspsema(SendSema); /* StopEngine() was still waiting for this acknowledgement. */ + usvsema(RcvSema); /* (semaEvent initialized with 0.) */ + } + DBUG(("Leaving sproc-thread.\n")); +} + +#define kALinternalQueuesizeFact 4L /* Internal queue 4 times as large as transferSize. */ + /* Used below, twice: for input and for output. */ /*--------------------------------------------------------------------------------------*/ PaError PaHost_OpenStream(internalPortAudioStream *past) { - PaError result = paNoError; - PaHostSoundControl *pahsc; - unsigned int minNumBuffers; - internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ - ALconfig sgiALconfig = NULL; /* IRIX-datatype. */ + PaError result = paNoError; + PaHostSoundControl *pahsc; + unsigned int minNumBuffers; + internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ long pvbuf[8]; /* To get/set hardware configs. */ - long sr, ALqsize; + long sr; DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ if (!past) - { + { ERR_RPT(("Streampointer NULL!\n")); result = paBadStreamPtr; goto done; - } - pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); - if (pahsc == NULL) - { + } + pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); + if (pahsc == NULL) + { ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ - } - memset(pahsc, 0, sizeof(PaHostSoundControl)); /* Hmmm, not too elegant, besides, the */ - pahsc->pahsc_threadPID = -1; /* pahsc_threadPID must be inited to */ - past->past_DeviceData = (void*)pahsc; /* -1 instead of 0! ?? */ - /*--------------------------------------------------- Allocate native buffers: --------*/ - pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumInputChannels; /* audio-thread. */ - pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); - if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */ - { - pahsc->pahsc_NativeInputBuffer = (short *) malloc(pahsc->pahsc_BytesPerInputBuffer); - if( pahsc->pahsc_NativeInputBuffer == NULL ) - { - ERR_RPT(("(normal yet) Memory allocation failed.\n")); - result = paInsufficientMemory; - goto done; - } - } - pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumOutputChannels; /* audio-thread. */ - pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); - if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */ - { - pahsc->pahsc_NativeOutputBuffer = (short *) malloc(pahsc->pahsc_BytesPerOutputBuffer); - if (pahsc->pahsc_NativeOutputBuffer == NULL) - { - ERR_RPT(("(normal yet) Memory allocation failed.\n")); - result = paInsufficientMemory; goto done; - } - } + } + memset(pahsc, 0, sizeof(PaHostSoundControl)); + pahsc->pahsc_threadPID = -1; /* Should pahsc_threadPID be inited to */ + past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ pvbuf[0] = AL_INPUT_RATE; @@ -586,139 +598,129 @@ PaError PaHost_OpenStream(internalPortAudioStream *past) pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ pvbuf[6] = AL_OUTPUT_COUNT; sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */ - if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ - { /* sponding native AL-number(s). */ + /*---------------------------------------------------- SET INPUT CONFIGURATION: ------------------------*/ + if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ + { /* sponding native AL-number(s). */ + /*--------------------------------------------------- Allocate native buffers: --------*/ + pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumInputChannels; /* audio-thread. */ + pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); + pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer); + if (!pahsc->pahsc_NativeInputBuffer) + { + ERR_RPT(("Fast memory allocation failed (in).\n")); + result = paInsufficientMemory; + goto done; + } padIN = Pa_GetInternalDevice(past->past_InputDeviceID); if (!padIN) - { + { ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); - result = paHostError; goto done; - } + result = paHostError; + goto done; + } if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ goto sgiError; /* the same AL-device, the AL-library might */ if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ - { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ + { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ - { + { ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ - another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); - result = paHostError; goto done; - } +another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); + result = paHostError; + goto done; + } pvbuf[1] = sr; /* Then set input-rate. */ if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) - goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ + goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ + } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */ + pahsc->pahsc_ALconfigIN = ALnewconfig(); /* Released at PaHost_CloseStream(). */ + if (pahsc->pahsc_ALconfigIN == (ALconfig)0) + goto sgiError; + if (ALsetsampfmt(pahsc->pahsc_ALconfigIN, AL_SAMPFMT_TWOSCOMP))/* Choose paInt16 as native i/o-format. */ + goto sgiError; + if (ALsetwidth (pahsc->pahsc_ALconfigIN, AL_SAMPLE_16)) /* Only meaningful when sample format for */ + goto sgiError; /* config is set to two's complement format. */ + /************************ Future versions might (dynamically) switch to 32-bit floats? ******* + if (ALsetsampfmt(pahsc_ALconfigIN, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) + goto sgiError; + if (ALsetfloatmax (pahsc_ALconfigIN, 1.0)) Only meaningful when sample format for config + goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ + /*--------- Set internal AL queuesize (in samples) -------------------------------*/ + if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, (long)pahsc->pahsc_SamplesPerInputBuffer * + (long)kALinternalQueuesizeFact)) + goto sgiError; /* Or should we use past_NumUserBuffers here? */ + /* Do 4 timea, using 2 times may give glitches. */ + if (ALsetchannels (pahsc->pahsc_ALconfigIN, (long)(past->past_NumInputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ } - } - if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels<=0! */ - { /* We use padOUT/IN later on, or at least 1 of both. */ + /*---------------------------------------------------- SET OUTPUT CONFIGURATION: ------------------------*/ + if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ + { /* We use padOUT/IN later on, or at least 1 of both. */ + pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumOutputChannels; /* audio-thread. */ + pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); + + pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer); + if (!pahsc->pahsc_NativeOutputBuffer) + { + ERR_RPT(("Fast memory allocation failed (out).\n")); + result = paInsufficientMemory; + goto done; + } padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); if (!padOUT) - { + { ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); - result = paHostError; goto done; - } + result = paHostError; + goto done; + } if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) goto sgiError; - if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr)) - { /* Output needed and rate different from current harware-rate. */ + if (pvbuf[5] != sr) + { /* Output needed and rate different from current harware-rate. */ if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ - { + { ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ - another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); - result = paHostError; goto done; /* Will free again the inputbuffer */ - } /* that was just created above. */ +another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); + result = paHostError; + goto done; /* Will free again the inputbuffer */ + } /* that was just created above. */ pvbuf[5] = sr; /* Then set output-rate. */ if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) goto sgiError; + } + pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */ + if (pahsc->pahsc_ALconfigOUT == (ALconfig)0) + goto sgiError; + if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ + goto sgiError; + if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */ + goto sgiError; /* config is set to two's complement format. */ + /************************************ Future versions might (dynamically) switch to 32-bit floats? *******/ + if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, (long)pahsc->pahsc_SamplesPerOutputBuffer * + (long)kALinternalQueuesizeFact)) + goto sgiError; /* Or should we use past_NumUserBuffers here?*/ + if (ALsetchannels (pahsc->pahsc_ALconfigOUT, (long)(past->past_NumOutputChannels))) + goto sgiError; } - } - /*------------------------------------------ Construct an audio-port-configuration ----------*/ - sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */ - if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */ - goto sgiError; /* See that sgiALconfig is NOT released! */ - if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ - goto sgiError; - if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */ - goto sgiError; /* config is set to two's complement format. */ - /************************ Future versions might (dynamically) switch to 32-bit floats? ******* - if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) - goto sgiError; - if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config - goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ /*---------- ?? --------------------*/ - /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */ + /* 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; - /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/ - if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer) - ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer; - else /* Take the largest of the two amounts. */ - ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer; - ALqsize *= 4; /* 4 times as large as amount per transfer! */ - if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */ - goto sgiError; /* Using 2 times may give glitches... */ - /* Have to work on ALsetqueuesize() above, fillpoints in the thread are ok now. */ - - /* Do ALsetchannels() later, apart per input and/or output. */ - /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/ - if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */ - { - if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) - { - DBUG(("PaHost_OpenStream: opening both input and output channels.\n")); - /*------------------------- open output port: ----------------------------------*/ - if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); - if (pahsc->pahsc_ALportOUT == (ALport)0) - goto sgiError; - /*------------------------- open input port: -----------------------------------*/ - if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); - if (pahsc->pahsc_ALportIN == (ALport)0) - goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */ - } /* Probably due to too small buffersizes?.... */ - else - { - ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); - result = paHostError; - goto done; + past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ? + minNumBuffers : past->past_NumUserBuffers; /* I don't yet use past_NumUserBuffers */ + /*----------------------------------------------- TEST DEVICE ID's: --------------------*/ + if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */ + (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) + { + ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); + result = paHostError; + goto done; } - } - else /* (OutputDeviceID != InputDeviceID) */ - { - if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */ - { - /*------------------------- open output port: ----------------------------------*/ - DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n", - past->past_NumOutputChannels, padOUT->pad_DeviceName)); - if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); - if (pahsc->pahsc_ALportOUT == (ALport)0) - goto sgiError; - } - if (past->past_NumInputChannels > 0) /* READ-ONLY: */ - { - /*------------------------- open input port: -----------------------------------*/ - DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n", - past->past_NumInputChannels, padIN->pad_DeviceName)); - if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); - if (pahsc->pahsc_ALportIN == (ALport)0) - goto sgiError; - } - } - DBUG(("PaHost_OpenStream() succeeded.\n")); goto done; /* (no errors occured) */ -sgiError: +sgiError: result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ done: - if (sgiALconfig) - ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */ if (result != paNoError) PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ return result; @@ -727,159 +729,165 @@ done: /*-----------------------------------------------------*/ PaError PaHost_StartOutput(internalPortAudioStream *past) { - return paNoError; /* Hmm, not implemented yet? */ + return paNoError; /* Hmm, not implemented yet? */ } PaError PaHost_StartInput(internalPortAudioStream *past) { - return paNoError; + return paNoError; } /*------------------------------------------------------------------------------*/ PaError PaHost_StartEngine(internalPortAudioStream *past) { - PaHostSoundControl *pahsc; + PaHostSoundControl *pahsc; usptr_t *arena; if (!past) /* Test argument. */ - { + { ERR_RPT(("PaHost_StartEngine(NULL)!\n")); return paBadStreamPtr; - } + } pahsc = (PaHostSoundControl*)past->past_DeviceData; if (!pahsc) - { + { ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n")); return paHostError; - } - past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ - past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */ + } + past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ + past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */ past->past_IsActive = 1; - + /* Although the pthread_create() function, as well as , may be */ /* available in IRIX, use sproc() on SGI to create audio-background-thread. */ /* (Linux/oss uses pthread_create() instead of __clone() because: */ /* - pthread_create also works for other UNIX systems like Solaris, */ /* - Java HotSpot VM crashes in pthread_setcanceltype() using __clone().) */ - + usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* (From SGI-AL-examples, file */ arena = usinit(tmpnam(0)); /* motifexample.c, function */ SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */ - RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process - will be permitted through a semaphore at a time. Values > 1 - imply that up to val resources may be simultaneously used, but requests - for more than val resources cause the calling process to block until a - resource comes free (by a process holding a resource performing a - usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */ - prctl(PR_SETEXITSIG, 0);/* No not (void*)9, but 0, which doesn't kill the parent! */ - /* PR_SETEXITSIG controls whether all members of a share group will be - signaled if any one of them leaves the share group - (either via exit() or exec()). If second - argument, interpreted as an int is 0, then normal IRIX - process termination rules apply, namely that the parent - is sent a SIGCLD upon death of child, but no indication - of death of parent is given. If the second argument is - a valid signal number then if any member - of a share group leaves the share group, a signal is - sent to ALL surviving members of the share group. */ + RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process + will be permitted through a semaphore at a time. Values > 1 + imply that up to val resources may be simultaneously used, but requests + for more than val resources cause the calling process to block until a + resource comes free (by a process holding a resource performing a + usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */ + prctl(PR_SETEXITSIG, 0); /* No not (void*)9, but 0, which doesn't kill the parent! */ + /* PR_SETEXITSIG controls whether all members of a share group will be + signaled if any one of them leaves the share group (either via exit() + or exec()). If 2nd arg, interpreted as an int is 0, then normal IRIX + process termination rules apply, namely that the parent is sent a + SIGCLD upon death of child, but no indication of death of parent is + given. If the second argument is a valid signal number then if any + member of a share group leaves the share group, a signal is + sent to ALL surviving members of the share group. */ /* SPAWN AUDIO-CHILD: */ pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */ PR_SALL, /* new process, or -1. */ - (void*)past); /* Pass past as optional */ - if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ - { + (void*)past); /* Pass past as optional */ /* IS THIS SAFE, will past never */ + if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ /* be moved around in memory???? */ + { ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); sPaHostError = oserror(); /* Pass native error-number to shared area. */ return paHostError; /* But return the generic error-number. */ - } + } return paNoError; /* Hmmm, errno may come from other threads in same group! */ } /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */ /*------------------------------------------------------------------------------*/ PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) { - int hres; - long timeOut; - PaError result = paNoError; - PaHostSoundControl *pahsc = (PaHostSoundControl*)past->past_DeviceData; - - if (pahsc == NULL) - return result; /* paNoError */ + int hres; + long timeOut; + PaError result = paNoError; + PaHostSoundControl *pahsc; + + DBUG(("PaHost_StopEngine() called.\n")); + if (!past) + return paBadStreamPtr; + pahsc = (PaHostSoundControl*)past->past_DeviceData; + /* Prevent from doing this twice!! */ + if ((!pahsc) || /* Some tests call this CLOSE twice!! */ + (!past->past_IsActive) || + past->past_StopSoon || past->past_StopNow) + return result; /* paNoError (already stopped, no err?). */ past->past_StopSoon = 1; /* Tell background thread to stop generating */ if (abort) /* more and to let current data play out. If */ past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ - - /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/ + /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/ usvsema(SendSema); /* Increments count associated with SendSema. */ - /* Wait for the response. */ + /* Wait for the response. */ uspsema(RcvSema); /* Decrements count of previously allocated */ - /* semaphore specified by RcvSema. */ - /* Must be sure sub-process is really there,... otherwise above semas block?! */ - if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */ - { - /* How to JOIN a "sproc"-thread to recover memory resources????? */ - /* hres = pthread_join( pahsc->pahsc_ThreadPID, NULL ); */ - DBUG(("PaHost_StopEngine() is about to KILL(SIGKILL) audio-thread.\n")); + /* semaphore specified by RcvSema. */ + while (past->past_IsActive) /* REALLY WAIT. */ + { + /* DBUG(("wait 1 ms for audio-thread to stop.\n")); */ + Pa_Sleep(1); + } + +#if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */ + if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */ + { + DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n")); if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */ - { /* Returns -1 in case of error. */ + { /* Returns -1 in case of error. */ result = paHostError; sPaHostError = oserror(); /* Hmmm, other threads may also write here! */ ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n")); - } + } else pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */ - } + } +#endif past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */ - return result; + return result; } /*---------------------------------------------------------------*/ PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) { - return paNoError; /* Not implemented yet? */ + return paNoError; /* Not implemented yet? */ } PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) { - return paNoError; + return paNoError; } /*******************************************************************/ PaError PaHost_CloseStream(internalPortAudioStream *past) { - PaHostSoundControl *pahsc; + PaHostSoundControl *pahsc; PaError result = paNoError; - - if (past == NULL) + + DBUG(("PaHost_CloseStream() called.\n")); + if (!past) return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ - return result; /* This test prevents from freeing NULL-pointers. */ + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ + return result; /* This test prevents from freeing NULL-pointers. */ - if (pahsc->pahsc_ALportIN) - { - if (ALcloseport(pahsc->pahsc_ALportIN)) - result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ - else /* But go on anyway... to release other stuff... */ - pahsc->pahsc_ALportIN = (ALport)0; - } - if (pahsc->pahsc_ALportOUT) - { - if (ALcloseport(pahsc->pahsc_ALportOUT)) - result = translateSGIerror(); - else - pahsc->pahsc_ALportOUT = (ALport)0; - } - if (pahsc->pahsc_NativeInputBuffer) - { - free(pahsc->pahsc_NativeInputBuffer); - pahsc->pahsc_NativeInputBuffer = NULL; - } - if (pahsc->pahsc_NativeOutputBuffer) - { - free(pahsc->pahsc_NativeOutputBuffer); - pahsc->pahsc_NativeOutputBuffer = NULL; - } - PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); /* Not just free(pahsc) because */ - past->past_DeviceData = NULL; /* PaHost_OpenStream(); allocated FAST (thus mpinned?) MEM. */ - return result; + if (pahsc->pahsc_ALconfigIN) + { /* Release configuration structs, only if allocated. */ + ALfreeconfig(pahsc->pahsc_ALconfigIN); + pahsc->pahsc_ALconfigIN = NULL; + } + if (pahsc->pahsc_ALconfigOUT) + { + ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */ + pahsc->pahsc_ALconfigOUT = NULL; + } + if (pahsc->pahsc_NativeInputBuffer) + { + PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer); + pahsc->pahsc_NativeInputBuffer = NULL; + } + if (pahsc->pahsc_NativeOutputBuffer) + { + PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); + pahsc->pahsc_NativeOutputBuffer = NULL; + } + PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); + past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */ + return result; } /************************************************************************* @@ -895,7 +903,7 @@ PaError PaHost_CloseStream(internalPortAudioStream *past) int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { - return 2; + return 2; } /* Hmmm, the note above isn't appropriate for SGI I'm afraid... */ /* Do we HAVE to do it this way under IRIX???.... */ @@ -903,32 +911,32 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) /*---------------------------------------------------------------------*/ -PaError PaHost_Term(void) /* Frees all of the linked devices. */ +PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ { /* Called by Pa_Terminate() from pa_lib.c. */ - internalPortAudioDevice *pad = sDeviceList, - *nxt; - while (pad) - { - DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); + internalPortAudioDevice *pad = sDeviceList, + *nxt; + while (pad) + { + DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); nxt = pad->pad_Next; - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); - pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ - } - sDeviceList = (internalPortAudioDevice*)NULL; - return 0; /* Got rid of sNumDevices=0; */ + PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); + pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ + } + sDeviceList = (internalPortAudioDevice*)NULL; + return 0; /* Got rid of sNumDevices=0; */ } /***********************************************************************/ void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ { #if 0 - struct timeval timeout; - timeout.tv_sec = msec / 1000; - timeout.tv_usec = (msec % 1000) * 1000; - select(0, NULL, NULL, NULL, &timeout); + 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 ); + long usecs = msec * 1000; + usleep( usecs ); #endif } @@ -938,20 +946,20 @@ void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ /* a call to PaHost_FreeFastMemory(). */ void *PaHost_AllocateFastMemory(long numBytes) { - void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */ - if (addr) /* range and locks the pages into memory. A counter */ - { /* is incremented each time the page is locked. The */ + void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */ + if (addr) /* range and locks the pages into memory. A counter */ + { /* is incremented each time the page is locked. The */ if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */ - { /* others are limited to the configurable PLOCK_MA. */ + { /* others are limited to the configurable PLOCK_MA. */ ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n")); #if 1 free(addr); /* You MAY cut out these 2 lines to be less strict, */ addr = NULL; /* you then only get the warning but PA goes on... */ #endif /* Only problem then may be corresponding munpin() */ - } /* call at PaHost_FreeFastMemory(), below. */ + } /* call at PaHost_FreeFastMemory(), below. */ memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */ - } /* a child process after a fork. Furthermore, IRIX- */ - return addr; /* man-pages warn against mixing both mpin and mlock */ + } /* a child process after a fork. Furthermore, IRIX- */ + return addr; /* man-pages warn against mixing both mpin and mlock */ } /* in 1 piece of code, so stick to mpin()/munpin() ! */ @@ -960,32 +968,32 @@ void *PaHost_AllocateFastMemory(long numBytes) /* call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory(void *addr, long numBytes) { - if (addr) - { + if (addr) + { if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */ ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n")); free(addr); /* But go on, try to release it, just warn... */ - } + } } /*----------------------------------------------------------*/ PaError PaHost_StreamActive( internalPortAudioStream *past ) { - PaHostSoundControl *pahsc; - if (past == NULL) + PaHostSoundControl *pahsc; + if (past == NULL) return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if (pahsc == NULL) return paInternalError; - return (PaError)(past->past_IsActive != 0); + return (PaError)(past->past_IsActive != 0); } /*-------------------------------------------------------------------*/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { - internalPortAudioStream *past = (internalPortAudioStream *) stream; - /* FIXME - return actual frames played, not frames generated. - ** Need to query the output device somehow. - */ - return past->past_FrameCount; + internalPortAudioStream *past = (internalPortAudioStream *) stream; +/* FIXME - return actual frames played, not frames generated. +** Need to query the output device somehow. +*/ + return past->past_FrameCount; } diff --git a/pa_sgi/pthread-Makefile b/pa_sgi/pthread-Makefile new file mode 100644 index 0000000..527677a --- /dev/null +++ b/pa_sgi/pthread-Makefile @@ -0,0 +1,52 @@ +# Make PortAudio for Silicon Graphics IRIX (6.2) +# Pieter suurmond, september 22, 2001. (v15 pa_sgi sub-version #0.18) + +# pthread, math (as with linux) and SGI audio library: +# SGI-books say -lpthread should be the last on the line. +LIBS = -lm -laudio -lpthread + +CDEFINES = -I../pa_common + +# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64, +# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging. +# And use for example -O2 or -O3 for better optimization: +CFLAGS = -O2 +PASRC = ../pa_common/pa_lib.c pa_sgi.c +PAINC = ../pa_common/portaudio.h + +# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). +#TESTC = $(PASRC) ../pa_tests/patest_record.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches. +TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?). +#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK +#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. + +# Tests that do not yet work. +#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default +#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default +#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS FUZZ CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-( + # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH. + # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON??? + # ANYWAY, I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS! +TESTH = $(PAINC) + +all: patest + +# "cc" for the MIPSpro compiler, may be changed to "gcc": +patest: $(TESTC) $(TESTH) Makefile + cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest + +run: patest + ./patest + diff --git a/pa_sgi/pthread-pa_sgi.c b/pa_sgi/pthread-pa_sgi.c new file mode 100644 index 0000000..e9ab273 --- /dev/null +++ b/pa_sgi/pthread-pa_sgi.c @@ -0,0 +1,908 @@ +/* + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * SGI IRIX implementation by Pieter Suurmond, september 22, 2001 (#0.18). + * + * Copyright (c) 1999-2001 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. + */ +/* +Modfication History: + 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. + 8/17/2001 - alpha release with IRIX sproc()-method, may sometimes let IRIX6.2 crash at closing audiostream. + 9/22/2001 - #0.18 pthread starts to work a bit: + BUT UNDER IRIX6.2, I DON'T GET IT TO WORK REALLY CORRECTLY, + this POSIX-attempt, + DON'T USE THIS FILE FOR RELIABLE OPERATION, IT IS HERE JUST + FOR DOCUMENTATION/ARCHIVE... OR FOR ANYONE WHO WANTS TO FIX...... +TODO: + - Test under IRIX 6.5. + - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), + and maybe also the other natively supported formats? (might increase performance) + - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet, + seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?) + - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4. +REFERENCES: + - IRIX 6.2 man pages regarding SGI AL library. + - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and + may not be publically available on the internet). +*/ + +#include /* Standard libraries. */ +#include + +#include "../pa_common/portaudio.h" /* Portaudio headers. */ +#include "../pa_common/pa_host.h" +#include "../pa_common/pa_trace.h" + +/* +#include +#include +#include Not needed +#include +#include +#include +#include Needed? +#include +#include sched_param struct and related functions + used in setting thread priorities. +#include Some POSIX constants such as _POSIX_THREAD_THREADS_MAX +*/ + +#include /* Pthreads are supported by IRIX 6.2 after */ + /* patches 1361, 1367, and 1429 are applied. */ + +#include /* fcntl.h needed for "O_RDONLY". */ +#include /* For usleep() and constants used when calling sysconf() */ + /* to query POSIX limits (see the sysconf(3) ref. page. */ + +#include /* SGI-specific audio library. */ + + +/*--------------------------------------------*/ +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) PRINT(x) +#define DBUGX(x) /* PRINT(x) */ + +#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */ +#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */ + +typedef struct internalPortAudioDevice /* IRIX specific device info: */ +{ + PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ + long pad_ALdevice; /* SGI-number! */ + double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ + char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ + PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ + /* int structVersion; */ + /* const char* name; */ + /* int maxInputChannels, maxOutputChannels; */ + /* int numSampleRates; Num rates, or -1 if range supprtd. */ + /* const double* sampleRates; Array of supported sample rates, */ + /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ + struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ +} internalPortAudioDevice; + +typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */ +{ + ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ + pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ + pthread_t pahsc_ThreadPID; + short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ + *pahsc_NativeOutputBuffer; + unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ + pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ + unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ + pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ + struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ + pahsc_LastExitTime; + long pahsc_InsideCountSum, + pahsc_TotalCountSum; +} PaHostSoundControl; + +/*----------------------------- Shared Data ------------------------------------------------------*/ +static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ +static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ + +long Pa_GetHostError(void) +{ + return (long)sPaHostError; +} + +/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ +/* (copied from source pa_linux_oss/pa_linux_oss.c) */ +static void Pa_StartUsageCalculation( internalPortAudioStream *past ) +{ + struct itimerval itimer; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; +/* Query system timer for usage analysis and to prevent overuse of CPU. */ + getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); +} + +static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) +{ + long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; + long usecs = secs * 1000000; + usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); + return usecs; +} + +static void Pa_EndUsageCalculation( internalPortAudioStream *past ) +{ + struct itimerval currentTime; + long insideCount; + long totalCount; /* Measure CPU utilization during this callback. */ + +#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 (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) + { + if (past->past_IfLastExitValid) + { + insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); + pahsc->pahsc_InsideCountSum += insideCount; + totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); + pahsc->pahsc_TotalCountSum += totalCount; + /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ + /* Low pass filter the result because sometimes we get called several times in a row. */ + /* That can cause the TotalCount to be very low which can cause the usage to appear */ + /* unnaturally high. So we must filter numerator and denominator separately!!! */ + if (pahsc->pahsc_InsideCountSum > 0) + { + past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); + past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + pahsc->pahsc_InsideCountSum = 0; + pahsc->pahsc_TotalCountSum = 0; + } + } + past->past_IfLastExitValid = 1; + } + pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; + pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; + setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); + past->past_IfLastExitValid = 1; +} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ + + +/*--------------------------------------------------------------------------------------*/ +PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */ +{ /* call to report via ERR_RPT(), yields a PaError-num. */ + const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ + switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ + { + case AL_BAD_OUT_OF_MEM: + ERR_RPT(("%sout of memory.\n", a)); + return paInsufficientMemory; /* Known PaError. */ + case AL_BAD_CONFIG: + ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_CHANNELS: + ERR_RPT(("%schannels not 1,2 or 4.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_NO_PORTS: + ERR_RPT(("%sout of audio ports.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DEVICE: + ERR_RPT(("%swrong device number.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DEVICE_ACCESS: + ERR_RPT(("%swrong device access.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DIRECTION: + ERR_RPT(("%sinvalid direction.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_SAMPFMT: + ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_FLOATMAX: + ERR_RPT(("%smax float value is zero.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_WIDTH: + ERR_RPT(("%sunsupported samplewidth.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_QSIZE: + ERR_RPT(("%sinvalid queue size.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_PVBUFFER: + ERR_RPT(("%sPVbuffer null.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_BUFFERLENGTH_NEG: + ERR_RPT(("%snegative bufferlength.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_BUFFERLENGTH_ODD: + ERR_RPT(("%sodd bufferlength.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_PARAM: + ERR_RPT(("%sparameter not valid for device.\n", a)); + return paHostError; /* Generic PaError. */ + default: + ERR_RPT(("%sunknown error.\n", a)); + return paHostError; /* Generic PaError. */ + } +} + +/*------------------------------------------------------------------------------------------*/ +/* Tries to set various rates and formats and fill in the device info structure. */ +static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */ + PaDeviceID id, /* (DefaultI|ODeviceID()) */ + char* name, /* (for example "SGI AL") */ + internalPortAudioDevice* pad) /* Result written to pad. */ +{ + int format; + long min, max; /* To catch hardware characteristics. */ + ALseterrorhandler(0); /* 0 = turn off the default error handler. */ + /*--------------------------------------------------------------------------------------*/ + pad->pad_ALdevice = ALdev; /* Set the AL device number. */ + pad->pad_DeviceID = id; /* Set the PA device number. */ + if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ + { + ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); + return paHostError; + } + strcpy(pad->pad_DeviceName, name); /* Write name-string. */ + pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ + /*--------------------------------- natively supported sample formats: -----------------*/ + pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ + /* Then also choose other CallConvertXX()! */ + /*--------------------------------- number of available i/o channels: ------------------*/ + if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) + return translateSGIerror(); + pad->pad_Info.maxInputChannels = max; + DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) + if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) + return translateSGIerror(); + pad->pad_Info.maxOutputChannels = max; + DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) + /*--------------------------------- supported samplerates: ----------------------*/ + pad->pad_Info.numSampleRates = 7; + pad->pad_Info.sampleRates = pad->pad_SampleRates; + pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ + pad->pad_SampleRates[1] = (double)AL_RATE_11025; + pad->pad_SampleRates[2] = (double)AL_RATE_16000; + pad->pad_SampleRates[3] = (double)AL_RATE_22050; + pad->pad_SampleRates[4] = (double)AL_RATE_32000; + pad->pad_SampleRates[5] = (double)AL_RATE_44100; + pad->pad_SampleRates[6] = (double)AL_RATE_48000; + if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */ + return translateSGIerror(); /* double -> long. */ + if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */ + goto weird; + if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ + return translateSGIerror(); + if (max != (long)(0.5 + pad->pad_SampleRates[6])) + { +weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); + return paHostError; /* Or make it a warning and just carry on... */ + } + /*-------------------------------------------------------------------------------*/ + return paNoError; +} + + +/*--------------------------------------------------------------------------------*/ +int Pa_CountDevices() /* Name of this function suggests it only counts and */ +{ /* is NOT destructive, it however resets whole PA ! */ + int numDevices = 0; /* Let 's not do that here. */ + internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ +#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ + if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */ + Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ +#endif /* friendly to clients that forgot to initialize PA. */ + while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ + { + numDevices++; + currentDevice = currentDevice->pad_Next; + } + return numDevices; +} + +/*-------------------------------------------------------------------------------*/ +static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) +{ + int numDevices = 0; + internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; + internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ + while (pad) /* pad may be NULL, that's ok, return 0. */ + { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ + if (pad->pad_DeviceID == id) /* This the device we were looking for? */ + res = pad; /* But keep on(!) counting so we don't */ + numDevices++; /* have to call Pa_CountDevices() later. */ + pad = pad->pad_Next; /* Advance to the next device or NULL. */ + } /* No assumptions about order of ID's in */ + if (!res) /* the list. */ + ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); + if ((id < 0) || (id >= numDevices)) + { + ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); +#if 1 /* Be strict, even when found, */ + res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ +#endif + } + return res; +} + +/*----------------------------------------------------------------------*/ +const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) +{ + PaDeviceInfo* res = (PaDeviceInfo*)NULL; + internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ + if (pad) + res = &pad->pad_Info; /* Not finding the specified ID is not */ + if (!res) /* the same as &pad->pad_Info == NULL. */ + ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); + return res; /* So (maybe) a second/third ERR_RPT(). */ +} + +/*------------------------------------------------*/ +PaDeviceID Pa_GetDefaultInputDeviceID(void) +{ + return 0; /* 0 is the default device ID. */ +} +/*------------------------------------------------*/ +PaDeviceID Pa_GetDefaultOutputDeviceID(void) +{ + return 0; +} + +/*-------------------------------------------------------------------------------------------------*/ +/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */ +PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ +{ + internalPortAudioDevice* pad; + PaError r = paNoError; + int audioLibFileID; /* To test for the presence of audio. */ + + if (sDeviceList) /* Allow re-init, only warn, no error. */ + { + ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); + return r; + } + /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/ + audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ + if (audioLibFileID < 0) /* IO port. On failure, machine */ + { /* has no audio ability. */ + ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); + return paHostError; + } + close(audioLibFileID); /* Allocate fast mem to hold device info. */ + pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); + if (pad == NULL) + return paInsufficientMemory; + memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ + r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ + Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ + "AL default", /* A suitable name. */ + pad); /* Write args and queried info into pad. */ + if (r != paNoError) + { + ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); + PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ + } + else + sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ + /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ + /*---------------------------------------------------------------------------------------------*/ + return r; +} + +/*---------------------------------------------------------------------------------------------------*/ +static PaError Pa_SgiAudioProcess(internalPortAudioStream *past) /* Spawned by PaHost_StartEngine(). */ +{ + PaError result = paNoError; + PaHostSoundControl *pahsc; + + if (!past) + return paBadStreamPtr; + pahsc = (PaHostSoundControl*)past->past_DeviceData; + if (!pahsc) + return paInternalError; + past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ + DBUG(("entering thread.\n")); + + while (!past->past_StopSoon) /* OR-ing StopSoon and StopNow here gives problems! */ + { + /*---------------------------------------- INPUT: ------------------------------------*/ + if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */ + { + while (ALgetfilled(pahsc->pahsc_ALportIN) < pahsc->pahsc_SamplesPerInputBuffer) + { + /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */ + if (past->past_StopNow) /* Don't let ALreadsamps() block */ + goto done; + } + if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer, + pahsc->pahsc_SamplesPerInputBuffer)) /* Number of samples instead */ + { /* of number of frames. */ + ERR_RPT(("ALreadsamps() failed.\n")); + result = paInternalError; + goto done; + } + } + /*---------------------------------------------------- USER CALLBACK ROUTINE: ----------*/ + /* DBUG(("Calling Pa_CallConvertInt16()...\n")); */ + Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ + result = Pa_CallConvertInt16(past, /* user data and call user routine. */ + pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer); + Pa_EndUsageCalculation(past); + if (result) + { + DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); + goto done; /* This is apparently NOT an error! */ + } /* Just letting the userCallBack stop us. */ + /*---------------------------------------- OUTPUT: ------------------------------------*/ + if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */ + { + while (ALgetfillable(pahsc->pahsc_ALportOUT) < pahsc->pahsc_SamplesPerOutputBuffer) + { + /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */ + if (past->past_StopNow) /* Don't let ALwritesamps() block */ + goto done; + } + if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer, + pahsc->pahsc_SamplesPerOutputBuffer)) + { + ERR_RPT(("ALwritesamps() failed.\n")); + result = paInternalError; + goto done; + } + } + /*-------------------------------------------------------------------------------------*/ + } +done: + /* pahsc->pahsc_ThreadPID = -1; Hu? doesn't help!! (added by Pieter) */ + past->past_IsActive = 0; + DBUG(("leaving thread.\n")); + return result; +} + + +/*--------------------------------------------------------------------------------------*/ +PaError PaHost_OpenStream(internalPortAudioStream *past) +{ + PaError result = paNoError; + PaHostSoundControl *pahsc; + unsigned int minNumBuffers; + internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ + ALconfig sgiALconfig = NULL; /* IRIX-datatype. */ + long pvbuf[8]; /* To get/set hardware configs. */ + long sr, ALqsize; + DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ + if (!past) + { + ERR_RPT(("Streampointer NULL!\n")); + result = paBadStreamPtr; goto done; + } + pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); + if (pahsc == NULL) + { + ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ + result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ + } + memset(pahsc, 0, sizeof(PaHostSoundControl)); +/* pahsc->pahsc_threadPID = -1; Should pahsc_threadPID be inited to */ + past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ + /*--------------------------------------------------- Allocate native buffers: --------*/ + pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumInputChannels; /* audio-thread. */ + pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); + if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */ + { + pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer); + if( pahsc->pahsc_NativeInputBuffer == NULL ) + { + ERR_RPT(("Fast memory allocation for input-buffer failed.\n")); + result = paInsufficientMemory; goto done; + } + } + pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumOutputChannels; /* audio-thread. */ + pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); + if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */ + { + pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer); + if (pahsc->pahsc_NativeOutputBuffer == NULL) + { + ERR_RPT(("Fast memory allocation for output-buffer failed.\n")); + result = paInsufficientMemory; goto done; + } + } + /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ + ALseterrorhandler(0); /* 0 = turn off the default error handler. */ + pvbuf[0] = AL_INPUT_RATE; + pvbuf[2] = AL_INPUT_COUNT; + pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ + pvbuf[6] = AL_OUTPUT_COUNT; + sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */ + if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ + { /* sponding native AL-number(s). */ + padIN = Pa_GetInternalDevice(past->past_InputDeviceID); + if (!padIN) + { + ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); + result = paHostError; goto done; + } + if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ + goto sgiError; /* the same AL-device, the AL-library might */ + if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ + { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ + if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ + { + ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ +another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); + result = paHostError; goto done; + } + pvbuf[1] = sr; /* Then set input-rate. */ + if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) + goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ + } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */ + } + if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ + { /* We use padOUT/IN later on, or at least 1 of both. */ + padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); + if (!padOUT) + { + ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); + result = paHostError; goto done; + } + if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) + goto sgiError; + if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr)) + { /* Output needed and rate different from current harware-rate. */ + if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ + { + ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ +another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); + result = paHostError; goto done; /* Will free again the inputbuffer */ + } /* that was just created above. */ + pvbuf[5] = sr; /* Then set output-rate. */ + if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) + goto sgiError; + } + } + /*------------------------------------------ Construct an audio-port-configuration ----------*/ + sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */ + if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */ + goto sgiError; /* See that sgiALconfig is NOT released! */ + if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ + goto sgiError; + if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */ + goto sgiError; /* config is set to two's complement format. */ + /************************ Future versions might (dynamically) switch to 32-bit floats? ******* + if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) + goto sgiError; + if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config + goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ + /*---------- ?? --------------------*/ + /* 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; + /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/ + if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer) + ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer; + else /* Take the largest of the two amounts. */ + ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer; + ALqsize *= 4; /* 4 times as large as amount per transfer! */ + if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */ + goto sgiError; /* Using 2 times may give glitches... */ + /* Have to work on ALsetqueuesize() above. */ + + /* Do ALsetchannels() later, apart per input and/or output. */ + /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/ + if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */ + { + if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) + { + DBUG(("PaHost_OpenStream: opening both input and output channels.\n")); + /*------------------------- open output port: ----------------------------------*/ + if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); + if (pahsc->pahsc_ALportOUT == (ALport)0) + goto sgiError; + /*------------------------- open input port: -----------------------------------*/ + if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); + if (pahsc->pahsc_ALportIN == (ALport)0) + goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */ + } /* Probably due to too small buffersizes?.... */ + else + { + ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); + result = paHostError; + goto done; + } + } + else /* (OutputDeviceID != InputDeviceID) */ + { + if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */ + { + /*------------------------- open output port: ----------------------------------*/ + DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n", + past->past_NumOutputChannels, padOUT->pad_DeviceName)); + if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); + if (pahsc->pahsc_ALportOUT == (ALport)0) + goto sgiError; + } + if (past->past_NumInputChannels > 0) /* READ-ONLY: */ + { + /*------------------------- open input port: -----------------------------------*/ + DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n", + past->past_NumInputChannels, padIN->pad_DeviceName)); + if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); + if (pahsc->pahsc_ALportIN == (ALport)0) + goto sgiError; + } + } + DBUG(("PaHost_OpenStream() succeeded.\n")); + goto done; /* (no errors occured) */ +sgiError: + result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ +done: + if (sgiALconfig) + ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */ + if (result != paNoError) + PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ + return result; +} + +/*-----------------------------------------------------*/ +PaError PaHost_StartOutput(internalPortAudioStream *past) +{ + return paNoError; /* Hmm, not implemented yet? */ +} +PaError PaHost_StartInput(internalPortAudioStream *past) +{ + return paNoError; +} + +/*------------------------------------------------------------------------------*/ +PaError PaHost_StartEngine(internalPortAudioStream *past) +{ + PaHostSoundControl *pahsc; + int hres; + PaError result = paNoError; + + if (!past) /* Test argument. */ + { + ERR_RPT(("PaHost_StartEngine(NULL)!\n")); + return paBadStreamPtr; + } + pahsc = (PaHostSoundControl*)past->past_DeviceData; + if (!pahsc) + { + ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData == NULL!\n")); + return paHostError; + } + past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ + past->past_StopNow = 0; + past->past_IsActive = 1; + DBUG(("PaHost_StartEngine() called.\n")); + /* Use pthread_create() instead of __clone() because: */ + /* - pthread_create also works for other UNIX systems like Solaris, */ + /* - Java HotSpot VM crashes in pthread_setcanceltype() when using __clone(). */ + hres = pthread_create(&(pahsc->pahsc_ThreadPID), /* SPAWN AUDIO-CHILD. */ + NULL, /* pthread_attr_t * attr */ + (void*)Pa_SgiAudioProcess, + past); + if (hres) + { + result = paHostError; + sPaHostError = hres; + ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); + } + return result; +} + +/*------------------------------------------------------------------------------*/ +PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) +{ + int hres; + PaError result = paNoError; + PaHostSoundControl *pahsc; + + DBUG(("PaHost_StopEngine() called.\n")); + if (!past) + return paBadStreamPtr; + pahsc = (PaHostSoundControl*)past->past_DeviceData; + if (pahsc == NULL) + return result; /* paNoError (already stopped, no err?). */ + past->past_StopSoon = 1; /* Tell background thread to stop generating */ + if (abort) /* more and to let current data play out. If */ + past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ + if (pahsc->pahsc_ThreadPID != -1) /* Join thread to recover memory resources. */ + { + DBUG(("pthread_join() called.\n")); + hres = pthread_join(pahsc->pahsc_ThreadPID, NULL); + if (hres) + { + result = paHostError; + sPaHostError = hres; + ERR_RPT(("PaHost_StopEngine() failed pthread_join().\n")); + } + pahsc->pahsc_ThreadPID = -1; + } + past->past_IsActive = 0; + return result; +} + +/*---------------------------------------------------------------*/ +PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) +{ + return paNoError; /* Not implemented yet? */ +} +PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) +{ + return paNoError; +} + +/*******************************************************************/ +PaError PaHost_CloseStream(internalPortAudioStream *past) +{ + PaHostSoundControl *pahsc; + PaError result = paNoError; + + DBUG(("PaHost_CloseStream() called.\n")); + if (past == NULL) + return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ + return result; /* This test prevents from freeing NULL-pointers. */ + + if (pahsc->pahsc_ALportIN) + { + if (ALcloseport(pahsc->pahsc_ALportIN)) + result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ + else /* But go on anyway... to release other stuff... */ + pahsc->pahsc_ALportIN = (ALport)0; + } + if (pahsc->pahsc_ALportOUT) + { + if (ALcloseport(pahsc->pahsc_ALportOUT)) + result = translateSGIerror(); + else + pahsc->pahsc_ALportOUT = (ALport)0; + } + if (pahsc->pahsc_NativeInputBuffer) + { + PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer); + pahsc->pahsc_NativeInputBuffer = NULL; + } + if (pahsc->pahsc_NativeOutputBuffer) + { + PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); + pahsc->pahsc_NativeOutputBuffer = NULL; + } + PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); + past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST. */ + 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 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. +*/ +#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") + +int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) +{ + return 2; +} +/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */ +/* Do we HAVE to do it this way under IRIX???.... */ +/*--------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------*/ +PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ +{ /* Called by Pa_Terminate() from pa_lib.c. */ + internalPortAudioDevice *pad = sDeviceList, + *nxt; + while (pad) + { + DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); + nxt = pad->pad_Next; + PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); + pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ + } + sDeviceList = (internalPortAudioDevice*)NULL; + return 0; /* Got rid of sNumDevices=0; */ +} + +/***********************************************************************/ +void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ +{ +#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 physi- */ +/* cal 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); + if (addr) + 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) +{ + if (addr) + 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); +} + +/*-------------------------------------------------------------------*/ +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + internalPortAudioStream *past = (internalPortAudioStream *) stream; +/* FIXME - return actual frames played, not frames generated. +** Need to query the output device somehow. +*/ + return past->past_FrameCount; +} From 78a93bacb23a991ea6d8e84aeea40f766f652032 Mon Sep 17 00:00:00 2001 From: philburk Date: Mon, 6 May 2002 16:49:10 +0000 Subject: [PATCH 075/814] Added for V18 easy build --- index.html | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..91e5b4c --- /dev/null +++ b/index.html @@ -0,0 +1,89 @@ + + + + + + + + + PortAudio Implementations for DirectSound + + +  +

+ + + +
+
+

+PortAudio - Portable Audio Library

+
+ +

Last updated 5/6/02. +

PortAudio is a cross platform, open-source, audio +I/O library proposed by Ross Bencina to the music-dsp +mailing list. It lets you write simple audio programs in 'C' that will +compile and run on Windows, Macintosh, Unix, BeOS. PortAudio is +intended to promote the exchange of audio synthesis software between developers +on different platforms. +

For complete information on PortAudio and to download the latest releases, +please visit "http://www.portaudio.com". +
  +
  +

+

+Click here for Documentation

+ +

+

+ +

+Contacts and E-Mail List

+ +
    +
  • +If you are using or implementing PortAudio then please join the PortAudio +mail list generously administered by +Bill +Eldridge.
  • + +
  • +If you find bugs in one of these implementations, or have suggestions, +please e-mail them to Phil Burk.
  • + +
  • +If you make improvements to the library, please send them to us so we can +incorporate the improvements.
  • +
+ +

+License

+PortAudio Portable Real-Time Audio Library +
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 ON INFRINGEMENT. +
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. +
  + + From ce2804c759130aa1f166349ef6c8509eebae17ec Mon Sep 17 00:00:00 2001 From: philburk Date: Mon, 6 May 2002 16:51:37 +0000 Subject: [PATCH 076/814] Documents should be in CVS to simplify release. --- docs/index.html | 60 ++++ docs/latency.html | 192 +++++++++++++ docs/pa_drivermodel.c.txt | 488 ++++++++++++++++++++++++++++++++ docs/pa_drivermodel.h.txt | 143 ++++++++++ docs/pa_impl_guide.html | 197 +++++++++++++ docs/pa_impl_startstop.html | 190 +++++++++++++ docs/pa_tut_asio.html | 55 ++++ docs/pa_tut_callback.html | 91 ++++++ docs/pa_tut_devs.html | 65 +++++ docs/pa_tut_explore.html | 42 +++ docs/pa_tut_init.html | 43 +++ docs/pa_tut_mac.html | 41 +++ docs/pa_tut_mac_osx.html | 46 +++ docs/pa_tut_open.html | 52 ++++ docs/pa_tut_oss.html | 46 +++ docs/pa_tut_over.html | 92 ++++++ docs/pa_tut_pc.html | 78 +++++ docs/pa_tut_run.html | 56 ++++ docs/pa_tut_rw.html | 79 ++++++ docs/pa_tut_term.html | 47 +++ docs/pa_tut_util.html | 55 ++++ docs/pa_tutorial.html | 46 +++ docs/portaudio_h.txt | 425 ++++++++++++++++++++++++++++ docs/portaudio_icmc2001.pdf | Bin 0 -> 50968 bytes docs/proposals.html | 550 ++++++++++++++++++++++++++++++++++++ docs/releases.html | 252 +++++++++++++++++ 26 files changed, 3431 insertions(+) create mode 100644 docs/index.html create mode 100644 docs/latency.html create mode 100644 docs/pa_drivermodel.c.txt create mode 100644 docs/pa_drivermodel.h.txt create mode 100644 docs/pa_impl_guide.html create mode 100644 docs/pa_impl_startstop.html create mode 100644 docs/pa_tut_asio.html create mode 100644 docs/pa_tut_callback.html create mode 100644 docs/pa_tut_devs.html create mode 100644 docs/pa_tut_explore.html create mode 100644 docs/pa_tut_init.html create mode 100644 docs/pa_tut_mac.html create mode 100644 docs/pa_tut_mac_osx.html create mode 100644 docs/pa_tut_open.html create mode 100644 docs/pa_tut_oss.html create mode 100644 docs/pa_tut_over.html create mode 100644 docs/pa_tut_pc.html create mode 100644 docs/pa_tut_run.html create mode 100644 docs/pa_tut_rw.html create mode 100644 docs/pa_tut_term.html create mode 100644 docs/pa_tut_util.html create mode 100644 docs/pa_tutorial.html create mode 100644 docs/portaudio_h.txt create mode 100644 docs/portaudio_icmc2001.pdf create mode 100644 docs/proposals.html create mode 100644 docs/releases.html diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..7d9b248 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,60 @@ + + + + + + + + + PortAudio Docs + + +  +
+ + + +
+
+

+PortAudio Documentation

+
+ +

Copyright 2000 Phil Burk and Ross Bencina +
  +

+API Reference

+ +
The Application Programmer Interface is documented in "portaudio.h".
+ +

+Tutorial

+ +
Describes how to write audio programs using the PortAudio API.
+ +

+Implementation Guide

+ +
Describes how to write an implementation of PortAudio for a +new computer platform.
+ +

+Paper Presented at ICMC2001 (PDF)

+ +
Describes the PortAudio API and discusses implementation issues. +Written July 2001.
+ +

+Improving Latency

+ +
How to tune your computer to achieve the lowest possible audio +delay.
+ +

+Proposed Changes

+ +
Describes API changes being considered by the developer community. +Feedback welcome.
+Return to PortAudio Home Page + + diff --git a/docs/latency.html b/docs/latency.html new file mode 100644 index 0000000..87f1d12 --- /dev/null +++ b/docs/latency.html @@ -0,0 +1,192 @@ + + + + + + + + + PortAudio Implementation - Start/Stop + + +  +
+ + + +
+
+

+PortAudio Latency

+
+ +

This page discusses the issues of audio latency for PortAudio +. It offers suggestions on how to lower latency to improve the responsiveness +of applications. +

What is Latency? +
PortAudio and Latency +
Macintosh +
Unix +
WIndows
+By Phil Burk, Copyright 2002 Phil Burk and Ross Bencina +

+What is Latency?

+Latency is basically longest time that you have to wait before you obtain +a desired result. For digital audio output it is the time between making +a sound in software and finally hearing it. +

Consider the example of pressing a key on the ASCII keyboard to play +a note. There are several stages in this process which each contribute +their own latency. First the operating system must respond to the keypress. +Then the audio signal generated must work its way through the PortAudio +buffers. Then it must work its way through the audio card hardware. Then +it must go through the audio amplifier which is very quick and then travel +through the air. Sound travels at abous one foot per millisecond through +air so placing speakers across the room can add 5-20 msec of delay. +

The reverse process occurs when recording or responding to audio input. +If you are processing audio, for example if you implement a software guitar +fuzz box, then you have both the audio input and audio output latencies +added together. +

The audio buffers are used to prevent glitches in the audio stream. +The user software writes audio into the output buffers. That audio is read +by the low level audio driver or by DMA and sent to the DAC. If the computer +gets busy doing something like reading the disk or redrawing the screen, +then it may not have time to fill the audio buffer. The audio hardware +then runs out of audio data, which causes a glitch. By using a large enough +buffer we can ensure that there is always enough audio data for the audio +hardware to play. But if the buffer is too large then the latency is high +and the system feels sluggish. If you play notes on the keyboard then the +"instrument" will feel unresponsive. So you want the buffers to be as small +as possible without glitching. +

+PortAudio and Latency

+The only delay that PortAudio can control is the total length of its buffers. +The Pa_OpenStream() call takes two parameters: numBuffers and framesPerBuffer. +The latency is also affected by the sample rate which we will call framesPerSecond. +A frame is a set of samples that occur simultaneously. For a stereo stream, +a frame is two samples. +

The latency in milliseconds due to this buffering  is: +

latency_msec = 1000 * numBuffers * framesPerBuffer / framesPerSecond
+This is not the total latency, as we have seen, but it is the part we can +control. +

If you call Pa_OpenStream() with numBuffers equal to zero, then PortAudio +will select a conservative number that will prevent audio glitches. If +you still get glitches, then you can pass a larger value for numBuffers +until the glitching stops. if you try to pass a numBuffers value that is +too small, then PortAudio will use its own idea of the minimum value. +

PortAudio decides on the minimum number of buffers in a conservative +way based on the frameRate, operating system and other variables. You can +query the value that PortAudio will use by calling: +

int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate +);
+On some systems you can override the PortAudio minimum if you know your +system can handle a lower value. You do this by setting an environment +variable called PA_MIN_LATENCY_MSEC which is read by PortAudio when it +starts up. This is supported on the PortAudio implementations for Windows +MME, Windows DirectSound, and Unix OSS. +

+Macintosh

+The best thing you can do to improve latency on Mac OS 8 and 9 is to turn +off Virtual Memory. PortAudio V18 will detect that Virtual Memory is turned +off and use a very low latency. +

For Mac OS X the latency is very low because Apple Core Audio is so +well written. You can set the PA_MIN_LATENCY_MSEC variable using: +

setenv PA_MIN_LATENCY_MSEC 4
+ +

+Unix

+PortAudio under Unix currently uses a backgroud thread that reads and writes +to OSS. This gives you decent but not great latency. But if you raise the +priority of the background thread to a very priority then you can get under +10 milliseconds latency. In order to raise your priority you must run the +PortAudio program as root! You must also set PA_MIN_LATENCY_MSEC using +the appropriate command for your shell. +

+Windows

+Latency under Windows is a complex issue because of all the alternative +operating system versions and device drivers. I have seen latency range +from 8 milliseconds to 400 milliseconds. The worst case is when using Windows +NT. Windows 98 is a little better, and Windows XP can be quite good if +properly tuned. +

The underlying audio API also makes a lot of difference. If the audio +device has its own DirectSound driver then DirectSound can often provide +better latency than WMME. But if a real DirectSound driver is not available +for your device then it is emulated using WMME and the latency can be very +high. That's where I saw the 400 millisecond latency. The ASIO implementation +is generally very good and will give the lowest latency if available. +

You can set the PA_MIN_LATENCY_MSEC variable to 50, for example, by +entering in MS-DOS: +

set PA_MIN_LATENCY_MSEC=50
+If you enter this in a DOS window then you must run the PortAudio program +from that same window for the variable to have an effect. You can add that +line to your C:\AUTOEXEC.BAT file and reboot if you want it to affect any +PortAudio based program. +

For Windows XP, you can set environment variables as follows: +

    +
  1. +Select "Control Panel" from the "Start Menu".
  2. + +
  3. +Launch the "System" Control Panel
  4. + +
  5. +Click on the "Advanced" tab.
  6. + +
  7. +Click on the "Environment Variables" button.
  8. + +
  9. +Click "New" button under  User Variables.
  10. + +
  11. +Enter PA_MIN_LATENCY_MSEC for the name and some optimistic number for the +value.
  12. + +
  13. +Click OK, OK, OK.
  14. +
+ +

+Improving Latency on Windows

+There are several steps you can take to improve latency under windows. +
    +
  1. +Avoid reading or writng to disk when doing audio.
  2. + +
  3. +Turn off all automated background tasks such as email clients, virus scanners, +backup programs, FTP servers, web servers, etc. when doing audio.
  4. + +
  5. +Disconnect from the network to prevent network traffic from interrupting +your CPU.
  6. +
+Important: Windows XP users can also tune the OS to favor background +tasks, such as audio, over foreground tasks, such as word processing. I +lowered my latency from 40 to 10 milliseconds using this simple technique. +
    +
  1. +Select "Control Panel" from the "Start Menu".
  2. + +
  3. +Launch the "System" Control Panel
  4. + +
  5. +Click on the "Advanced" tab.
  6. + +
  7. +Click on the "Settings" button in the Performance area.
  8. + +
  9. +Click on the "Advanced" tab.
  10. + +
  11. +Select "Background services" in the Processor Scheduling area.
  12. + +
  13. +Click OK, OK.
  14. +
+Please let us know if you have others sugestions for lowering latency. +
  +
  + + diff --git a/docs/pa_drivermodel.c.txt b/docs/pa_drivermodel.c.txt new file mode 100644 index 0000000..956f664 --- /dev/null +++ b/docs/pa_drivermodel.c.txt @@ -0,0 +1,488 @@ +/* + This file contains the host-neutral code for implementing multiple driver model + support in PortAudio. + + It has not been compiled, but it is supplied only for example purposes at this stage. + + TODO: use of CHECK_DRIVER_MODEL is bogus in some instances since some + of those functions don't return a PaError + + +*/ + +#include "pa_drivermodel.h.txt" + + +#ifndef PA_MULTIDRIVER +/* single driver support, most functions will stay in the implementation files */ + +PaDriverModelID Pa_CountDriverModels() +{ + return 1; +} + +/* +Perhaps all drivers should define this with this signature +const PaDriverModelInfo* Pa_GetDriverModelInfo( PaDriverModelID driverModelID ) +{ +} +*/ + +PaDeviceID Pa_DriverModelDefaultInputDeviceID( PaDriverModelID driverModelID ) +{ + return Pa_GetDefaultInputDeviceID(); +} + + +PaDeviceID Pa_DriverModelDefaultOutputDeviceID( PaDriverModelID driverModelID ) +{ + return Pa_GetDefaultInputDeviceID(); +} + +/* +Perhaps all drivers should define with this signature +int Pa_DriverModelMinNumBuffers( PaDriverModelID driverModelID, int framesPerBuffer, double sampleRate ) +{ + +} +*/ + +int Pa_DriverModelCountDevices( PaDriverModelID driverModelID ) +{ + return Pa_CountDevices(); +} + +PaDeviceID Pa_DriverModelGetDeviceID(PaDriverModelID driverModelID, int perDriverModelIndex ) +{ + return perDriverModelIndex; +} + + +#else +/* multidriver support */ + + +typedef PaError (*PaInitializeFunPtr)( PaDriverModelImplementation** ); + +/* + the initializers array is a static table of function pointers + to all the available driverModels on the current platform. + + the order of pointers in the array is important. the first + pointer is always considered to be the "default" driver model. +*/ + +static PaInitializeFunPtr driverModelInitializers[] = { +#ifdef WINDOWS + PaWin32WMME_MultiDriverInitialize, + PaWin32DS_MultiDriverInitialize, + PaASIO_MultiDriverInitialize +#endif +#ifdef MAC + PaMacSM_MultiDriverInitialize, + PaMacCA_MultiDriverInitialize, + PaASIO_MultiDriverInitialize +#endif +/* other platforms here */ + (PaInitializeFunPtr*)0 /* NULL terminate the list */ +}; + + +/* + the driverModels array is a dynamically created table of + currently available driverModels. +*/ +static PaDriverModelImplementation* driverModels = 0; +static int numDriverModels = 0; + + +#define PA_CHECK_INITIALIZED\ + if( driverModels == 0 ) + return paLibraryNotInitialised + +#define PA_CHECK_DRIVER_MODEL_ID( id ) + if( id < 0 || id >= numDriverModels ) + return paBadDriverModelID; + + +/* + ConvertPublicDeviceIdToImplementationDeviceId converts deviceId + from a public device id, to a device id for a particular + PortAudio implementation. On return impl will either point + to a valid implementation or will be NULL. +*/ +static void ConvertPublicDeviceIDToImplementationDeviceID( + PaDriverModelImplementation *impl, PaDeviceID deviceID ) +{ + int i, count; + + impl = NULL; + + for( i=0; i < numDriverModels; ++i ){ + count = driverModels[i]->countDevices(); + if( deviceID < count ){ + impl = driverModels[i]; + return NULL; + }else{ + deviceID -= count; + } + } +} + +static PaDeviceID ConvertImplementationDeviceIDToPublicDeviceID( + PaDriverModelID driverModelID, PaDeviceID deviceID ) +{ + int i; + + for( i=0; i < driverModelID; ++i ) + deviceID += driverModels[i]->countDevices(); +} + + +PaError Pa_Initialize( void ) +{ + PaError result = paNoError; + int i, initializerCount; + PaDriverModelImplementation *impl; + + if( driverModels != 0 ) + return paAlreadyInitialized; + + /* count the number of driverModels */ + initializerCount=0; + while( driverModelInitializers[initializerCount] != 0 ){ + ++initializerCount; + } + + driverModels = malloc( sizeof(PaDriverModelImplementation*) * initializerCount ); + if( driverModels == NULL ) + return paInsufficientMemory; + + numDriverModels = 0; + for( i=0; iterminate( driverModels[i] ); +} + + +long Pa_GetHostError( void ) +{ + PA_CHECK_INITIALIZED; + + under construction. depends on error text proposal. +} + + +const char *Pa_GetErrorText( PaError errnum ) +{ + PA_CHECK_INITIALIZED; + + under construction. may need to call driver model specific code + depending on how the error text proposal pans out. +} + + + +int Pa_CountDevices() +{ + int i, result; + + PA_CHECK_INITIALIZED; + + result = 0; + for( i=0; i < numDriverModels; ++i ) + result += driverModels[i]->countDevices(); + + return result; +} + + +PaDeviceID Pa_GetDefaultInputDeviceID( void ) +{ + PA_CHECK_INITIALIZED; + + return driverModels[0]->getDefaultInputDeviceID(); +} + +PaDeviceID Pa_GetDefaultOutputDeviceID( void ) +{ + PA_CHECK_INITIALIZED; + + return driverModels[0]->getDefaultInputDeviceID(); +} + + +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID deviceID ) +{ + PaDriverModelImplementation *impl; + + PA_CHECK_INITIALIZED; + + ConvertPublicDeviceIDToImplementationDeviceID( impl, deviceID ); + if( impl == NULL ) + return paInvalidDeviceID; + + return impl->getDeviceInfo( deviceID ); +} + +/* NEW MULTIPLE DRIVER MODEL FUNCTIONS ---------------------------------- */ + +PaDriverModelID Pa_CountDriverModels() +{ + PA_CHECK_INITIALIZED; + + return numDriverModels; +} + + +const PaDriverModelInfo* Pa_GetDriverModelInfo( PaDriverModelID driverModelID ) +{ + PA_CHECK_INITIALIZED; + PA_CHECK_DRIVER_MODEL_ID( driverModelID ); + + return driverModels[ driverModelID ]->getDriverModelInfo(); +} + + +PaDeviceID Pa_DriverModelDefaultInputDeviceID( PaDriverModelID driverModelID ) +{ + PA_CHECK_INITIALIZED; + PA_CHECK_DRIVER_MODEL_ID( driverModelID ); + + return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, + driverModels[ driverModelID ]->getDefaultInputDeviceID(); +} + + +PaDeviceID Pa_DriverModelDefaultOutputDeviceID( PaDriverModelID driverModelID ) +{ + PA_CHECK_INITIALIZED; + PA_CHECK_DRIVER_MODEL_ID( driverModelID ); + + return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, + driverModels[ driverModelID ]->getDefaultOutputDeviceID(); +} + + +int Pa_DriverModelMinNumBuffers( PaDriverModelID driverModelID, int framesPerBuffer, double sampleRate ) +{ + PA_CHECK_INITIALIZED; + PA_CHECK_DRIVER_MODEL_ID( driverModelID ); + + return driverModels[ driverModelID ]->getMinNumBuffers( int framesPerBuffer, double sampleRate ); +} + + +int Pa_DriverModelCountDevices( PaDriverModelID driverModelID ) +{ + PA_CHECK_INITIALIZED; + PA_CHECK_DRIVER_MODEL_ID( driverModelID ); + + return driverModels[ driverModelID ]->coundDevices(); +} + +PaDeviceID Pa_DriverModelGetDeviceID(PaDriverModelID driverModelID, int perDriverModelIndex ) +{ + PA_CHECK_INITIALIZED; + PA_CHECK_DRIVER_MODEL_ID( driverModelID ); + + return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, perDriverModelIndex ); +} + +/* END NEW MULTIPLE DRIVER MODEL FUNCTIONS ------------------------------ */ + + +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 ) +{ + PaError result; + PaDriverModelImplementation *inputImpl, *outputImpl, impl; + + PA_CHECK_INITIALIZED; + + if( inputDevice != paNoDevice ){ + ConvertPublicDeviceIDToImplementationDeviceID( inputImpl, inputDevice ); + if( inputImpl == NULL ) + return paInvalidDeviceID; + else + impl = inputImpl; + } + + if( outputDevice != paNoDevice ){ + ConvertPublicDeviceIDToImplementationDeviceID( outputImpl, outputDevice ); + if( outputImpl == NULL ) + return paInvalidDeviceID; + else + impl = outputImpl; + } + + if( inputDevice != paNoDevice && outputDevice != paNoDevice ){ + if( inputImpl != outputImpl ) + return paDevicesMustBelongToTheSameDriverModel; + } + + + result = impl->openStream( stream, inputDevice, numInputChannels, inputSampleFormat, inputDriverInfo, + outputDevice, numOutputChannels, outputSampleFormat, outputDriverInfo, + sampleRate, framesPerBuffer, numberOfBuffers, streamFlags, callback, userData ); + + + if( result == paNoError ) + ((PaStreamImplementation*)stream)->magic = PA_STREAM_MAGIC; + + 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 ) +{ + PaError result; + int inputDevice = driverModels[0]->getDefaultInputDeviceID; + int outputDevice = driverModels[0]->getDefaultOutputDeviceID; + + result = driverModels[0]->openStream( stream, inputDevice, numInputChannels, sampleFormat, 0, + outputDevice, numOutputChannels, sampleFormat, 0, + sampleRate, framesPerBuffer, numberOfBuffers, + streamFlags, callback, userData ); + + if( result == paNoError ) + ((PaStreamImplementation*)stream)->magic = PA_STREAM_MAGIC; + + return result; +} + + +PaError Pa_CloseStream( PortAudioStream* stream ) +{ + PA_CHECK_INITIALIZED; + + PaError result = ((PaStreamImplementation*)stream)->close(); + + if( result == PaNoError ) + ((PaStreamImplementation*)stream)->magic = 0; /* clear magic number */ + + return result; +} + + +PaError Pa_StartStream( PortAudioStream *stream ); +{ + PA_CHECK_INITIALIZED; + + return ((PaStreamImplementation*)stream)->start(); +} + + +PaError Pa_StopStream( PortAudioStream *stream ); +{ + PA_CHECK_INITIALIZED; + + return ((PaStreamImplementation*)stream)->stop(); +} + + +PaError Pa_AbortStream( PortAudioStream *stream ); +{ + PA_CHECK_INITIALIZED; + + return ((PaStreamImplementation*)stream)->abort(); +} + + +PaError Pa_StreamActive( PortAudioStream *stream ) +{ + PA_CHECK_INITIALIZED; + + return ((PaStreamImplementation*)stream)->active(); +} + +PaTimestamp Pa_StreamTime( PortAudioStream *stream ) +{ + PA_CHECK_INITIALIZED; + + return ((PaStreamImplementation*)stream)->time(); +} + + +double Pa_StreamCPULoad( PortAudioStream* stream ) +{ + PA_CHECK_INITIALIZED; + + return ((PaStreamImplementation*)stream)->cpuLoad(); +} + + + +int Pa_GetMinNumBuffers( PaDeviceID deviceID, int framesPerBuffer, double sampleRate ) +{ + PaDriverModelImplementation *impl; + PA_CHECK_INITIALIZED; + + ConvertPublicDeviceIDToImplementationDeviceID( impl, deviceID ); + if( impl == NULL ) + return paInvalidDeviceID; + + return impl->getMinNumBuffers( framesPerBuffer, sampleRate ); +} + + +void Pa_Sleep( long msec ) +{ + same as existing implementaion +} + + +PaError Pa_GetSampleSize( PaSampleFormat format ) +{ + same as existing implementation +} + +#endif /* PA_MULTIDRIVER */ + + diff --git a/docs/pa_drivermodel.h.txt b/docs/pa_drivermodel.h.txt new file mode 100644 index 0000000..f3f2ca2 --- /dev/null +++ b/docs/pa_drivermodel.h.txt @@ -0,0 +1,143 @@ +#ifndef PA_MULTIDRIVERMODEL_H +#define PA_MULTIDRIVERMODEL_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* + This file contains the host-neutral code for implementing multiple driver model + support in PortAudio. + + It has not been compiled, but it is supplied only for example purposes at this stage. +*/ + + +#include "portaudio.h" + + +#define PA_MULTIDRIVER // for multidriver support + + + +TODO: declare function pointer types for the following function pointers + +/* + Each driver model implementation needs to implement an initialize function + which is added to the driverModelInitializers array in pa_multidrivermodel.c + + the initializer function needs to return a pointer to a + PaDriverModelImplementation structure, or NULL if initiliazation failed. TODO: need error code instead + + the function pointer members of this structure point to funtions + which operate in exactly the same way as the corresponding functions + in the PortAudio API. +*/ + +struct{ + fptr terminate; /* takes the PaDriverModelImplementation* returned by initialize */ + fptr getDriverModelInfo; + fptr getHostError; + fptr getHostErrorText; + fptr countDevices; + fptr getDefaultInputDeviceID; + fptr getDefaultOutputDeviceID; + fptr getDeviceInfo; + fptr openStream; + fptr getMinNumBuffers; +} PaDriverModelImplementation; + +/* + whenever an implementaion's openstream method is called it should return a + PortAudioStream* whose first segment is actually the following structure. + + the functions pointer members of this structure point to funcitons + which operate in exactly the same way as the corresponding functions + in the PortAudio API. +*/ +struct{ + unsigned long magic; + fptr close; + fptr start; + fptr stop; + fptr abort; + fptr active; + fptr time; + fptr cpuLoad; +} PaStreamImplementation; + +/* + Implementations should set magic to PA_STREAM_MAGIC when opening + a stream _and_ clear it to zero when closing a stream. + All functions which operate on streams should check the validity + of magic. +*/ + +#define PA_STREAM_MAGIC 0x12345678 + +#define PA_CHECK_STREAM( stream )\ + if( ((PaStreamImplementation*)stream)->magic != PA_STREAM_MAGIC )\ + return paBadStreamPtr; + + +/* + PA_API allows the same implementation to be used for single + driver model and multi-driver model operation. If + PA_MULTIDRIVER not defined, PA_API will declare api + functions as global, otherwise they will be static, and include + the drivermodel code. + + Usage would be something like: + + int PA_API(CountDevices)(); + + The PA_MULTIDRIVER_SUPPORT macro declares the initialization and + termination functions required by the multidriver support. it also + allocates and deallocates the PaDriverModelImplementation structure. + + TODO: add macros for initializing PaStreamImplementation PortAudioStream + these would be PA_INITIALIZE_STREAM and PA_TERMINATE_STREAM + they would assign and clear the magic number and assign the + interface functions if neceassary. +*/ + +#ifdef PA_MULTIDRIVER + +#define PA_API( model, name ) static Pa ## model ## _ ## name + +#define PA_MULTIDRIVER_SUPPORT( model )\ +PaError Pa_ ## model ## _MultiDriverTerminate( PaStreamImplementation *impl )\ +{\ + free( impl );\ + return Pa ## model ## _Terminate();\ +}\ +PaError Pa ## model ## _MultiDriverInitialize( PaStreamImplementation** impl )\ +{\ + PaError result = Pa ## model ## _Initialize();\ +\ + if( result == paNoError ){\ + *impl = malloc( sizeof( PaDriverModelImplementation ) );\ + if( impl == NULL ){\ + // TODO: call terminate, return an error + }else{\ + (*impl)->terminate = Pa ## model ## _MultiDriverTerminate();\ + (*impl)->getDriverModelInfo = Pa ## model ## _GetDriverModelInfo();\ + (*impl)->getHostError = Pa ## model ## _GetHostError();\ + // TODO: assign the rest of the interface functions + }\ + }\ + return result;\ +} + +#else /* !PA_MULTIDRIVER */ + +#define PA_API( model, name ) Pa_ ## name + +#define PA_MULTIDRIVER_SUPPORT + +#endif /* PA_MULTIDRIVER */ + + + +#endif /* PA_MULTIDRIVERMODEL_H */ diff --git a/docs/pa_impl_guide.html b/docs/pa_impl_guide.html new file mode 100644 index 0000000..50abc30 --- /dev/null +++ b/docs/pa_impl_guide.html @@ -0,0 +1,197 @@ + + + + + + + + + PortAudio Implementation - Start/Stop + + +  +
+ + + +
+
+

+PortAudio Implementation Guide

+
+ +

This document describes how to implement the PortAudio API on a new +computer platform. Implementing PortAudio on a new platform, makes it possible +to port many existing audio applications to that platform. +

By Phil Burk +
Copyright 2000 Phil Burk and Ross Bencina +

Note that the license says: "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.". +So when you have finished a new implementation, please send it back to +us at  "http://www.portaudio.com" +so that we can make it available for other users. Thank you! +

+Download the Latest PortAudio Implementation

+Always start with the latest implementation available at "http://www.portaudio.com". +Look for the nightly snapshot under the CVS section. +

+Select an Existing Implementation as a Basis

+The fastest way to get started is to take an existing implementation and +translate it for your new platform. Choose an implementation whose architecture +is as close as possible to your target. +
    +
  • +DirectSound Implementation - pa_win_ds - Uses a timer callback for the +background "thread". Polls a circular buffer and writes blocks of data +to keep it full.
  • + +
  • +Windows MME - pa_win_wmme - Spawns an actual Win32 thread. Writes blocks +of data to the HW device and waits for events that signal buffer completion.
  • + +
  • +Linux OSS - pa_linux - Spawns a real thread that writes to the "/dev/dsp" +stream using blocking I/O calls.
  • +
+When you write a new implementation, you will be using some code that is +in common with all implementations. This code is in the folder "pa_common". +It provides various functions such as parameter checking, error code to +text conversion, sample format conversion, clipping and dithering, etc. +

The code that you write will go into a separate folder called "pa_{os}_{api}". +For example, code specific to the DirectSound interface for Windows goes +in "pa_win_ds". +

+Read Docs and Code

+Famialiarize yourself with the system by reading the documentation provided. +here is a suggested order: +
    +
  1. +User Programming Tutorial
  2. + +
  3. +Header file "pa_common/portaudio.h" which defines API.
  4. + +
  5. +Header file "pa_common/pa_host.h" for host dependant code. This definces +the routine you will need to provide.
  6. + +
  7. +Shared code in "pa_common/pa_lib.c".
  8. + +
  9. +Docs on Implementation of Start/Stop +code.
  10. +
+ +

+Implement  Output to Default Device

+Now we are ready to crank some code. For instant gratification, let's try +to play a sine wave. +
    +
  1. +Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c" +and the implementation specific file you are creating.
  2. + +
  3. +For now, just stub out the device query code and the audio input code.
  4. + +
  5. +Modify PaHost_OpenStream() to open your default target device and get everything +setup.
  6. + +
  7. +Modify PaHost_StartOutput() to start playing audio.
  8. + +
  9. +Modify PaHost_StopOutput() to stop audio.
  10. + +
  11. +Modify PaHost_CloseStream() to clean up. Free all memory that you allocated +in PaHost_OpenStream().
  12. + +
  13. +Keep cranking until you can play a sine wave using "patest_sine.c".
  14. + +
  15. +Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".
  16. + +
  17. +To test your Open and Close code, try "patest_many.c".
  18. + +
  19. +Now test to make sure that the three modes of stopping are properly supported +by running "patest_stop.c".
  20. + +
  21. +Test your implementation of time stamping with "patest_sync.c".
  22. +
+ +

+Implement Device Queries

+Now that output is working, lets implement the code for querying what devices +are available to the user. Run "pa_tests/pa_devs.c". It should print all +of the devices available and their characteristics. +

+Implement Input

+Implement audio input and test it with: +
    +
  1. +patest_record.c - record in half duplex, play back as recorded.
  2. + +
  3. +patest_wire.c - full duplex, copies input to output. Note that some HW +may not support full duplex.
  4. + +
  5. +patest_fuzz.c - plug in your guitar and get a feel for why latency is an +important issue in computer music.
  6. + +
  7. +paqa_devs.c - try to open every device and use it with every possible format
  8. +
+ +

+Debugging Tools

+You generally cannot use printf() calls to debug real-time processes because +they disturb the timing. Also calling printf() from your background thread +or interrupt could crash the machine. So PA includes a tool for capturing +events and storing the information while it is running. It then prints +the events when Pa_Terminate() is called. +
    +
  1. +To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h" +from a (0) to a (1).
  2. + +
  3. +Link with "pa_common/pa_trace.c".
  4. + +
  5. +Add trace messages to your code by calling:
  6. + +
       void AddTraceMessage( char *msg, int data ); +
    for example +
       AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", +past->past_NumCallbacks ); +
  7. +Run your program. You will get a dump of events at the end.
  8. + +
  9. +You can leave the trace messages in your code. They will turn to NOOPs +when you change TRACE_REALTIME_EVENTS back to (0).
  10. +
+ +

+Delivery

+Please send your new code along with notes on the implementation back to +us at "http://www.portaudio.com". +We will review the implementation and post it with your name. If you had +to make any modifications to the code in "pa_common" or "pa_tests" please +send us those modifications and your notes. We will try to merge your changes +so that the "pa_common" code works with all implementations. +

If you have suggestions for how to make future implementations easier, +please let us know. +
THANKS! +
  + + diff --git a/docs/pa_impl_startstop.html b/docs/pa_impl_startstop.html new file mode 100644 index 0000000..0f2d0ce --- /dev/null +++ b/docs/pa_impl_startstop.html @@ -0,0 +1,190 @@ + + + + + + + + + PortAudio Implementation - Start/Stop + + +  +

+ + + +
+
+

+PortAudio Implementation

+
+ +

+Starting and Stopping Streams

+PortAudio is generally executed in two "threads". The foreground thread +is the application thread. The background "thread" may be implemented as +an actual thread, an interrupt handler, or a callback from a timer thread. +

There are three ways that PortAudio can stop a stream. In each case +we look at the sequence of events and the messages sent between the two +threads. The following variables are contained in the internalPortAudioStream. +

int   past_IsActive;     +/* Background is still playing. */ +
int   past_StopSoon;     /* Stop +when last buffer done. */ +
int   past_StopNow;      /* +Stop IMMEDIATELY. */
+ +

+Pa_AbortStream()

+This function causes the background thread to terminate as soon as possible +and audio I/O to stop abruptly. +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Foreground ThreadBackground Thread
sets StopNow
sees StopNow
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
+ +

+Pa_StopStream()

+This function stops the user callback function from being called and then +waits for all audio data written to the output buffer to be played. In +a system with very low latency, you may not hear any difference between +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Foreground ThreadBackground Thread
sets StopSoon
stops calling user callback
continues until output buffer empty
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
+ +

+User callback returns one.

+If the user callback returns one then the user callback function will no +longer be called. Audio output will continue until all audio data written +to the output buffer has been played. Then the audio I/O is stopped, the +background thread terminates, and the stream becomes inactive. +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Foreground ThreadBackground Thread
callback returns 1
sets StopSoon
stops calling user callback
continues until output buffer empty
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O
+ +
  + + diff --git a/docs/pa_tut_asio.html b/docs/pa_tut_asio.html new file mode 100644 index 0000000..1c3e5bf --- /dev/null +++ b/docs/pa_tut_asio.html @@ -0,0 +1,55 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for ASIO (Windows or Macintosh)

+ +
ASIO is a low latency audio API from Steinberg. To compile +an ASIO application, you must first download +the ASIO SDK from Steinberg. You also need to obtain ASIO drivers for +your audio device. +

Note: I am using '/' as a file separator below. On Macintosh replace +'/' with ':'. On Windows, replace '/' with '\'. +

 To use ASIO with the PortAudio library add the following source +files to your project: +

+
pa_asio/pa_asio.cpp
+
+and also these files from the ASIO SDK: +
+
common/asio.cpp
+host/asiodrivers.cpp
+host/asiolist.cpp
+
+and add these directories to the path for include files +
+
asiosdk2/host/pc   (for Windows)
+asiosdk2/common
+asiosdk2/host
+
+You may try compiling the "pa_tests/patest_saw.c" file first because it +is the simplest.
+home | +contents +| previousnext + + diff --git a/docs/pa_tut_callback.html b/docs/pa_tut_callback.html new file mode 100644 index 0000000..f5ccaf0 --- /dev/null +++ b/docs/pa_tut_callback.html @@ -0,0 +1,91 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Writing a Callback Function

+ +
To write a program using PortAudio, you must include the "portaudio.h" +include file. You may wish to read "portaudio.h" +because it contains a complete description of the PortAudio functions and +constants. +
+
#include "portaudio.h"
+
+The next task is to write your custom callback function. It is a function +that is called by the PortAudio engine whenever it has captured audio data, +or when it needs more audio data for output. +

Your callback function is often called by an interrupt, or low level +process so you should not do any complex system activities like allocating +memory, or reading or writing files, or printf(). Just crunch numbers and +generate audio signals. What is safe or not safe will vary from platform +to platform. On the Macintosh, for example, you can only call "interrupt +safe" routines. Also do not call any PortAudio functions in the callback +except for Pa_StreamTime() and Pa_GetCPULoad(). +

Your callback function must return an int and accept the exact parameters +specified in this typedef: +

+
typedef int (PortAudioCallback)(
+               void *inputBuffer, void *outputBuffer,
+               unsigned long framesPerBuffer,
+               PaTimestamp outTime, void *userData );
+
+Here is an example callback function from the test file "patests/patest_saw.c". +It calculates a simple left and right sawtooth signal and writes it to +the output buffer. Notice that in this example, the signals are of float +data type. The signals must be between -1.0 and +1.0. You can also use +16 bit integers or other formats which are specified during setup. You +can pass a pointer to your data structure through PortAudio which will +appear as userData. +
+
int patestCallback(  void *inputBuffer, void *outputBuffer,
+                     unsigned long framesPerBuffer,
+                     PaTimestamp outTime, void *userData )
+{
+    unsigned int i;
+/* Cast data passed through stream to our structure type. */
+    paTestData *data = (paTestData*)userData;
+    float *out = (float*)outputBuffer;
+        
+    for( i=0; i<framesPerBuffer; i++ )
+    {
+    /* Stereo channels are interleaved. */
+        *out++ = data->left_phase;              /* left */
+        *out++ = data->right_phase;             /* right */
+
+    /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
+        data->left_phase += 0.01f;
+    /* When signal reaches top, drop back down. */
+        if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
+
+    /* higher pitch so we can distinguish left and right. */
+        data->right_phase += 0.03f; 
+        if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
+    }
+    return 0;
+}
+
+
+home | +contents +| previousnext + + diff --git a/docs/pa_tut_devs.html b/docs/pa_tut_devs.html new file mode 100644 index 0000000..1756992 --- /dev/null +++ b/docs/pa_tut_devs.html @@ -0,0 +1,65 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Querying for Available Devices

+ +
There are often several different audio devices available in +a computer with different capabilities. They can differ in the sample rates +supported, bit widths, etc. PortAudio provides a simple way to query for +the available devices, and then pass the selected device to Pa_OpenStream(). +For an example, see the file "pa_tests/pa_devs.c". +

To determine the number of devices: +

+
numDevices = Pa_CountDevices();
+
+You can then query each device in turn by calling Pa_GetDeviceInfo() with +an index. +
+
for( i=0; i<numDevices; i++ ) {
+     pdi = Pa_GetDeviceInfo( i );
+
+It will return a pointer to a PaDeviceInfo structure which is +defined as: +
+
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 nativeSampleFormat;
+}PaDeviceInfo;
+
+If the device supports a continuous range of sample rates, then numSampleRates +will equal -1, and the sampleRates array will have two values, the minimum  +and maximum rate. +

The device information is allocated by Pa_Initialize() and freed by +Pa_Terminate() so you do not have to free() the structure returned by Pa_GetDeviceInfo().

+home | +contents +| previousnext + + diff --git a/docs/pa_tut_explore.html b/docs/pa_tut_explore.html new file mode 100644 index 0000000..91c08a5 --- /dev/null +++ b/docs/pa_tut_explore.html @@ -0,0 +1,42 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Exploring PortAudio

+ +
Now that you have a good idea of how PortAudio works, you can +try out the test programs. +
    +
  • +For an example of playing a sine wave, see "pa_tests/patest_sine.c".
  • + +
  • +For an example of recording and playing back a sound, see  "pa_tests/patest_record.c".
  • +
+I also encourage you to examine the source for the PortAudio libraries. +If you have suggestions on ways to improve them, please let us know. if +you want to implement PortAudio on a new platform, please let us know as +well so we can coordinate people's efforts.
+home | contents +| previous |  next + + diff --git a/docs/pa_tut_init.html b/docs/pa_tut_init.html new file mode 100644 index 0000000..91bfa8d --- /dev/null +++ b/docs/pa_tut_init.html @@ -0,0 +1,43 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Initializing PortAudio

+ +
Before making any other calls to PortAudio, you must call Pa_Initialize(). +This will trigger a scan of available devices which can be queried later. +Like most PA functions, it will return a result of type paError. +If the result is not paNoError, then an error has occurred. +
+
err = Pa_Initialize();
+if( err != paNoError ) goto error;
+
+You can get a text message that explains the error message by passing it +to +
+
printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );
+
+
+home | contents +| previousnext + + diff --git a/docs/pa_tut_mac.html b/docs/pa_tut_mac.html new file mode 100644 index 0000000..bf3dafd --- /dev/null +++ b/docs/pa_tut_mac.html @@ -0,0 +1,41 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for Macintosh

+ +
To compile a Macintosh application with the PortAudio library, +add the following source files to your project: +
+
pa_mac:pa_mac.c
+pa_common:pa_lib.c
+pa_common:portaudio.h
+pa_common:pa_host.h
+
+Also add the Apple SoundLib to your project. +

You may try compiling the "pa_tests:patest_saw.c" file first because +it is the simplest.

+home | +contents +| previousnext + + diff --git a/docs/pa_tut_mac_osx.html b/docs/pa_tut_mac_osx.html new file mode 100644 index 0000000..3af8c14 --- /dev/null +++ b/docs/pa_tut_mac_osx.html @@ -0,0 +1,46 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for Macintosh OS X

+ +
To compile a Macintosh OS X CoreAudio application with the +PortAudio library: +

Create a new ProjectBuilder project. You can use a "Tool" project to +run the PortAudio examples. +

Add the following source files to your Project: +

+
pa_mac_core/pa_mac_core.c
+pa_common/pa_lib.c
+pa_common/portaudio.h
+pa_common/pa_host.h
+pa_common/pa_convert.c
+
+Add the Apple CoreAudio.framework to your project by selecting "Add FrameWorks..." +from the Project menu. +

Compile and run the "pa_tests:patest_saw.c" file first because it is +the simplest.

+home | +contents +| previousnext + + diff --git a/docs/pa_tut_open.html b/docs/pa_tut_open.html new file mode 100644 index 0000000..1621ef3 --- /dev/null +++ b/docs/pa_tut_open.html @@ -0,0 +1,52 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Opening a Stream using Defaults

+ +
The next step is to open a stream which is similar to opening +a file. You can specify whether you want audio input and/or output, how +many channels, the data format, sample rate, etc. There are two calls for +opening streams, Pa_OpenStream() and Pa_OpenDefaultStream(). +

Pa_OpenStream() takes extra  parameters which give you +more control. You can normally just use Pa_OpenDefaultStream() +which just calls Pa_OpenStream() with some reasonable +default values.  Let's open a stream for stereo output, using floating +point data, at 44100 Hz. +

+
err = Pa_OpenDefaultStream(
+    &stream,        /* passes back stream pointer */
+    0,              /* no input channels */
+    2,              /* stereo output */
+    paFloat32,      /* 32 bit floating point output */
+    44100,          /* sample rate */
+    256,            /* frames per buffer */
+    0,              /* number of buffers, if zero then use default minimum */
+    patestCallback, /* specify our custom callback */
+    &data );        /* pass our data through to callback */
+
+If you want to use 16 bit integer data, pass paInt16 instead of +paFloat32.
+home | contents +| previousnext + + diff --git a/docs/pa_tut_oss.html b/docs/pa_tut_oss.html new file mode 100644 index 0000000..1bb76f2 --- /dev/null +++ b/docs/pa_tut_oss.html @@ -0,0 +1,46 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for Unix OSS

+ +
[Skip this page if you are not using Unix and OSS] +

We currently support the OSS +audio drivers for Linux, Solaris, and FreeBSD. We hope to someday support +the newer ALSA drivers. +

    +
  1. +cd to pa_unix_oss directory
  2. + +
  3. +Edit the Makefile and uncomment one of the tests. You may try compiling +the "patest_sine.c" file first because it is very simple.
  4. + +
  5. +gmake run
  6. +
+
+home | +contents +| previousnext + + diff --git a/docs/pa_tut_over.html b/docs/pa_tut_over.html new file mode 100644 index 0000000..baa9920 --- /dev/null +++ b/docs/pa_tut_over.html @@ -0,0 +1,92 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Overview of PortAudio

+ +
PortAudio is a library that provides streaming audio input +and output. It is a cross-platform API (Application Programming Interface) +that works on Windows, Macintosh, Unix running OSS, SGI, BeOS, and perhaps +other platforms by the time you read this. This means that you can write +a simple 'C' program to process or generate an audio signal, and that program +can run on several different types of computer just by recompiling the +source code. +

Here are the steps to writing a PortAudio application: +

    +
  1. +Write a callback function that will be called by PortAudio when audio processing +is needed.
  2. + +
  3. +Initialize the PA library and open a stream for audio I/O.
  4. + +
  5. +Start the stream. Your callback function will be now be called repeatedly +by PA in the background.
  6. + +
  7. +In your callback you can read audio data from the inputBuffer and/or write +data to the outputBuffer.
  8. + +
  9. +Stop the stream by returning 1 from your callback, or by calling a stop +function.
  10. + +
  11. +Close the stream and terminate the library.
  12. +
+
+ +
There is also another interface +provided that allows you to generate audio in the foreground. You then +simply write data to the stream and the tool will not return until it is +ready to accept more data. This interface is simpler to use but is usually +not preferred for large applications because it requires that you launch +a thread to perform the synthesis. Launching a thread may be difficult +on non-multi-tasking systems such as the Macintosh prior to MacOS X. +

Let's continue by building a simple application that will play a sawtooth +wave. +

Please select the page for the specific implementation you would like +to use: +

+or continue with the next page of the programming +tutorial.
+home | +contents +| previous + + diff --git a/docs/pa_tut_pc.html b/docs/pa_tut_pc.html new file mode 100644 index 0000000..87e5f9a --- /dev/null +++ b/docs/pa_tut_pc.html @@ -0,0 +1,78 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Compiling for Windows (WMME or DirectSound)

+ +
To compile PortAudio for Windows, you can choose between two +options. One implementation uses the DirectSound API. The other uses the +Windows MultiMedia Extensions API (aka WMME or WAVE). +

Some advantages of using DirectSound are that DirectSound may have lower +latency than WMME, and supports effects processing plugins. But one disadvantage +is that DirectSound is not installed on all PCs, and is not well supported +under Windows NT. So WMME is the best choice for most projects. +

For either implementation add the following source files to your project: +

+
pa_common\pa_lib.c
+pa_common\portaudio.h
+pa_common\pa_host.h
+
+Link with the system library "winmm.lib". For Visual C++: +
    +
  1. +select "Settings..." from the "Project" menu,
  2. + +
  3. +select the project name in the tree on the left,
  4. + +
  5. +choose "All Configurations" in the popup menu above the tree,
  6. + +
  7. +select the "Link" tab,
  8. + +
  9. +enter "winmm.lib", without quotes, as the first item in the "Object/library +modules:" field.
  10. +
+WMME - To use the WMME implementation, add the following source +files to your project: +
pa_win_wmme/pa_win_wmme.c
+DirectSound - If you want to use the DirectSound implementation +of PortAudio then you must have a recent copy of the free +DirectX +SDK for Developers from Microsoft installed on your computer. To compile +an application add the following source files to your project: +
+
pa_win_ds\dsound_wrapper.c
+pa_win_ds\pa_dsound.c
+
+Link with the system library "dsound.lib" using the procedure described +above for "winmm.lib".
+ +
You might try compiling the "pa_tests\patest_saw.c" file first +because it is the simplest.
+home | +contents +| previousnext + + diff --git a/docs/pa_tut_run.html b/docs/pa_tut_run.html new file mode 100644 index 0000000..5c70d08 --- /dev/null +++ b/docs/pa_tut_run.html @@ -0,0 +1,56 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Starting and Stopping a Stream

+ +
The stream will not start running until you call Pa_StartStream(). +Then it will start calling your callback function to perform the audio +processing. +
+
err = Pa_StartStream( stream );
+if( err != paNoError ) goto error;
+
+At this point, audio is being generated. You can communicate to your callback +routine through the data structure you passed in on the open call, or through +global variables, or using other interprocess communication techniques. +Please be aware that your callback function may be called at interrupt +time when your foreground process is least expecting it. So avoid sharing +complex data structures that are easily corrupted like double linked lists. +

In many of the tests we simply sleep for a few seconds so we can hear +the sound. This is easy to do with Pa_Sleep() which will sleep for some +number of milliseconds. Do not rely on this function for accurate scheduling. +it is mostly for writing examples. +

+
/* Sleep for several seconds. */
+Pa_Sleep(NUM_SECONDS*1000);
+
+When you are through, you can stop the stream from the foreground. +
+
err = Pa_StopStream( stream );
+if( err != paNoError ) goto error;
+
+You can also stop the stream by returning 1 from your custom callback function.
+home | contents +| previousnext + + diff --git a/docs/pa_tut_rw.html b/docs/pa_tut_rw.html new file mode 100644 index 0000000..93c7b8b --- /dev/null +++ b/docs/pa_tut_rw.html @@ -0,0 +1,79 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Blocking Read/Write Functions

+ +
[Note: These functions are not part of the official PortAudio +API. They are simply built on top of PortAudio as an extra utility. Also +note that they are under evaluation and their definition may change.] +

There are two fundamentally different ways to design an audio API. One +is to use callback functions the way we have already shown. The callback +function operates under an interrupt or background thread This leaves the +foreground application free to do other things while the audio just runs +in the background. But this can sometimes be awkward. +

So we have provided an alternative technique that lets a program generate +audio in the foreground and then just write it to the audio stream as if +it was a file. If there is not enough room in the audio buffer for more +data, then the write function will just block until more room is available. +This can make it very easy to write an audio example. To use this tool, +you must add the files "pablio/pablio.c" and "pablio/ringbuffer.c" to your +project. You must also: +

+
#include "pablio.h"
+
+Here is a short excerpt of a program that opens a stream for input and +output. It then reads a block of samples from input, and writes them to +output, in a loop.  The complete example can be found in "pablio/test_rw.c". +
+
    #define SAMPLES_PER_FRAME     (2)
+    #define FRAMES_PER_BLOCK    (1024)
+    SAMPLE          samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
+    PaError         err;
+    PABLIO_Stream  *aStream;
+
+/* Open simplified blocking I/O layer on top of PortAudio. */
+    err = OpenAudioStream( &rwbl, SAMPLE_RATE, paFloat32,
+                         (PABLIO_READ_WRITE | PABLIO_STEREO) );
+    if( err != paNoError ) goto error;
+
+/* Process samples in the foreground. */
+    for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
+    {
+    /* Read one block of data into sample array from audio input. */
+        ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK );
+    /*
+    ** At this point you could process the data in samples array,
+    ** and write the result back to the same samples array.
+    */
+    /* Write that same frame of data to output. */
+        WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK );
+    }
+
+    CloseAudioStream( aStream );
+
+
+home | +contents +| previousnext + + diff --git a/docs/pa_tut_term.html b/docs/pa_tut_term.html new file mode 100644 index 0000000..1c72209 --- /dev/null +++ b/docs/pa_tut_term.html @@ -0,0 +1,47 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Terminating PortAudio

+ +
You can start and stop a stream as many times as you like. +But when you are done using it, you should close it by calling:
+ +
+
+
err = Pa_CloseStream( stream );
+if( err != paNoError ) goto error;
+
+Then when you are done using PortAudio, you should terminate the whole +system by calling: +
+
Pa_Terminate();
+
+That's basically it. You can now write an audio program in 'C' that will +run on multiple platforms, for example PCs and Macintosh. +

In the rest of the tutorial we will look at some additional utility +functions, and a different way of using PortAudio that does not require +the use of a callback function.

+home | contents +| previousnext + + diff --git a/docs/pa_tut_util.html b/docs/pa_tut_util.html new file mode 100644 index 0000000..f4b5475 --- /dev/null +++ b/docs/pa_tut_util.html @@ -0,0 +1,55 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

+Utility Functions

+ +
Here are several more functions that are not critical, but +may be handy when using PortAudio. +

Pa_StreamActive() returns one when the stream in playing audio, zero +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 number of samples that have been generated. +PaTimeStamp is a double precision number which is a convenient way to pass +big numbers around even though we only need integers. +
+
PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+The "CPU Load" is a fraction of total CPU time consumed by the stream's +audio processing. 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 );
+
+
+home | +contents | previous +|  next + + diff --git a/docs/pa_tutorial.html b/docs/pa_tutorial.html new file mode 100644 index 0000000..1371c44 --- /dev/null +++ b/docs/pa_tutorial.html @@ -0,0 +1,46 @@ + + + + + + + + + PortAudio Tutorial + + +  +
+ + + +
+
+

+PortAudio Tutorial

+
+ +

Copyright 2000 Phil Burk and Ross Bencina +

+Table of Contents

+ +
Overview of PortAudio +
Compiling for Macintosh OS 7,8,9 +
Compiling for Macintosh OS X +
Compiling for Windows (DirectSound and WMME) +
Compiling for ASIO on Windows or Mac OS +8,9 +
Compiling for Unix OSS +
Writing a Callback Function +
Initializing PortAudio +
Opening a Stream using Defaults +
Starting and Stopping a Stream +
Cleaning Up +
Utilities +
Querying for Devices +
Blocking Read/Write Functions +
Exploring the PortAudio Package
+home | contents | +previous |  next + + diff --git a/docs/portaudio_h.txt b/docs/portaudio_h.txt new file mode 100644 index 0000000..6d60086 --- /dev/null +++ b/docs/portaudio_h.txt @@ -0,0 +1,425 @@ +#ifndef PORT_AUDIO_H +#define PORT_AUDIO_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * 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 +} 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 ); + +/* + Return host specific error. + This can be called after receiving a paHostError. +*/ +long Pa_GetHostError( void ); + +/* + Translate the 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 devices. + + The floating point representation uses +1.0 and -1.0 as the respective + maximum and minimum. + +*/ + +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)) /* unsigned 8 bit, 128 is "ground" */ +#define paCustomFormat ((PaSampleFormat) (1<<16)) + +/* + Device enumeration mechanism. + + Device ids range from 0 to Pa_CountDevices()-1. + + Devices may support input, output or both. Device 0 is always the "default" + device and should support at least stereo in and out if that is available + on the taget platform _even_ if this involves kludging an input/output + device on platforms that usually separate input from output. Other platform + specific devices are specified by positive device ids. +*/ + +typedef int PaDeviceID; +#define paNoDevice -1 + +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; + + +int Pa_CountDevices(); +/* + Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() + + Return the default device ID or paNoDevice if there is no devices. + 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 ID by using + the supplied application "pa_devs". +*/ +PaDeviceID Pa_GetDefaultInputDeviceID( void ); +PaDeviceID Pa_GetDefaultOutputDeviceID( void ); + +/* + PaTimestamp is used to represent a continuous sample clock with arbitrary + start time useful for syncronisation. The type is used in the outTime + argument to the callback function and the result of Pa_StreamTime() +*/ + +typedef double PaTimestamp; + +/* + Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure + referring to the device specified by id. + If id is out of range the function returns NULL. + + The returned structure is owned by the PortAudio implementation and must + not be manipulated or freed. The pointer is guaranteed to be valid until + between calls to Pa_Initialize() and Pa_Terminate(). +*/ + +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID ); + +/* + PortAudioCallback is implemented by clients of the portable audio api. + + 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 nonzero 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 + nonzero 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. + + [ suggestions? ] +*/ + +#define paNoFlag (0) +#define paClipOff (1<<0) /* disable defult 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 + device input record for the device specified in the inputDevice parameter. + If inputDevice is paNoDevice numInputChannels is ignored. + + inputSampleFormat is the 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 sound devices 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 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. 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 behavior 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: + Apon 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 nonzero 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 ouput 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 (same 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 when the stream is playing audio, + zero 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 for the stream in samples. + This time may be used as a time reference (for example syncronising audio to + MIDI). +*/ + +PaTimestamp Pa_StreamTime( PortAudioStream *stream ); + +/* + The "CPU Load" is a fraction of total CPU time consumed by the + stream's audio processing. + 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 ); + +/* + Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for + 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 ); + +/* + Sleep for at least 'msec' milliseconds. + You may sleep longer than the requested time so don't rely + on this for accurate musical timing. +*/ +void Pa_Sleep( long msec ); + +/* + Return size in bytes of a single sample in a given PaSampleFormat + or paSampleFormatNotSupported. +*/ +PaError Pa_GetSampleSize( PaSampleFormat format ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PORT_AUDIO_H */ diff --git a/docs/portaudio_icmc2001.pdf b/docs/portaudio_icmc2001.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dd074b7d334d9b0d4415330c2a123131aa130115 GIT binary patch literal 50968 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
_indHVG)3^ZrAZg!fH65_!ltCUc#av(>q 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 + +Proposed Changes to PortAudio API + + + + + +  +

+ + + +
+
+

Proposed Changes to PortAudio API

+
+
+

PortAudio Home Page

+ +

Updated: January 7, 2002

+

This document describes modifications to the PortAudio API currently being considered by the developer community. It is intended to capture the current state of discussions. The authors are the various members of the PortAudio community and are too numerous to mention. Please refer to the mailing list archives to see who said what.

+

We are still at the design stage with all of these proposals - if you think something is missing, could be improved, or would just like to comment please do so on the PortAudio mailing list.

+

  http://techweb.rfa.org/mailman/listinfo/portaudio

+

Contents

+ + + +

The proposals above which are marked with a * are under construction, those marked with |C| are essentially complete but require approval or comment before they are considered complete. The remaining proposals are essentially complete and will be implemented as-is unless significant objections are raised.

+

____________

+

PortAudioCallback Underflow/Overflow Handling

+

Status

+

This proposal is sufficiently well defined to be implemented

+

Background

+

There are conditions where a full-duplex stream needs to generate output but doesn't have any input available, or where it has too much input so some input needs to be discarded (not passed to the output.) There is also the case where output is needed, but the callback has (transiently) consumed so much CPU time that output has to be generated without the callback being called.

+

Currently (V17) the PortAudioCallback Function handles these underflow/overflow conditions by passing NULL buffer pointers to the callback. This can happen if the output is pre-rolled and there is not yet any input data. It can also happen if the input underflows.

+

A number of concerns have been raised about the current system: For PortAudio to discard input just because it is not needed for output is considered unacceptable for some recording applications. Passing of NULL buffer pointers has been deemed to be too error prone and requires too much housekeeping for simple programs.

+

See http://techweb.rfa.org/pipermail/portaudio/2001-October/000222.html and subsequent messages in various threads.

+

This proposal seeks to keep the PortAudioCallback as simple as possible for ease-of-use while providing full access to overflow/underflow information, and all input and output sample data when clients require it.

+

Proposal

+

For streams providing input, the inputBuffer parameter will always point to a valid memory location containing framesPerBuffer frames of sample data in the requested format. The inputBuffer parameter will be NULL for output only streams. Similarly, the outputBuffer parameter will be NULL for input only streams, otherwise it will point to a valid memory location containing framesPerBuffer frames of sample data.

+

A new parameter will be added to the PortAudioCallback Function that gives the status of the data as bit flags.

+
typedef int (PortAudioCallback)( 
+  void *inputBuffer, void *outputBuffer, 
+  unsigned long framesPerBuffer, 
+  PaTimestamp outTime, 
+  unsigned long  statusFlags,
+  void *userData ); 
+
+These bits may be set in the statusFlags parameter. 
+#define paInputUnderflow   (1<<0) /* Input data is all zeros because no real data is available. */ 
+#define paInputOverflow    (1<<1) /* Input data was discarded by PortAudio */
+#define paOutputUnderflow  (1<<2) /* Output data was inserted by PortAudio because the callback is using too much CPU */
+#define paOutputOverflow   (1<<3) /* Output data will be ignored because no room is available. */
+

 

+

New rules will govern when the PortAudioCallback is called:

+ +
    +
  • For input-only streams, the callback will be called for every available input buffer. If the callback takes too long to complete and input samples have to be discarded the paInputOverflow flag will be set the next time the callback is called. In input-only stream will never be called with the paInputUnderflow flag set.
  • +
  • For output-only streams, the callback will be called whenever an output buffer needs to be filled, except when doing so would cause the stream to fall further behind real-time due to CPULoad being too high. In such cases PortAudio will insert silence or repeat the previous buffer to the output and the paOutputUnderflow bit will be set next time the callback is called. An output-only stream will never be called with the paOutputOverflow flag set.
  • +
  • By default, a full duplex stream will behave according to the same rules as an output-only stream. If input is not available, the paInputUnderflow bit will be set and the input buffers will contain zeros. In the case of an input buffer overflow, PortAudio will discard input - in such cases the input samples will not be passed to a callback, and paInputOverflow will be set next time the callback is called to generate more output. A default full-duplex stream will never be called with the paOutputOverflow flag set.
  • +
  • A new mode flag paNeverDropInput to Pa_OpenStream() specifies that a full duplex stream will not discard overflowed input samples without calling the callback. When an input buffer overflow occurs, the callback will be called with the paOutputOverflow flag set, when the callback completes the output buffers will be discarded.
+ +

Note that the default full-duplex mode is intended to cover most common uses of PortAudio, where the client wants a simple audio streaming interface, and is happy to let PortAudio handle buffer underflow/overflow conditions when they occurs.

+

Impact Analysis

+

This proposal involves adding a new statusFlags parameter to PortAudioCallback. This will require all clients to update their callback implementations accordingly. Clients who previously checked for NULL buffers will be able to remove such checks.

+

____________

+

Improve Device Format Query System

+

Status

+

This proposal is open for discussion.

+

Background

+

It has been noted that the current method (Pa_GetDeviceInfo()) of querying devices for supported sample formats, channels and sample rates is weak. It does not cleanly differentiate between 'PortAudio supported' formats and 'native' formats, and it is incapable of representing formats where the parameters are interdependent (eg where full duplex is only supported for certain sample rates.) We have also found that a static structure is not a good match for many driver models where format discovery is performed by polling the driver. Even if a sound card supports arbitrary sample rates, the driver model may only allow a client to poll to see whether a rate is available rather than providing the available rate ranges.

+

It has been noted that most (platform specific) audio APIs do a pretty bad job of allowing for device capability querying. Even the better APIs (ALSA is perhaps one) don't necessarily provide accurate information. This proposal should seek to maximise the amount of information that can be extracted from existing APIs while remaining expressive enough to take full advantage of APIs with more advanced capability querying systems should they become available in the future.

+

Proposal

+

Use PaDeviceInfo only for representing information that can be expressed without polling the driver multiple times, or only check for "standard" formats, or leave it unchanged, or do away with it completely.

+

And/Or

+

We could do things the way MME does: if Pa_OpenStream() is called with a NULL stream parameter then the stream isn't opened, but it is checked to see if the device supports the specified format - if the format is supported then paNoError would be returned, otherwise an error would be returned.

+

And/Or

+

Add an IsFormatSupported() function:

+
Pa_IsFormatSupported( deviceId, inputDevice, numInputChannels, inputSampleFormat, inputDriverInfo, outputDevice, numOutputChannels, outputSampleFormat, outputDriverInfo, sampleRate );
+

Impact Analysis

+

This proposal will provide clients with more expressive methods for querying device capabilities, which should improve the utility of PortAudio. It is not yet clear what the full impact of this proposal will be.

+

____________

+

Improve Latency Mechanisms

+

Status

+

This proposal is open for discussion.

+

Background

+

The current mechanism for setting latency is not considered optimal by all clients of the API. There seems to be some tension between using the framesPerBuffer parameter of Pa_OpenStream as a latency control parameter and as a specifier for the number of frames supplied to the callback. Specifying latency as a single millisecond value would be more user friendly for some users, however some driver models need latency to be tuned by specifying buffer sizes and number of buffers. Additionally, it not clear whether separate input and output buffer counts would allow tuning of lower latencies in some circumstances.

+

A related issue is the need to improve the interface available to determine default latency parameters. The most recent proposal is documented below, however there is still some debate as to whether this is satisfactory.

+

See this thread: http://techweb.rfa.org/pipermail/portaudio/2001-October/000196.html

+

Proposal

+

The numBuffers parameter for Pa_OpenStream() could accept the following values in addition to the normal N>0 values.  Use PA_LATENCY_LOW for interactive performance, when response time is critical.  Use PA_LATENCY_HIGH when playing sound files or other non-interactive uses, when glitch free operation is more critical.

+

#define PA_LATENCY_WHATEVER   (0) /* or _NO_OPINION or? */
+#define PA_LATENCY_LOW       (-1)  /* For interactive performance. */
+#define PA_LATENCY_HIGH      (-2)  /* For playing sound files. */

+

Currently, when numBuffers>0, Pa_OpenStream will constrain the actual numBuffers so that the latency is within a valid range determined by the driver, or an environment variables such as PA_MIN_LATENCY_MSEC. Propose changing the behaviour so that the requested value is honoured as much as possible. This will allow the user to override the minimum if they know their system can handle it. This might be used, for example on patched Linux kernels. By doing this we simplify the implementations and eliminate the need for adding a Pa_SetMinimumLatency() function.

+

/* Negative return values are (double) paError */
+double Pa_GetMinimumLatency( int deviceId, double frameRate );
+double Pa_GetPreferredLatency( int deviceId, double frameRate );
+double Pa_GetMaximumLatency( int deviceId, double frameRate );

+

/* This would only be valid after Pa_OpenStream() */
+double Pa_GetActualLatency( int deviceId, double frameRate );

+

Discussion

+

This proposal does not yet address the question of whether there needs to be separate numInputBuffers and numOutputBuffers parameters for optimal latency specification.

+

____________

+

Blocking Read/Write API

+

Status

+

This proposal is waiting to be written up (assigned to Roger Dannenberg.)

+

Background

+

Many PortAudio users have requested a blocking read/write API which will be supported in addition to the current callback based API. A blocking Read/Write API would allow a more natural style of multi-threaded programming, and facilitate single-threaded reactive applications, while insulating clients from platform-specific thread synchronisation facilities. A blocking read/write API would also be useful when binding PortAudio to languages that don't easily support callbacks such as Python, Java, Lisp and Smalltalk. However in this case it has been noted that a blocking API is not sufficient - the host language also needs to support native threads to interact efficiently with blocking.

+

Adding a blocking Read/Write interface to PortAudio has been discussed on a number of occasions, including the following threads:

+

http://techweb.rfa.org/pipermail/portaudio/2001-August/000063.html a long thread about blocking calls.

+

http://techweb.rfa.org/pipermail/portaudio/2001-August/000137.html this is Roger Dannenberg's proposal and a subsequent discussion

+

http://techweb.rfa.org/pipermail/portaudio/2001-August/000144.html is a thread discussing using blocking APIs with other languages

+

Proposal

+

This proposal needs further documentation, but some details are provided below.

+

If a NULL callback parameter is passed to Pa_OpenStream() then the stream is opened in blocking mode. This enables users to call Pa_WriteStream() and Pa_ReadStream() to read and write sample data.

+

For a while there was a talk about only requiring implementations to implement blocking calls and that callbacks would always be implemented on top of blocking. The current direction is that this decision will be made independently for each driver-model.

+

There needs to be a way to call the read and write functions without them blocking or to determine in advance how many samples can be read or written without blocking. One proposal to avoid blocking in environments without native threads is to ask PortAudio how many frames are available, and then to sleep() (using non-native thread management) until the next buffer boundary.

+

Roger Dannenberg wrote the following email that is included here because it didn't seem to make it into the mailing list archive:

+
> It would be nice if the buffer could be returned to PortAudio as soon
+> as the client had finished with it. For example, in the MME
+> implementation this would allow the buffer to be requeued with
+> the driver sooner.
+
+My model is that, in general, you should target the worst case where audio processing takes most of the CPU time. In that case, the app finishes reading and writing buffers just before it's time to start the next buffer. In that case, there's little to gain by trying to return buffers early. Alternatively, if CPU time is negligible, wouldn't returning the buffer immediately (to MME) effectively increase the buffer count by one? In other words, you could just allocate one extra buffer and not return read buffers until later.
+
+I agree that ideally you should return the buffer when you can, but this adds complexity to the application and is not typical of a blocking read interface. If the call to release the buffer was *optional*, I'd have no objection, but that puts some additional bookkeeping back on the library side.
+
+> Is GetAvailable() the best way to implement non-blocking i/o?
+It works in practice. Some systems including Windows do not implement this function very well, i.e. the reported available space comes in fits and starts. But at least you can find out if an IO call would block or fail. I'd like to avoid the extra system call when possible though.
+

Implementation Notes

+

Implementing blocking i/o will be quite simple for driver models where the underlying API is blocking-based, and quite difficult to do well under Windows where much fun will be had with Win32 synchronisation primitives.

+

Impact Analysis

+

This proposal would extend the functionality of PortAudio without requiring any changes to client code.

+

____________

+

Non-Interleaved Buffers

+

Status

+

This proposal is sufficiently well defined to be implemented. No objections have been raised.

+

Background

+

http://techweb.rfa.org/pipermail/portaudio/2001-October/000210.html

+

Some native APIs use non-interleaved buffers, particularly those that support N>2 channels. Additionally, many client applications use non-interleaved buffers internally. In order to avoid adding unnecessary overhead, PortAudio should support both interleaved and non-interleaved buffers on all platforms.

+

The current PortAudio/ASIO implementation works as follows : ASIO native buffers are non-interleaved and the de-interleaving, format conversion and copying the data into PortAudio interleaved buffers is done in one loop. But if PortAudio supported non-interleaved buffers then we could use efficient vector operations even for native buffer <==> port audio buffers transfers.

+

Proposal

+

A new sample format could be defined:

+
#define paNonInterleaved ((PaSampleFormat) (1<<32)) 
+

 

+

This could be used as a modifier flag to the buffer format fields of Pa_OpenStream(). When present, this flag would indicate that non-interleaved buffers would be passed to the callback. When not present, interleaved buffers would be used as is currently always the case. For example, the following code would open an interleaved stream:

+
+Pa_OpenStream(&stream,
+    paNoDevice,
+    0,
+    paFloat32
+    NULL,
+    Pa_GetDefaultOutputDeviceID(),
+    2,
+    paFloat32,
+    NULL,
+    SAMPLE_RATE,
+    FRAMES_PER_BUFFER,
+    0,
+    paClipOff,
+    patestCallback,
+    &data );
+

And the following code would open a non-interleaved stream:

+
+Pa_OpenStream(&stream,
+    paNoDevice,
+    0,
+    paFloat32|paNonInterleaved,
+    NULL,
+    Pa_GetDefaultOutputDeviceID(),
+    2,
+    paFloat32|paNonInterleaved,
+    NULL,
+    SAMPLE_RATE,
+    FRAMES_PER_BUFFER,
+    0,
+    paClipOff,
+    patestCallback,
+    &data );
+

In the user callback, the application would be passed a pointer to an array of buffers. The left and right buffers of a non-interleaved stream could be accessed as follows:

+
+    float *left = ((float **) inputBuffer)[0];
+    float *right = ((float **) inputBuffer)[1];
+

This new sample format could also be used to interrogate the native driver to see if it supports interleaved or non-interleaved buffers. This would be achieved by reading the nativeSampleFormats field of the PaDeviceInfo structure.

+

Impact Analysis

+

This proposal extends the functionality of PortAudio without any impact on existing client code. It will require new conversion functions and all existing PortAudio implementations will have to be modified to reference these new conversion functions.

+

____________

+

Support For Multiple Driver Models in a Single Build

+

Status

+

This proposal is currently being discussed. Its final form depends on a number of other unfinished proposals.

+

Dependencies

+

The API changes described in this proposal are independent of all other proposals. However, changes to the host error mechanism defined in Handling of Host-Specific Error Codes, and the addition of new API functions due to the Blocking Read/Write API proposal may effect the implementation of this proposal. Changes to the API defined by the Improve Device Format Query System and the Improve the Latency Setting Mechanism proposals will need to be multi-driver-model capable.

+

Background

+

As the number of supported driver models available on each platform grows (WMME, ASIO, and DirectSound under Windows for example) client applications need to be able to select between different driver models at run-time. At least four platforms supported by PortAudio have multiple native driver models. At present PortAudio allows clients to link in support for at most one driver model.

+

This proposal is based this email: http://techweb.rfa.org/pipermail/portaudio/2001-December/000308.html

+

Requirements

+

It will be necessary to supply clients with a method of displaying a textual description of the driver model for each PortAudio device.

+

Some PortAudio functions do not operate on PortAudioStreams, but rather they operate on or return the global state of the PortAudio library as a whole. If multiple driver-models were present, some of these functions would have different implementations, or would return different values depending on which the driver model they applied to. These functions include:

+
    int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
+    PaDeviceID Pa_GetDefaultInputDeviceID( void );
+    PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+    
+

Note that Pa_CountDevices() could also be interpreted as applying to a specific driver model.

+

PortAudio currently implements a per-driver-model extension mechanism via the inputDriverInfo and outputDriverInfo parameters to Pa_OpenStream(). For code to take advantage of driver-model-specific extensions when multiple driver models are present there needs to be a way to establish which (statically named) driver model is associated with each device. This is because driver-model-specific extensions should only be used in combination with devices supplied by that driver model.

+

PortAudio should present clients with all of the devices made available by each driver model. This means that some physical devices may be accessible though multiple driver models. Since it will not be possible to open a full duplex stream with input and output devices from different driver models, some clients may want to enumerate the available driver models and only display devices from one driver model at a time.

+

Introducing a new PortAudioDriverModel abstraction could fulfil the above requirements. At a minimum, this abstraction would need to have the following attributes:

+ +
    +
  • A textual description for display on user interfaces
  • +
  • Functions for querying default device ids and latency parameters for each driver model
  • +
  • A unique identifier published in portaudio.h for use in code which takes advantage of driver model specific extensions
+ +

Additionally, the following features could be present:

+ +
    +
  • A method for querying the default PortAudioDriverModel (perhaps the "best" driver model which has more than 0 devices available)
  • +
  • A method for enumerating 'currently available' PortAudioDriverModels. 'Currently available' could be interpreted as meaning the driver models linked into the current PortAudio implementation, or it could mean the driver models which currently have more than zero devices available.
  • +
  • A method of enumerating PortAudioDevices independently for each available PortAudioDriverModel
+ +

Proposal

+

This proposal consists of the 7 modifications to the PortAudio API listed below.

+

1. Define a new PaDriverModelTypeID enumeration, with fixed values for each driver model:

+
+/*
+    The PaDriverModelTypeID enumeration contains constants for uniquely 
+    Identifying each driver model supported by PortAudio. This type
+    is used in the PaDriverModelInfo structure below. Driver model type ids
+    are guaranteed to never change, thus allowing code to be written that 
+    conditionally uses driver model specific extensions.
+    New type ids will only be allocated when support for a new driver 
+    model reaches "public alpha" status, prior to that developers should
+    use the paInDevelopment type id.
+*/
+
+typedef enum {
+    paInDevelopment=0, /* use while developing support for a new driver model */
+    paWin32DirectSound=1,
+    paWin32MME=2,
+    paWin32ASIO=3,
+    paMacOSSoundManager=4,
+    paMacOSCoreAudio=5,
+    paMacOSASIO=6,
+    paOSS=7,
+    paALSA=8,
+    paIRIXAL=9,
+    paBeOS=10    
+}PaDriverModelTypeID;
+

2. Define a method for enumerating driver models:

+
+/*
+    Driver model enumeration mechanism.
+
+    Driver model ids range from 0 to Pa_CountDriverModels()-1.
+
+    The default driver model is the lowest common denominator
+    driver model on the current platform and is unlikely to provide
+    the best performance.
+*/
+
+typedef int PaDriverModelID;
+#define paDefaultDriverModel 0;
+
+struct{
+    int structVersion; 
+    PaDriverModelTypeID typeID; /* the well known unique identifier of this driver model */
+    const char *name; /* a textual description of the driver model for display on user interfaces */
+}PaDriverModelInfo;
+
+
+PaDriverModelID Pa_CountDriverModels();
+

3. Provide a method for retrieving information about a given driver model:

+
+/*
+    Pa_ GetDriverModelInfo () returns a pointer to an immutable 
+    PaDriverModelInfo structure referring to the device specified by driverModelID. 
+    If driverModelID is out of range the function returns NULL. The returned structure 
+    is owned by the PortAudio implementation and must not be manipulated or 
+    freed. The pointer is only guaranteed to be valid between calls 
+    to Pa_Initialize() and Pa_Terminate(). 
+*/ 
+
+const PaDriverModelInfo* Pa_GetDriverModelInfo( PaDriverModelID driverModelID );
+

4. Add a new field to PaDeviceInfo to identify the driver model type:

+
+struct{
+    ...
+    PaDriverModelID driverModel; /* note this is the run-time id */
+    ...
+}PaDeviceInfo;
+

This would enable the following two code fragments to be written.

+
+/* obtain the user-readable name of a device's driver model */
+Pa_GetDriverModelInfo( deviceInfo->driverModel )->name;
+
+/* implement special behavior for a specific driver model */
+if( Pa_GetDriverModelInfo( deviceInfo->driverModel )->typeID == paWin32MME ){
+    InitialiseMMESpecificDeviceInfo();
+}
+

5. Provide methods for finding per-driver model default devices and latency settings:

+
+PaDeviceID Pa_DriverModelDefaultInputDeviceID( PaDriverModelID driverModelID );
+PaDeviceID Pa_DriverModelDefaultOutputDeviceID( PaDriverModelID driverModelID );
+int Pa_DriverModelMinNumBuffers( PaDriverModelID driverModelID, int framesPerBuffer, double sampleRate );
+

6. Provide functions for enumerating devices on a per-driver-model basis. Note that this functionality is provided in addition to the current Pa_CountDevices() and Pa_GetDeviceInfo() functions:

+
+int Pa_DriverModelCountDevices( PaDriverModelID driverModelID );
+PaDeviceID Pa_DriverModelGetDeviceID( PaDriverModelID driverModelID, int perDriverModelIndex );
+

7. Re-implement the following existing functions to use the default driver model. This would be a backwards compatible change except for Pa_GetMinNumBuffers() which gains an extra parameter.

+
+PaDeviceID Pa_GetDefaultInputDeviceID( void ); /* returns the default device id for the default driver model */
+PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+
+int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate );
+

Note that Pa_GetMinNumBuffers() takes a device id, not a driver model id. This minimises the need for clients to be aware of the multiple driver model extensions.

+

Discussion

+

The main disadvantage of this proposal it that it may make the API seem more complex for new users.

+

There is concern that this proposal is too complex, and that the simpler solution of simply adding a driverModel string to the device info structure of each device would be sufficient. It is true that the simple solution would allow clients to duplicate the functionality of this proposal, provided driverModel strings were published and guaranteed not to change in the future. However, the bulk of the functionality included in this proposal will need to be implemented internally to facilitate multiple driver model support anyway. This proposal is based on the assumption that it is better to expose such functionality in the PortAudio API rather than require clients to reimplement what is already present internally.

+

There has been discussion about supporting "pluggable" driver models - the general idea is that a client application could link against PortAudio and PortAudio would load the available Driver Models at run-time using "PortAudio Driver Model Plugins." Some people consider this to be an overly complex solution, and no significant advantages over a monolithic PortAudio dll have been submitted yet. Some people would like PortAudio to always be able to be statically linked with multiple driver model support.

+

The overhead (both processor and memory) of the Multiple Driver Model support should be minimised on platforms which don't have multiple driver models (such as BeOS and some handheld devices.) Essentially this means that the functionality provided in the multiple driver model façade should be easy to duplicate.

+

Implementation Notes

+

The implementation will follow the methodology currently employed in PortMIDI described here: http://techweb.rfa.org/pipermail/portaudio/2001-December/000295.html

+

An implementation of the driver model neutral "Façade" of this proposal exists here:

+

pa_drivermodel.c.txt

+

pa_drivermodel.h.txt

+

This proposal will involve the changes described below. Note that the string <DM> will be replaced with a driver model tag for each implementation.

+

Each driver model will have it's own Initialize function which PortAudio will call in response to client calls to Pa_Initialize and Pa_Terminate respectively. This will be the only identifier each driver model implementation will be required to expose.

+
PaError Pa<DM>_MultiDriverInitialize( PaDriverModelImplementation **impl );
+

PaDriverModelImplementation is an internal data structure containing a set of function pointers for globally relevant functions: (function pointer type declarations omitted for simplicity:)

+
struct{
+    fptr terminate; /* takes the PaDriverModelImplementation* returned by initialize */
+    fptr getDriverModelInfo;
+    fptr getHostError;
+    fptr getHostErrorText;
+    fptr countDevices;
+    fptr getDefaultInputDeviceID;
+    fptr getDefaultOutputDeviceID;
+    fptr getDeviceInfo;
+    fptr openStream;
+    fptr getMinNumBuffers;
+} PaDriverModelImplementation;
+

The function pointers in PaDriverModelImplementation will point to the corresponding functions in current PortAudio implementations. The new multiple driver model support code will take care of mapping per-driver model device ids onto a single homogenous driver id range. A significant advantage of this scheme is that it will require very little change to existing PortAudio implementations.

+

A new PaStreamImplementation internal data structure will be defined to contain function pointers to implementations of the stream functions for each driver model. This structure will be placed at the head of implementation-specific data structures returned as PortAudioStream* in current implementations.

+
struct{
+    unsigned long magic;
+    fptr close;
+    fptr start;
+    fptr stop;
+    fptr abort;
+    fptr active;
+    fptr time;
+    fptr cpuLoad;
+} PaStreamImplementation;
+

Magic contains a unique bit pattern which should be set by implementations when a stream is opened, and cleared when it is closed. This technique will allow implementations to perform some degree of validation on PortAudioStream* passed to PortAudio.

+

Impact Analysis

+

This proposal will significantly improve the utility of PortAudio by allowing clients to support multiple driver models in a single executable.

+

The only required change for existing clients will to insert an extra deviceID parameter into calls to Pa_GetMinNumBuffers().

+

Since multiple driver models may return devices with the same names, a minimum requirement for clients who want to be "multiple driver model aware" will be to ensure that the appropriate driver model name is displayed alongside device names in the user interface.

+

____________

+

Driver Model Specific Pa_OpenStream() Parameters

+

Status

+

This proposal is essentially complete, but is pending the final definition of PaDriverModelTypeID (see below.)

+

Dependencies

+

If the PaDriverModelSpecificStreamInfo structure defined in this proposal includes a PaDriverModelTypeID driver model identifier, then this proposal depends on the Support for Multiple Driver Models in a Single PortAudio Build proposal to define the form of the identifier.

+

Background

+

Pa_OpenStream has always had the inputDriverInfo and outputDriverInfo parameters, which were defined to support passing driver-model specific information to PortAudio implementations. Currently these parameters are defined as void* and are not used by any implementation. Two uses of inputDriverInfo and outputDriverInfo are planned for the near future: passing device names to OSS drivers, and passing additional device ids for opening multichannel soundcards under MME.

+

Proposal

+

The following structure could be defined and be placed at the head of all data structures passed to the inputDriverInfo and outputDriverInfo parameters of Pa_OpenStream:

+
struct{
+    unsigned long size;    /* size of whole structure including this header */
+    PaDriverModelTypeID driverModel; /* driver model for which this data is intended */
+    unsigned long version; /* structure version */
+}PaDriverModelSpecificStreamInfo;
+

The following driver model specific extensions should be placed in separate header files rather than being placed in portaudio.h

+

___

+

The following structure is proposed for passing device names to the OSS implementation:

+
struct{
+    PaDriverModelSpecificStreamInfo header;
+    char *deviceName;
+}PaOSSSpecificStreamInfo;
+

A pointer to this structure could be passed to Pa_OpenStream() to request that a device other than the default dsp device be opened. This structure could be used for opening input and/or output devices.

+

___

+

The following structure is proposed for passing multiple interleaved device ids to the MME implementation in order to open a multichannel stream with some soundcards that support multichannel operation via multiple stereo (or other number of channels) interleaved devices. When this structure is passed, the MME implementation would ignore the deviceId parameters passed directly to Pa_OpenStream(), however it would not ignore the channelCount parameters.

+

#define paWMMEPassMultipleInterleavedBuffers 0x01 /* a flag */

+
struct{
+    PaDriverModelSpecificStreamInfo header;
+    int *deviceIdsAndChannelCounts; /* interleaved deviceIds and channelCounts */
+    int deviceCount;
+    int flags;
+}PaMMESpecificStreamInfo;
+

The deviceIdsAndChannelCounts field points to an array of ints containing multiple {deviceId, channelCount} pairs. The number of integer elements in the array must be two times the value of the deviceCount field. Specified deviceIds must have a driver model type of Windows MME. Currently only one flag is defined: paWMMEPassMultipleInterleavedBuffers, this can be used to request that the raw, multiple interleaved buffers be passed to the callback.

+

Discussion

+

The type of the inputDriverInfo and outputDriverInfo parameters could be changed to PaDriverModelSpecificStreamInfo* however this may cause more trouble that it's worth.

+

The PaMMESpecificStreamInfo functionality may require the common buffer conversion functions defined in the Revise Internal Host API proposal to support (multiple interleave <==> unified interleave) and (multiple interleave <==> non-interleaved) conversions.

+

Impact Analysis

+

This proposal provides access to new platform-specific extensions. No existing client code will be modified. Only implementations that implement the extensions will be effected.

+

____________

+

Handling of Host-Specific Error Codes

+

Status

+

This proposal is sufficiently well defined to be implemented immediately. However, the possibility of extending the scope of this proposal is being discussed in this thread: http://techweb.rfa.org/pipermail/portaudio/2002-January/000358.html

+

Background

+

Currently the PaHostError error code is used to notify clients that a platform-specific error condition occurred. This is considered ambiguous and difficult to work with.

+

Proposal

+

PortAudio should seek to avoid returning ambiguous paHostError error codes, and instead translate to portable PortAudio error codes instead. In the case of the pa_win_mme implementation this means translating the following MME error codes:

+

MMSYSERR_ALLOCATED to paDeviceBusy (new)
+MMSYSERR_BADDEVICEID to paInvalidDeviceId (already defined)
+MMSYSERR_NODRIVER to paDriverMissing (new)
+MMSYSERR_NOMEM to paInsufficientMemory (already defined)
+WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined)

+

Discussion

+

It is suggested that all implementations should be audited for their use of PaHostError.

+

There was some concern about polluting the PortAudio error code namespace with platform-specific error codes, and of the potential overhead of including platform specific error strings on other platforms. Another suggestion has been to add a Pa_GetHostErrorText() function.

+

If all error codes are mapped to PortAudio error codes do we need a PaHostError code and the Pa_GetHostErrorCode() function?

+

A suggestion has been made to extend Pa_GetErrorText() so that it retrieved driver model specific error strings when a host error occurs.

+

Impact Analysis

+

This proposal improves the quality of PortAudio diagnostics. Client code that depends on paHostError code to flag certain conditions may be effected.

+

____________

+

Rename Pa_GetCPULoad() to Pa_StreamCPULoad()

+

Status

+

Proposal is sufficiently well defined to be implemented. No objections have been raised.

+

Background

+

PortAudio functions that return global information typically have names of the form Pa_Get*() (eg. Pa_GetDeviceInfo). Almost all functions operating on PortAudio streams conform to the following implicit naming convention: Pa_*Stream( stream ) performs an action on a stream (eg Pa_StartStream() ) and Pa_Stream*( stream ) returns a stream attribute (eg. Pa_StreamTime() ). The only exception to this convention is the confusingly named Pa_GetCPULoad() which actually returns the CPU consumption of a particular stream's callback.

+

Proposal

+

Rename PaGetCPULoad() to Pa_StreamCPULoad() in order to conform to established naming conventions.

+

Impact Analysis

+

This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which call Pa_GetCPULoad() will need to alter their code by renaming the function call.

+

____________

+

Coding Style Guidelines

+

Status

+

This proposal is under construction. Further suggestions and comments would be extremely welcome.

+

Background

+

Since the PortAudio code is commonly edited on many different platforms using different editors it has been suggested that some conventions be adopted to improve readability and consistency. The general opinion is that the definition of such conventions, and their enforcement shouldn't be too extreme. There are also a number of unspoken implementation standards that could be usefully written down. This proposal consists of a list of mechanical formatting conventions, and a list of "quality of implementation" conventions. When completed this proposal will packaged with the distribution and placed on the web site as "Coding Style Guidelines for PortAudio Implementors."

+

Proposal

+

The following formatting conventions should be adhered to in all PortAudio code:

+ +
    +
  • TABs should not be used in .c and .h files; instead 4 spaces should be used. Makefiles should continue to use TABs since this is required by Make
  • +
  • Adopt a consistent set of rules for placement of braces (see note regarding Astyle below)
  • +
  • Adopt a consistent policy for line-end characters. This could be 'use CR on Mac, CRLF on Windows and LF on Unix' or it could be 'use Unix style new-lines in all source files.
+ +

AStyle ( http://astyle.sourceforge.net/ ) has been proposed as helpful tool for cleaning code, however we haven't yet decided whether to use it on an ongoing basis. Once our style guidelines have been established it is expected that contributors of each implementation will take responsibility for keeping their code clean, as an automated tool applied by someone unfamiliar with the code will probably just mess things up.

+

In addition to the formatting conventions noted above, the following "quality of implementation" coding guidelines are being proposed to establish a quality baseline for our implementations:

+ +
    +
  • All code should be written in C++-compatible plain ANSI-C (i.e. no // comments). The following guideline has been proposed: should compile silently with both "gcc -ansi -pedantic -Wall" and "g++ -ansi -pedantic -Wall"
  • +
  • Think of PortAudio as a heavyweight library rather than a lightweight wrapper. Always code defensively. Efficiency is important where it matters (eg in real-time callbacks) but safety is important everywhere.
  • +
  • All parameters passed to PortAudio by the user should be validated, and error codes returned where necessary. All reasonable efforts should be made to minimise the risk of a crash resulting from passing incorrect parameters to PortAudio.
  • +
  • Error handling should be complete. Every host function that can return an error condition should have its status checked. PortAudio may attempt to recover from errors, but generally error codes should be returned to the client.
  • +
  • In almost all cases, a PortAudio error code should be preferred to returning PaHostError. If a new PortAudio error code is needed it should be discussed with the maintainer to coordinate updating port_audio.h
  • +
  • PortAudio code should not cause resource leaks. After Pa_Terminate() is called, implementations should guarantee that all dynamically allocated resources have been freed.
  • +
  • The definition of the PortAudio API should minimise "implementation defined behaviour". For example, calling functions such as Pa_Initialize() after PortAudio is initialised, or Pa_Terminate() after PortAudio has been terminated should have well defined behaviour. (In this example, both calls should be safe and simply return an error code.)
  • +
  • Minimise dependence on ANSI C runtime on platforms where it would have to be loaded separately (eg on Win32 prefer Win32 API functions such as GlobalAlloc() to ANSI C functions such as malloc().)
+ +

It has been suggested that we make an effort to minimise the use of global and static data in PortAudio implementations. Another related goal is to reduce name pollution in the global scope. Some possible guidelines in this regard are:

+ +
    +
  • Implementations should avoid exporting any symbols except where absolutely necessary. Specifically, global data must be declared statically. We will need a naming convention for non-public global symbols, such as internal functions defined in one module and used in another.
  • +
  • Implementations should minimise their use of static data.
+ +

Discussion

+

There will always be time to improve these guidelines, however we are making a concerted effort to document some standards before the next round of changes are implemented.

+

Impact Analysis

+

This proposal will require all existing code to be reviewed and possibly revised. This is not expected to be a "big-bang" operation. Rather it is envisaged that this will be a long term, ongoing process aimed at improving the quality of the PortAudio codebase.

+

____________

+

Additional Pa_Terminate() Behaviour

+

Status

+

This proposal is sufficiently well defined to be implemented.

+

Background

+

Some driver models (eg ASIO, MME and DirectSound under Windows NT) can require a reboot to free devices when they are not closed properly (due to a program not calling Pa_Close() either in error, or due to a crash.) As a quality of implementation issue PortAudio should seek to avoid such circumstances.

+

Proposal

+

The definition of Pa_Terminate() should be extended as follows:

+
/*
+    Pa_Terminate() is the library termination function - call this after 
+    using the library. This function deallocates all resources allocated 
+    by PortAudio since it was initializied using Pa_Initialize(). Any open 
+    PortAudioStreams are closed.
+
+    Pa_Terminate() MUST be called before exiting a program which 
+    uses PortAudio. Failure to do so may result in serious resource 
+    leaks, such as audio devices not being available until the next reboot.
+*/
+PaError Pa_Terminate( void );
+

Implementation Notes

+

One possible implementation strategy would be to add a "next" member to the internal stream data structure thus making it a linked list node, which could be linked into a list of all open streams.

+

Discussion

+

Some concerns have been raised about the overhead involved in PortAudio having to keep track of which streams are currently open.

+

There has been some discussion about the behaviour of nesting multiple calls to Pa_Initialize() and Pa_Terminate() - there is no intention of changing the current behaviour, which is that PortAudio has two states: "Initialized" and "Uninitialized" - in the Initialized state, Pa_Initialize() does nothing and returns an error, in the Uninitialized state Pa_Terminate() does nothing and returns an error.

+

Impact Analysis

+

This proposal changes the termination behaviour of PortAudio to reduce the likelihood of resource leaks.

+

On Windows, the new Pa_Terminate() behaviour would allow users who want full protection against device leakage to install a global Win32 exception handler that calls Pa_Terminate() before exiting when a crash occurs. Similar techniques (using SIGNAL handlers perhaps?) may be possible on other platforms where necessary.

+

____________

+

Revise Internal Host API

+

Status

+

This proposal is under construction. Ideally, someone should go through all of the existing implementations and identify code that could be factored into a common library (parameter validation code for example.)

+

Dependencies

+

This proposal is dependent on the Support for Multiple Driver Models in a Single PortAudio Build proposal, and the Non-Interleaved Buffers proposal. The proposed conversion functions may be dependent on the MME multichannel via stereo pairs extension which is part of the Driver Model Specific Pa_OpenStream() Parameters proposal.

+

Background

+

PortAudio defines a set of helper functions that all implementations share. It is envisaged that these internal functions will need to be revised in response to the changes proposed in this document. It would also be beneficial to take this opportunity to refactor any other common code fragments that could be shared by multiple implementations.

+

A refactoring of the buffer data conversion functions was proposed here: http://techweb.rfa.org/pipermail/portaudio/2001-November/000244.html However the proposal below is not quite the same. A significant benefit of formally specifying the interface to the buffer conversion functions is that it would facilitate the creation of optimised assembly language versions for different platforms.

+

Proposal

+

A common set of buffer conversion functions should be defined and shared by all implementations. The buffer conversion functions should handle all permutations of:

+ +
    +
  • Sample format
  • +
  • Channels
  • +
  • Interleave / Non-interleave
  • +
  • Endianness
  • +
  • Channel compensation
+ +

"Channel-compensation" is necessary when certain devices require a higher number of channels than the user requests. With the Midiman Delta1010, for example, the device always needs to be fed 10 channels of output and you must read 12 channels of input (at least under ALSA without the "plug" interface).

+

The conversion functions could look something like:

+
void ConversionFunction_DestType_DestInterleave_SrcType_SrcInterleave_ ( void *dest, int destChannels, void *src, int srcChannels, int frames );
+

The dest and src parameters have the same format as those supplied to the PortAudio client callback.

+

Rather than have each implementation call these conversion functions directly, a 'factory function' could be implemented that returnes a pointer to a conversion function based on parameters specifying the format of the source and destination buffers. This factory function could be called as needed when a stream is opened. The conversion functions could then be made static and hidden from the rest of PortAudio. The 'factory function' could have the following form:

+
enum PaEndiannes { paBigEndian, paSmallEndian, paHostEndian };
+
+PaBufferConversionFunction* Pa_GetBufferConversionFunction( 
+    PaSampleFormat destFormat, int destChannels, PaEndianness destEndianness,
+    PaSampleFormat srcFormat, int srcChannels, PaEndianness srcEndianness );
+

Note that the interleave/deinterleave status is encoded in the destFormat and srcFormat parameters. paHostEndian is used to represent the endianness of the current platform since some driver models (eg ASIO) allow the driver to use samples in a different endianness from the host endianness. Another alternative is to encode sample endianness in PaSampleFormat - this would allow clients to write sample data of either endianness to PortAudio (e.g. soundfile playback direct from file) and benefit from PortAudio's byte swapping code.

+

The redundant use of channel parameters in both the conversion functions and the factory function is intentional and would allow channel-optimised conversion functions to be supplied for common cases such as 16-bit stereo.

+

Discussion

+

This proposal currently only addresses buffer conversion functions, but we would like to identify other common code fragments which could be placed in the shared PortAudio library.

+

This proposal has not yet addressed the fact that the conversion functions also need to handle clipping and dithering.

+

It is not clear whether additional conversion functions will be needed to accommodate the MME interleaved stereo pairs for multichannel devices proposal.

+

It hasn't been established whether PortAudio will be extended to support all PaSampleFormats on all devices.

+

It isn't clear whether paCustomFormat is viable under this proposal, or how it would be accommodated.

+

When the client requested format and the host format are different a temporary buffer may be required to hold the converted data. However, in general PortAudio should aim to convert data in-place. Functions may be needed to establish when temporary buffers are needed, and to allocate them.

+

Due to a mismatch between the API buffer size and the PortAudio callback buffer size some driver models require PortAudio to shuffle data among multiple buffers in order to fulfil client requests - this has not yet been considered within the current proposal.

+

Memory allocation should probably be handled with platform specific functions such as Win32 GlobalAlloc() rather than using malloc()

+

Impact Analysis

+

This proposal only effects PortAudio implementors. Increasing the utility of shared code will improve the quality of all PortAudio implementations in terms of speed, size, and robustness. It should also reduce the effort involved in porting PortAudio to a new driver model.

+

____________

+ diff --git a/docs/releases.html b/docs/releases.html new file mode 100644 index 0000000..4a7efad --- /dev/null +++ b/docs/releases.html @@ -0,0 +1,252 @@ + + + + + + + + + PortAudio Implementations for DirectSound + + +  +
+ + + +
+
+

+PortAudio - Release Notes

+
+ +

Link to PortAudio Home Page +

+V18 - unreleased

+ +
Ran most of the code through AStyle +to cleanup ragged indentation caused by using different editors. Used this +command: +
astyle --style=ansi -c -o --convert-tabs --indent-preprocessor +*.c
+ +
WMME +
    +
  • +Fixed bug that caused TIMEOUT in Pa_StopStream(). Added check for past_StopSoon() +in Pa_TimeSlice(). Thanks Julien Maillard.
  • +
+Unix OSS +
    +
  • +Use high real-time priority if app is running with root priveledges. Lowers +latency.
  • +
+
+ +

+V17 - 10/15/01

+ +
Unix OSS +
    +
  • +Set num channels back to two after device query for ALSA. This fixed a +bug in V16 that sometimes caused a failure when querying for the sample +rates. Thanks Stweart Greenhill.
  • +
+
+ +
+

+Macintosh Sound Manager

+ +
    +
  • +Use NewSndCallBackUPP() for CARBON compatibility.
  • +
+
+ +

+V16 - 9/27/01

+ +
Added Alpha implementations for ASIO, SGI, and BeOS! +
  +
  • +CPULoad is now calculated based on the time spent to generate a known number +of frames. This is more accurate than a simple percentage of real-time. +Implemented in pa_unix_oss, pa_win_wmme and pa_win_ds.
  • + +
  • +Fix dither and shift for recording PaUInt8 format data.
  • + +
  • +Added "patest_maxsines.c" which tests Pa_GetCPULoad().
  • +
    + +
    +

    +Windows WMME

    + +
      +
    • +sDevicePtrs now allocated using GlobalAlloc(). This prevents a +crash in Pa_Terminate() on Win2000. Thanks Mike Berry for finding this. +Thanks Mike Berry.
    • + +
    • +Pass process instead of thread to SetPriorityClass(). This fixes +a bug that caused the priority to not be increased. Thanks to Alberto di +Bene for spotting this.
    • +
    + +

    +Windows DirectSound

    + +
      +
    • +Casts for compiling with __MWERKS__ CodeWarrior.
    • +
    + +

    +UNIX OSS

    + +
      +
    • +Derived from Linux OSS implementation.
    • + +
    • +Numerous patches from Heiko Purnhagen, Stephen Brandon, etc.
    • + +
    • +Improved query mechanism which often bailed out unnecessarily.
    • + +
    • +Removed sNumDevices and potential related bugs,
    • + +
    • +Use getenv("PA_MIN_LATENCY_MSEC") in code to set desired latency. +User can set by entering:
    • + +
          export PA_MIN_LATENCY_MSEC=40
    + +

    +Macintosh Sound Manager

    + +
      +
    • +Pass unused event to WaitNextEvent instead of NULL to prevent Mac OSX crash. +Thanks Dominic Mazzoni.
    • + +
    • +Use requested number of input channels.
    • + +
       
    +
    + +

    +V15 - 5/29/01

    + +
    +
      +
    • +New Linux OSS Beta
    • +
    + +

    +Windows WMME

    + +
      +
    • + sDevicePtrs now allocated based on sizeof(pointer). Was allocating +too much space.
    • + +
    • + Check for excessive numbers of channels. Some drivers reported bogus +numbers.
    • + +
    • +Apply Mike Berry's changes for CodeWarrior on PC including condition including +of memory.h, and explicit typecasting on memory allocation.
    • +
    + +

    +Macintosh Sound Manager

    + +
      +
    • +ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID.
    • + +
    • +Device Scan was crashing for anything other than siBadSoundInDevice, but +some Macs may return other errors! Caused failure to init on some G4s under +OS9.
    • + +
    • +Fix TIMEOUT in record mode.
    • + +
    • +Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON
    • +
    +
    + +

    +V14 - 2/6/01

    + +
    +
      +
    • +Added implementation for Windows MultiMedia Extensions (WMME) by Ross and +Phil
    • + +
    • +Changed Pa_StopStream() so that it waits for the buffers to drain.
    • + +
    • +Added Pa_AbortStream() that stops immediately without waiting.
    • + +
    • +Added new test: patest_stop.c to test above two mods.
    • + +
    • +Fixed Pa_StreamTime() so that it returns current play position instead +of the write position. Added "patest_sync.c" to demo audio/video sync.
    • + +
    • +Improved stability of Macintosh implementation. Added timeouts to prevent +hangs.
    • + +
    • +Added Pa_GetSampleSize( PaSampleFormat format );
    • + +
    • +Changes some "int"s to "long"s so that PA works properly on Macintosh which +often compiles using 16 bit ints.
    • + +
    • +Added Implementation Guide
    • +
    +
    + +

    +V12 - 1/9/01

    + +
    +
      +
    • +Mac now scans for and queries all devices. But it does not yet support +selecting any other than the default device.
    • + +
    • +Blocking I/O calls renamed to separate them from the PortAudio API.
    • + +
    • +Cleaned up indentation problems with tabs versus spaces.
    • + +
    • +Now attempts to correct bogus sample rate info returned from DirectSound +device queries.
    • +
    +
    + + + From 5186638b3f6915977733acb109dcc1af99da9f44 Mon Sep 17 00:00:00 2001 From: philburk Date: Mon, 6 May 2002 16:55:25 +0000 Subject: [PATCH 077/814] More changes by Ross --- docs/proposals.html | 168 ++++++++++++++++++++++++++++++-------------- 1 file changed, 116 insertions(+), 52 deletions(-) diff --git a/docs/proposals.html b/docs/proposals.html index 5bebc65..f8efcff 100644 --- a/docs/proposals.html +++ b/docs/proposals.html @@ -21,7 +21,9 @@ name=KeyWords>

    PortAudio Home Page

    -

    Updated: January 7, 2002

    + +

    Updated: January 11, 2002

    +

    Introduction

    This document describes modifications to the PortAudio API currently being considered by the developer community. It is intended to capture the current state of discussions. The authors are the various members of the PortAudio community and are too numerous to mention. Please refer to the mailing list archives to see who said what.

    We are still at the design stage with all of these proposals - if you think something is missing, could be improved, or would just like to comment please do so on the PortAudio mailing list.

      http://techweb.rfa.org/mailman/listinfo/portaudio

    @@ -30,19 +32,25 @@ name=KeyWords> -

    The proposals above which are marked with a * are under construction, those marked with |C| are essentially complete but require approval or comment before they are considered complete. The remaining proposals are essentially complete and will be implemented as-is unless significant objections are raised.

    -

    ____________

    +

    The proposals above which are marked with a * are under construction, those marked with |C| are essentially complete but require community approval or comment before they are considered complete. The remaining proposals are essentially complete and will be implemented as-is unless significant objections are raised.

    +

    Status

    +

    This document describes proposals that range in complexity from clarifications of existing API functionality, through to renaming API functions for consistency, through to significant feature additions. Due to the interdependency of many of the proposed changes, we plan to introduce all API changes simultaneously as part of release 19.

    +

    The developer community is in the process of reviewing all proposals. Most proposals are defined in sufficient detail to implement, however some completed proposals are dependent on proposals that are still under construction. Of the remaining unfinished proposals, only Improve Device Format Query System, Improve Latency Mechanisms, Allow Callbacks to Accept Variable framesPerBuffer, and Handling of Host-Specific Error Codes require significant attention. Both the Coding Style Guidelines and Revise Internal Host API proposals only effect implementors and do not effect the API definition itself. Refinement of these proposals is desirable but not critical to the development of release 19. Interested readers are advised to consult the Dependencies section of each proposal for more detailed information.

    +

    Client Impact

    +

    Some of the proposed changes will break existing client code. Usually these breakages involve renaming of constant identifiers or function calls. In a small number of cases additional parameters will be added to existing API functions. Concerned readers are advised to consult the Impact Analysis section of each proposal for further details.

    +

    ____________

    PortAudioCallback Underflow/Overflow Handling

    Status

    This proposal is sufficiently well defined to be implemented

    @@ -87,12 +95,27 @@ These bits may be set in the statusFlags parameter.

    It has been noted that the current method (Pa_GetDeviceInfo()) of querying devices for supported sample formats, channels and sample rates is weak. It does not cleanly differentiate between 'PortAudio supported' formats and 'native' formats, and it is incapable of representing formats where the parameters are interdependent (eg where full duplex is only supported for certain sample rates.) We have also found that a static structure is not a good match for many driver models where format discovery is performed by polling the driver. Even if a sound card supports arbitrary sample rates, the driver model may only allow a client to poll to see whether a rate is available rather than providing the available rate ranges.

    It has been noted that most (platform specific) audio APIs do a pretty bad job of allowing for device capability querying. Even the better APIs (ALSA is perhaps one) don't necessarily provide accurate information. This proposal should seek to maximise the amount of information that can be extracted from existing APIs while remaining expressive enough to take full advantage of APIs with more advanced capability querying systems should they become available in the future.

    Proposal

    -

    Use PaDeviceInfo only for representing information that can be expressed without polling the driver multiple times, or only check for "standard" formats, or leave it unchanged, or do away with it completely.

    +

    A number of options are being considered with regard to supplying clients with format information:

    +

    Use PaDeviceInfo only for representing information that can be expressed without polling the driver multiple times, or only check for "standard" formats, or leave it unchanged.

    And/Or

    -

    We could do things the way MME does: if Pa_OpenStream() is called with a NULL stream parameter then the stream isn't opened, but it is checked to see if the device supports the specified format - if the format is supported then paNoError would be returned, otherwise an error would be returned.

    -

    And/Or

    -

    Add an IsFormatSupported() function:

    -
    Pa_IsFormatSupported( deviceId, inputDevice, numInputChannels, inputSampleFormat, inputDriverInfo, outputDevice, numOutputChannels, outputSampleFormat, outputDriverInfo, sampleRate );
    +

    Add a Pa_IsFormatSupported() function:

    +
    Pa_IsFormatSupported( PaDeviceID inputDevice, 
    +                        int numInputChannels, 
    +                        PaSampleFormat inputSampleFormat,
    +                        void *inputDriverInfo, 
    +                        PaDeviceID outputDevice, 
    +                        int numOutputChannels, 
    +                        PaSampleFormat outputSampleFormat, 
    +                        void *outputDriverInfo, 
    +                        double sampleRate );
    +

    Discussion

    +

    At present it seems desirable to retain Pa_GetDeviceInfo() and the PaDeviceInfo structure. At a minimum PaDeviceInfo needs to contain name and driver model type code fields:

    +
    typedef struct{
    +    int structVersion; 
    +    const char *name;
    +    PaDriverModelTypeCode driverModel;
    +} PaDeviceInfo;
    +

    It was suggested that we could do things the way MME does: if Pa_OpenStream() is called with a NULL stream parameter then the stream isn't opened, but it is checked to see if the device supports the specified format - if the format is supported then paNoError would be returned, otherwise an error code would be returned. However, this has been ruled to be unsatisfactory, since querying for supported formats is really a different function from opening a stream.

    Impact Analysis

    This proposal will provide clients with more expressive methods for querying device capabilities, which should improve the utility of PortAudio. It is not yet clear what the full impact of this proposal will be.

    ____________

    @@ -105,49 +128,84 @@ These bits may be set in the statusFlags parameter.

    See this thread: http://techweb.rfa.org/pipermail/portaudio/2001-October/000196.html

    Proposal

    The numBuffers parameter for Pa_OpenStream() could accept the following values in addition to the normal N>0 values.  Use PA_LATENCY_LOW for interactive performance, when response time is critical.  Use PA_LATENCY_HIGH when playing sound files or other non-interactive uses, when glitch free operation is more critical.

    -

    #define PA_LATENCY_WHATEVER   (0) /* or _NO_OPINION or? */
    -#define PA_LATENCY_LOW       (-1)  /* For interactive performance. */
    -#define PA_LATENCY_HIGH      (-2)  /* For playing sound files. */

    +
    +#define PA_LATENCY_WHATEVER   (0) /* or _NO_OPINION or? */
    +#define PA_LATENCY_LOW       (-1)  /* For interactive performance. */
    +#define PA_LATENCY_HIGH      (-2)  /* For playing sound files. */

    Currently, when numBuffers>0, Pa_OpenStream will constrain the actual numBuffers so that the latency is within a valid range determined by the driver, or an environment variables such as PA_MIN_LATENCY_MSEC. Propose changing the behaviour so that the requested value is honoured as much as possible. This will allow the user to override the minimum if they know their system can handle it. This might be used, for example on patched Linux kernels. By doing this we simplify the implementations and eliminate the need for adding a Pa_SetMinimumLatency() function.

    -

    /* Negative return values are (double) paError */
    -double Pa_GetMinimumLatency( int deviceId, double frameRate );
    -double Pa_GetPreferredLatency( int deviceId, double frameRate );
    -double Pa_GetMaximumLatency( int deviceId, double frameRate );

    -

    /* This would only be valid after Pa_OpenStream() */
    -double Pa_GetActualLatency( int deviceId, double frameRate );

    +
    +/* Negative return values are (double) paError */
    +double Pa_GetMinimumLatency( int deviceId, double frameRate );
    +double Pa_GetPreferredLatency( int deviceId, double frameRate );
    +double Pa_GetMaximumLatency( int deviceId, double frameRate );
    +/* the following would operate directly on streams */
    +double Pa_StreamInputLatency( PortAudioStream *stream );
    +double Pa_StreamOutputLatency(PortAudioStream *stream );

    Discussion

    This proposal does not yet address the question of whether there needs to be separate numInputBuffers and numOutputBuffers parameters for optimal latency specification.

    ____________

    -

    Blocking Read/Write API

    +

    Allow Callbacks to Accept Variable framesPerBuffer

    Status

    -

    This proposal is waiting to be written up (assigned to Roger Dannenberg.)

    +

    This proposal is under construction.

    +

    Background
    +
    +Some devices prefer, or even require, a particular value for framesPerBuffer. Some applications also prefer a particular buffer size because they may, for example, be doing FFTs. If possible, an integral number of application buffers can be fit into a device buffer. If an integral number of application buffers cannot be fit into an application buffer then some system for adapting between them is required. Stephane Letz implemented a block adapter for the ASIO driver that could perhaps be made part of a utility library for PortAudio.
    +
    +Adapting between different block size, unfortunately, involves extra memory movement and should be avoided. One way to avoid this is to allow an application to say "I can handle any value for framesPerBuffer". An example would be a simple algorithm like the one in "pa_tests/pa_fuzz.c". Its callback function could easily work with any value for FramesPerBuffer.
    +
    +Proposal
    +
    +Pa_OpenStream() should be able to accept a zero value for framesPerBuffer. When framesPerBuffer is zero, the implementation can choose any value that it thinks will work best given the other constraints. That value will be passed to the user callback.
    +
    +To make the code more obvious, this constant could be used:
    +
    +#define paFramesPerBufferUnspecified (0)
    +
    +In order to find out what value the implementation chose, and also to help the application determine the actual latency, the following calls could be added:
    +
    +int Pa_GetFramesPerBuffer( PortAudioStream* stream );
    +int Pa_GetNumOutputBuffers( PortAudioStream* stream );
    +int Pa_GetNumInputBuffers( PortAudioStream* stream );

    +

    +

    ____________

    +

    Blocking Read/Write API

    +

    Status

    +

    This proposal is open for comment.

    Background

    -

    Many PortAudio users have requested a blocking read/write API which will be supported in addition to the current callback based API. A blocking Read/Write API would allow a more natural style of multi-threaded programming, and facilitate single-threaded reactive applications, while insulating clients from platform-specific thread synchronisation facilities. A blocking read/write API would also be useful when binding PortAudio to languages that don't easily support callbacks such as Python, Java, Lisp and Smalltalk. However in this case it has been noted that a blocking API is not sufficient - the host language also needs to support native threads to interact efficiently with blocking.

    +

    Many PortAudio users have requested a blocking read()/write() API that will be supported in addition to the current callback based API. A blocking Read/Write API would allow a more natural style of multi-threaded programming, and facilitate single-threaded reactive applications, while insulating clients from platform-specific thread synchronisation facilities.

    +

    A blocking read/write API would also be useful when binding PortAudio to languages that don't easily support callbacks such as Python, Java, Lisp and Smalltalk. However in this case it has been noted that a blocking API is not sufficient - the host language also needs to support native threads to interact efficiently with blocking. Dannenberg observes that native thread support cannot be added without major redesign (based on a study of Python and Squeak), but given blocking calls, there are several ways to structure programs using non-native threads.

    Adding a blocking Read/Write interface to PortAudio has been discussed on a number of occasions, including the following threads:

    http://techweb.rfa.org/pipermail/portaudio/2001-August/000063.html a long thread about blocking calls.

    http://techweb.rfa.org/pipermail/portaudio/2001-August/000137.html this is Roger Dannenberg's proposal and a subsequent discussion

    http://techweb.rfa.org/pipermail/portaudio/2001-August/000144.html is a thread discussing using blocking APIs with other languages

    Proposal

    -

    This proposal needs further documentation, but some details are provided below.

    -

    If a NULL callback parameter is passed to Pa_OpenStream() then the stream is opened in blocking mode. This enables users to call Pa_WriteStream() and Pa_ReadStream() to read and write sample data.

    -

    For a while there was a talk about only requiring implementations to implement blocking calls and that callbacks would always be implemented on top of blocking. The current direction is that this decision will be made independently for each driver-model.

    -

    There needs to be a way to call the read and write functions without them blocking or to determine in advance how many samples can be read or written without blocking. One proposal to avoid blocking in environments without native threads is to ask PortAudio how many frames are available, and then to sleep() (using non-native thread management) until the next buffer boundary.

    -

    Roger Dannenberg wrote the following email that is included here because it didn't seem to make it into the mailing list archive:

    -
    > It would be nice if the buffer could be returned to PortAudio as soon
    -> as the client had finished with it. For example, in the MME
    -> implementation this would allow the buffer to be requeued with
    -> the driver sooner.
    -
    -My model is that, in general, you should target the worst case where audio processing takes most of the CPU time. In that case, the app finishes reading and writing buffers just before it's time to start the next buffer. In that case, there's little to gain by trying to return buffers early. Alternatively, if CPU time is negligible, wouldn't returning the buffer immediately (to MME) effectively increase the buffer count by one? In other words, you could just allocate one extra buffer and not return read buffers until later.
    -
    -I agree that ideally you should return the buffer when you can, but this adds complexity to the application and is not typical of a blocking read interface. If the call to release the buffer was *optional*, I'd have no objection, but that puts some additional bookkeeping back on the library side.
    -
    -> Is GetAvailable() the best way to implement non-blocking i/o?
    -It works in practice. Some systems including Windows do not implement this function very well, i.e. the reported available space comes in fits and starts. But at least you can find out if an IO call would block or fail. I'd like to avoid the extra system call when possible though.
    +

    If a NULL callback parameter is passed to Pa_OpenStream() then the stream will be opened in blocking mode. This enables users to call Pa_WriteStream() and Pa_ReadStream() to read and write sample data. (The PaErrorNum item "paNullCallback" becomes obsolete.)

    +

    Pa_WriteStream() writes a buffer of frames to a stream. The length of the buffer is arbitrary and specified by the frames parameter. Pa_WriteStream() returns when all samples have been copied from buffer. If necessary, Pa_WriteStream() will wait until buffer space becomes available. (Waiting on Unix will be the by-product of an I/O system call, waiting in Win32 will be implemented by waiting on an Event object, and waiting on MacOS 9 will probably require a busy wait.) High performance applications will want to match the length of the buffer to framesPerBuffer, but this is not a requirement.

    +

    The buffer parameter has the same semantics and format as the inputbuffer and outputbuffer parameters of a PortAudioCallback function. In particular, non-interleaved data is handled in the same way.

    +

    Pa_ReadStream() is similar, but it reads rather than writes.

    +
    PaError Pa_WriteStream( PortAudioStream *stream,
    +                        void *buffer,
    +                        unsigned long frames );
    +
    +PaError Pa_ReadStream( PortAudioStream *stream,
    +                       void *buffer,
    +                       unsigned long frames );
    +

    Pa_ReadStream() returns paInputUnderflow if input data was discarded by PortAudio after the previous call and before this call. Pa_WriteStream() returns paOutputUnderflow if output data was inserted after the previous call and before this call. The mode flag paNeverDropInput is ignored because Pa_ReadStream() and Pa_WriteStream() are not synchronized.

    +

    There are two functions to determine the number of frames available for writing and reading. These functions may be called to determine whether calls to Pa_WriteStream() or Pa_ReadStream() will return immediately or will wait. The return value, if non-negative, is the maximum number of frames that can be written or read without blocking or busy waiting. A negative value is a PaErrorNum.

    +
    long Pa_StreamWriteAvailable( PortAudioStream *stream );
    +
    +long Pa_StreamReadAvailable( PortAudioStream *stream );
    +

    The stream functions Pa_CloseStream(), Pa_StartStream(), Pa_StopStream(), Pa_AbortStream(), Pa_StreamActive(), and Pa_StreamTime() work with the blocking API as well as with callbacks. Pa_StreamCPULoad() does not work with the blocking API. PortAudio might be extended to give applications access to the internal routines that compute Pa_StreamCPULoad(). Applications using blocking calls could then bracket audio computation with these calls to determine the CPU load. (This additional functionality is not being proposed here.)

    +

    Discussion

    +

    A rejected alternative is to allow Pa_WriteStream() and Pa_ReadStream() to return the number of frames actually written or read so that a Mac implementation could return immediately and avoid blocking. This would require applications to be prepared to handle partial read/writes. It seems simpler and more consistent to use "Available" to determine in advance whether blocking or busy waiting will occur if that is a concern. Also, note that data is almost certainly copied; however, it seems likely that the copy will be folded into any format conversion.

    +

    Implementations may want to provide a way for applications to be notified when data can be written or read. For example, one might want to know the file ID of an ALSA or OSS stream for use in a select() system call. Since this sort of information will be platform-specific and non-portable, no interface is defined here, but implementations can include a device-model-specific access function. If applications commonly need this information, we can think about how to make this more standardized.

    Implementation Notes

    -

    Implementing blocking i/o will be quite simple for driver models where the underlying API is blocking-based, and quite difficult to do well under Windows where much fun will be had with Win32 synchronisation primitives.

    +

    Implementing blocking i/o will be quite simple for driver models where the underlying API is blocking-based. Under Windows (MME), the arrival of a buffer will signal an Event passed to waveOutOpen(). Pa_WriteStream() and Pa_ReadStream() will do all the work (no server threads necessary). Writes will make waveOutWrite calls. When no buffer is available, the writer will wait on the event and try again. Reading is similar. On the Mac, a double-buffer scheme can be set up where the Mac callbacks pick up data placed in buffers by Pa_WriteStream(). The double-buffer adds to the latency. Alternatively (and preferably) callbacks can be used only for notification, and Pa_WriteStream() can issue all the calls to write samples.

    +

    PABLIO currently contains a busy-wait ring buffer in "ringbuffer.c" which is generic, used in many projects and is pretty solid. This code could be a useful starting point for implementing the new blocking API on some platforms.

    +

    Pa_WriteStream() and Pa_ReadStream() are not thread safe. Applications wanting to call these from multiple threads should manage their own mutual exclusion. [Roger: Is any of PortAudio thread safe? I don't think so. This is good because it avoids many system calls for mutual exclusion.]

    +

    At one time it was suggested that implementations only implement blocking calls and that callbacks would be required to implement callbacks in terms of the blocking API. The current direction is that this decision should be made independently for each driver-model.

    Impact Analysis

    -

    This proposal would extend the functionality of PortAudio without requiring any changes to client code.

    +

    This proposal would extend the functionality of PortAudio without requiring any changes to client code with the exception that the PaErrorNum paNullCallback will no longer be defined. As noted above, implementation complexity is dependent on the target platform.

    ____________

    Non-Interleaved Buffers

    Status

    @@ -158,7 +216,7 @@ It works in practice. Some systems including Windows do not implement this funct

    The current PortAudio/ASIO implementation works as follows : ASIO native buffers are non-interleaved and the de-interleaving, format conversion and copying the data into PortAudio interleaved buffers is done in one loop. But if PortAudio supported non-interleaved buffers then we could use efficient vector operations even for native buffer <==> port audio buffers transfers.

    Proposal

    A new sample format could be defined:

    -
    #define paNonInterleaved ((PaSampleFormat) (1<<32)) 
    +
    #define paNonInterleaved ((PaSampleFormat) (1<<31)) 

     

    This could be used as a modifier flag to the buffer format fields of Pa_OpenStream(). When present, this flag would indicate that non-interleaved buffers would be passed to the callback. When not present, interleaved buffers would be used as is currently always the case. For example, the following code would open an interleaved stream:

    @@ -337,8 +395,8 @@ int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate )
     

    Implementation Notes

    The implementation will follow the methodology currently employed in PortMIDI described here: http://techweb.rfa.org/pipermail/portaudio/2001-December/000295.html

    An implementation of the driver model neutral "Façade" of this proposal exists here:

    -

    pa_drivermodel.c.txt

    -

    pa_drivermodel.h.txt

    +

    http://www.portaudio.com/docs/pa_drivermodel.c.txt

    +

    http://www.portaudio.com/docs/pa_drivermodel.h.txt

    This proposal will involve the changes described below. Note that the string <DM> will be replaced with a driver model tag for each implementation.

    Each driver model will have it's own Initialize function which PortAudio will call in response to client calls to Pa_Initialize and Pa_Terminate respectively. This will be the only identifier each driver model implementation will be required to expose.

    PaError Pa<DM>_MultiDriverInitialize( PaDriverModelImplementation **impl );
    @@ -363,6 +421,10 @@ int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate ) fptr start; fptr stop; fptr abort; + fptr read; + fptr write; + fptr readAvailable; + fptr writeAvailable; fptr active; fptr time; fptr cpuLoad; @@ -431,15 +493,17 @@ WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined)

    Impact Analysis

    This proposal improves the quality of PortAudio diagnostics. Client code that depends on paHostError code to flag certain conditions may be effected.

    ____________

    -

    Rename Pa_GetCPULoad() to Pa_StreamCPULoad()

    +

    Rename Pa_GetCPULoad() and paInvalidDeviceId for Consistency

    Status

    Proposal is sufficiently well defined to be implemented. No objections have been raised.

    Background

    PortAudio functions that return global information typically have names of the form Pa_Get*() (eg. Pa_GetDeviceInfo). Almost all functions operating on PortAudio streams conform to the following implicit naming convention: Pa_*Stream( stream ) performs an action on a stream (eg Pa_StartStream() ) and Pa_Stream*( stream ) returns a stream attribute (eg. Pa_StreamTime() ). The only exception to this convention is the confusingly named Pa_GetCPULoad() which actually returns the CPU consumption of a particular stream's callback.

    +

    PortAudio functions and parameter names that operate on integer identifiers use the string ID (all uppercase.) The paInvalidDeviceId error code is an exception to this convention.

    Proposal

    -

    Rename PaGetCPULoad() to Pa_StreamCPULoad() in order to conform to established naming conventions.

    +

    Rename PaGetCPULoad() to Pa_StreamCPULoad() in order to conform to the established naming conventions.

    +

    Rename the paInvalidDeviceId error code to paInvalidDeviceID to conform to the established naming conventions.

    Impact Analysis

    -

    This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which call Pa_GetCPULoad() will need to alter their code by renaming the function call.

    +

    This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which call Pa_GetCPULoad() will need to alter their code by renaming the function call. Clients who explicitly check for the paInvalidDeviceId error code will have to edit its capitalisation.

    ____________

    Coding Style Guidelines

    Status

    @@ -465,9 +529,9 @@ WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined)

  • In almost all cases, a PortAudio error code should be preferred to returning PaHostError. If a new PortAudio error code is needed it should be discussed with the maintainer to coordinate updating port_audio.h
  • PortAudio code should not cause resource leaks. After Pa_Terminate() is called, implementations should guarantee that all dynamically allocated resources have been freed.
  • The definition of the PortAudio API should minimise "implementation defined behaviour". For example, calling functions such as Pa_Initialize() after PortAudio is initialised, or Pa_Terminate() after PortAudio has been terminated should have well defined behaviour. (In this example, both calls should be safe and simply return an error code.)
  • -
  • Minimise dependence on ANSI C runtime on platforms where it would have to be loaded separately (eg on Win32 prefer Win32 API functions such as GlobalAlloc() to ANSI C functions such as malloc().)
  • +
  • Minimise dependence on ANSI C runtime on platforms where it would have to be loaded separately (eg on Win32 prefer Win32 API functions such as GlobalAlloc() to ANSI C functions such as malloc().) (Ross: this may be problematic, since some portable parts of the implementation may need to allocate memory -- perhaps we should define our own internal memory allocation functions.)
  • -

    It has been suggested that we make an effort to minimise the use of global and static data in PortAudio implementations. Another related goal is to reduce name pollution in the global scope. Some possible guidelines in this regard are:

    +

    It has been suggested that we make an effort to minimise the use of global and static data in PortAudio implementations. Another related goal is to reduce name pollution in the global scope. Some possible guidelines in this regard are:

    • Implementations should avoid exporting any symbols except where absolutely necessary. Specifically, global data must be declared statically. We will need a naming convention for non-public global symbols, such as internal functions defined in one module and used in another.
    • @@ -527,7 +591,7 @@ PaError Pa_Terminate( void );

    The conversion functions could look something like:

    void ConversionFunction_DestType_DestInterleave_SrcType_SrcInterleave_ ( void *dest, int destChannels, void *src, int srcChannels, int frames );

    The dest and src parameters have the same format as those supplied to the PortAudio client callback.

    -

    Rather than have each implementation call these conversion functions directly, a 'factory function' could be implemented that returnes a pointer to a conversion function based on parameters specifying the format of the source and destination buffers. This factory function could be called as needed when a stream is opened. The conversion functions could then be made static and hidden from the rest of PortAudio. The 'factory function' could have the following form:

    +

    Rather than have each implementation call these conversion functions directly, a 'factory function' could be implemented that returns a pointer to a conversion function based on parameters specifying the format of the source and destination buffers. This factory function could be called as needed when a stream is opened. The conversion functions could then be made static and hidden from the rest of PortAudio. The 'factory function' could have the following form:

    enum PaEndiannes { paBigEndian, paSmallEndian, paHostEndian };
     
     PaBufferConversionFunction* Pa_GetBufferConversionFunction( 
    @@ -536,7 +600,7 @@ PaBufferConversionFunction* Pa_GetBufferConversionFunction(
     

    Note that the interleave/deinterleave status is encoded in the destFormat and srcFormat parameters. paHostEndian is used to represent the endianness of the current platform since some driver models (eg ASIO) allow the driver to use samples in a different endianness from the host endianness. Another alternative is to encode sample endianness in PaSampleFormat - this would allow clients to write sample data of either endianness to PortAudio (e.g. soundfile playback direct from file) and benefit from PortAudio's byte swapping code.

    The redundant use of channel parameters in both the conversion functions and the factory function is intentional and would allow channel-optimised conversion functions to be supplied for common cases such as 16-bit stereo.

    Discussion

    -

    This proposal currently only addresses buffer conversion functions, but we would like to identify other common code fragments which could be placed in the shared PortAudio library.

    +

    This proposal currently only addresses buffer conversion functions, however it is important to identify other common code fragments that could be placed in the shared PortAudio library.

    This proposal has not yet addressed the fact that the conversion functions also need to handle clipping and dithering.

    It is not clear whether additional conversion functions will be needed to accommodate the MME interleaved stereo pairs for multichannel devices proposal.

    It hasn't been established whether PortAudio will be extended to support all PaSampleFormats on all devices.

    From 06e8ece9dfcf5b10768fd40e6121b6af14dd6180 Mon Sep 17 00:00:00 2001 From: philburk Date: Mon, 6 May 2002 17:18:27 +0000 Subject: [PATCH 078/814] Added V18 release notes. --- docs/releases.html | 99 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 6 deletions(-) diff --git a/docs/releases.html b/docs/releases.html index 4a7efad..aec80a1 100644 --- a/docs/releases.html +++ b/docs/releases.html @@ -2,11 +2,11 @@ - + - PortAudio Implementations for DirectSound + PortAudio Release Notes   @@ -22,25 +22,112 @@ PortAudio - Release Notes

    Link to PortAudio Home Page

    -V18 - unreleased

    +V18 - 5/6/02 -
    Ran most of the code through AStyle +
    All source code and documentation now under CVS. +

    Ran most of the code through AStyle to cleanup ragged indentation caused by using different editors. Used this command: -
    astyle --style=ansi -c -o --convert-tabs --indent-preprocessor +
       astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c

    -
    WMME +
    Added "pa_common/pa_convert.c" for Mac OS X. Start of new conversion +utilities. +

    ASIO +

      +
    • +New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables,
    • + +
    • +Cleanup of Pa_ASIO_Callback_Input
    • + +
    • +Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo
    • + +
    • +Deallocate all resources in PaHost_Term for cases where Pa_CloseStream +is not called properly
    • + +
    • +New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows. +Allows use by multiple threads.
    • + +
    • +Correct error code management in PaHost_Term, removed various compiler +warning
    • + +
    • +Add Mac includes for <Devices.h> and <Timer.h>
    • + +
    • +Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better +error handling
    • +
    +Mac OS X +
      +
    • +Major cleanup and improvements.
    • + +
    • +Fixed device queries for numChannels and sampleRates,
    • + +
    • +Audio input works if using same CoreAudio device (some HW devices make +separate CoreAudio devices).
    • + +
    • +Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.
    • + +
    • +Return error if opened in mono mode cuz not supported.
    • + +
    • +Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally.
    • + +
    • +Use getrusage() instead of gettimeofday() for CPU Load calculation.
    • +
    +Windows MME
    • Fixed bug that caused TIMEOUT in Pa_StopStream(). Added check for past_StopSoon() in Pa_TimeSlice(). Thanks Julien Maillard.
    • + +
    • +Detect Win XP versus NT, use lower latency.
    • + +
    • +Fix DBUG typo;
    • + +
    • +removed init of CurrentCount which was not compiling on Borland
    • + +
    • +general cleanup, factored streamData alloc and cpu usage initialization
    • + +
    • +stopped counting WAVE_MAPPER when there were no audio cards plugged in
    • +
    +Windows DirectSound +
      +
    • +Detect Win XP and Win 2K properly when determining latency.
    Unix OSS
    • Use high real-time priority if app is running with root priveledges. Lowers latency.
    • + +
    • +Added watch dog thread that prevents real-time thread from hogging CPU +and hanging the computer.
    • + +
    • +Check error return from read() and write().
    • + +
    • +Check CPU endianness instead of assuming Little Endian.
    From d9f118bbacb64134b5965095440226fbf32129c4 Mon Sep 17 00:00:00 2001 From: philburk Date: Mon, 6 May 2002 18:29:52 +0000 Subject: [PATCH 079/814] link to release notes --- docs/index.html | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/index.html b/docs/index.html index 7d9b248..dfd648e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -21,16 +21,22 @@ PortAudio Documentation

    Copyright 2000 Phil Burk and Ross Bencina -
      -

    -API Reference

    - -
    The Application Programmer Interface is documented in "portaudio.h".
    -

    Tutorial

    -
    Describes how to write audio programs using the PortAudio API.
    +
    +
    Describes how to write audio programs using the PortAudio API.
    + +

    +API Reference

    + +
    The Application Programmer Interface is documented in "portaudio.h".
    + +

    +Release Notes

    + +
    What changed since the last release?
    +

    Implementation Guide

    From d5b636eea7eaf9ec089f12b29ba037540c3622c9 Mon Sep 17 00:00:00 2001 From: philburk Date: Tue, 7 May 2002 15:40:40 +0000 Subject: [PATCH 080/814] More informative DBUG statement. --- pa_common/pa_lib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pa_common/pa_lib.c b/pa_common/pa_lib.c index 1c6e82f..3df5ec5 100644 --- a/pa_common/pa_lib.c +++ b/pa_common/pa_lib.c @@ -70,8 +70,8 @@ O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for c #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) */ -#define DBUGX(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. */ @@ -152,10 +152,10 @@ PaError Pa_OpenStream( int bitsPerInputSample; int bitsPerOutputSample; /* Print passed parameters. */ - DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n", + DBUG(("Pa_OpenStream( %p, dev=%d, numChan=%d, format=%d, info=%p, /* input */ \n", streamPtrPtr, inputDeviceID, numInputChannels, inputSampleFormat, inputDriverInfo )); - DBUG((" %d, %d, %d, %p, /* output */\n", + DBUG((" dev=%d, numChan=%d, format=%d, info=%p, /* output */\n", outputDeviceID, numOutputChannels, outputSampleFormat, outputDriverInfo )); DBUG((" %g, %d, %d, 0x%x, , %p )\n", From c44218276bd12fbe93cfc41c10d158774fa12cf3 Mon Sep 17 00:00:00 2001 From: rossb Date: Mon, 13 May 2002 21:08:36 +0000 Subject: [PATCH 081/814] various edits to proposals document --- docs/proposals.html | 337 +++++++++++++++++++++++--------------------- 1 file changed, 175 insertions(+), 162 deletions(-) diff --git a/docs/proposals.html b/docs/proposals.html index f8efcff..782c24b 100644 --- a/docs/proposals.html +++ b/docs/proposals.html @@ -21,8 +21,7 @@ name=KeyWords>

    PortAudio Home Page

    - -

    Updated: January 11, 2002

    +

    Updated: May 14, 2002

    Introduction

    This document describes modifications to the PortAudio API currently being considered by the developer community. It is intended to capture the current state of discussions. The authors are the various members of the PortAudio community and are too numerous to mention. Please refer to the mailing list archives to see who said what.

    We are still at the design stage with all of these proposals - if you think something is missing, could be improved, or would just like to comment please do so on the PortAudio mailing list.

    @@ -33,15 +32,15 @@ name=KeyWords>
  • PortAudioCallback Underflow/Overflow Handling
  • Improve Device Format Query System *
  • Improve Latency Mechanisms *
  • -
  • Allow Callbacks to Accept Variable framesPerBuffer *
  • -
  • Blocking Read/Write API |C|
  • +
  • Allow Callbacks to Accept Variable framesPerBuffer *
  • +
  • Blocking Read/Write API
  • Non-Interleaved Buffers
  • -
  • Support for Multiple Driver Models in a Single PortAudio Build |C|
  • -
  • Driver Model Specific Pa_OpenStream() Parameters |C|
  • -
  • Handling of Host-Specific Error Codes *
  • +
  • Support for Multiple Host APIs in a Single PortAudio Build |C|
  • +
  • Host API Specific Pa_OpenStream() Parameters |C|
  • +
  • Handling of Host API Specific Error Codes *
  • Rename Pa_GetCPULoad() and paInvalidDeviceId for Consistency
  • -
  • Coding Style Guidelines *
  • Additional Pa_Terminate() Behaviour
  • +
  • Coding Style Guidelines *
  • Revise Internal Host API *
  • The proposals above which are marked with a * are under construction, those marked with |C| are essentially complete but require community approval or comment before they are considered complete. The remaining proposals are essentially complete and will be implemented as-is unless significant objections are raised.

    @@ -74,29 +73,29 @@ These bits may be set in the statusFlags parameter. #define paInputUnderflow   (1<<0) /* Input data is all zeros because no real data is available. */ #define paInputOverflow (1<<1) /* Input data was discarded by PortAudio */ #define paOutputUnderflow (1<<2) /* Output data was inserted by PortAudio because the callback is using too much CPU */ -#define paOutputOverflow (1<<3) /* Output data will be ignored because no room is available. */
    -

     

    +#define paOutputOverflow (1<<3) /* Output data will be ignored because no room is available. */ +

    New rules will govern when the PortAudioCallback is called:

      -
    • For input-only streams, the callback will be called for every available input buffer. If the callback takes too long to complete and input samples have to be discarded the paInputOverflow flag will be set the next time the callback is called. In input-only stream will never be called with the paInputUnderflow flag set.
    • +
    • For input-only streams, the callback will be called for every available input buffer. If the callback takes too long to complete and input samples have to be discarded the paInputOverflow flag will be set the next time the callback is called. An input-only stream will never be called with the paInputUnderflow flag set.
    • For output-only streams, the callback will be called whenever an output buffer needs to be filled, except when doing so would cause the stream to fall further behind real-time due to CPULoad being too high. In such cases PortAudio will insert silence or repeat the previous buffer to the output and the paOutputUnderflow bit will be set next time the callback is called. An output-only stream will never be called with the paOutputOverflow flag set.
    • -
    • By default, a full duplex stream will behave according to the same rules as an output-only stream. If input is not available, the paInputUnderflow bit will be set and the input buffers will contain zeros. In the case of an input buffer overflow, PortAudio will discard input - in such cases the input samples will not be passed to a callback, and paInputOverflow will be set next time the callback is called to generate more output. A default full-duplex stream will never be called with the paOutputOverflow flag set.
    • -
    • A new mode flag paNeverDropInput to Pa_OpenStream() specifies that a full duplex stream will not discard overflowed input samples without calling the callback. When an input buffer overflow occurs, the callback will be called with the paOutputOverflow flag set, when the callback completes the output buffers will be discarded.
    +
  • By default, a full duplex stream will behave according to the same rules as an output-only stream. If input is not available, the paInputUnderflow bit will be set and the input buffers will contain zeros. In the case of an input buffer overflow, PortAudio will discard input - in such cases the input samples will not be passed to a callback, and paInputOverflow will be set next time the callback is called to generate more output. A full-duplex stream in default mode will never be called with the paOutputOverflow flag set.
  • +
  • A new mode flag to Pa_OpenStream(), paNeverDropInput specifies that a full duplex stream will not discard overflowed input samples without calling the callback. When an input buffer overflow occurs, the callback will be passed an input buffer containing valid data and a valid output buffer pointer, the paOutputOverflow flag will be set, when the callback completes the output buffer will be discarded.
  • -

    Note that the default full-duplex mode is intended to cover most common uses of PortAudio, where the client wants a simple audio streaming interface, and is happy to let PortAudio handle buffer underflow/overflow conditions when they occurs.

    +

    Note that the default full-duplex mode is intended to cover most common uses of PortAudio, where the client wants a simple audio streaming interface, and is happy to let PortAudio handle buffer underflow/overflow conditions when they occur.

    Impact Analysis

    -

    This proposal involves adding a new statusFlags parameter to PortAudioCallback. This will require all clients to update their callback implementations accordingly. Clients who previously checked for NULL buffers will be able to remove such checks.

    +

    This proposal involves adding a new statusFlags parameter to PortAudioCallback. This will require all clients to update their callback declarations accordingly. Clients who previously checked for NULL buffers will be able to remove such checks. Only clients who whish to take advantage of the callback flags, or the new paNeverDropInput mode will require significant changes.

    ____________

    Improve Device Format Query System

    Status

    This proposal is open for discussion.

    Background

    -

    It has been noted that the current method (Pa_GetDeviceInfo()) of querying devices for supported sample formats, channels and sample rates is weak. It does not cleanly differentiate between 'PortAudio supported' formats and 'native' formats, and it is incapable of representing formats where the parameters are interdependent (eg where full duplex is only supported for certain sample rates.) We have also found that a static structure is not a good match for many driver models where format discovery is performed by polling the driver. Even if a sound card supports arbitrary sample rates, the driver model may only allow a client to poll to see whether a rate is available rather than providing the available rate ranges.

    +

    It has been noted that the current method (Pa_GetDeviceInfo()) of querying devices for supported sample formats, channels and sample rates is weak. It does not cleanly differentiate between 'PortAudio supported' formats and 'native' formats, and it is incapable of representing formats where the parameters are interdependent (eg where full duplex is only supported for certain sample rates.) We have also found that a static structure is not a good match for many host APIs where format discovery is performed by polling the driver. Even if a sound card supports arbitrary sample rates, the host API may only allow a client to poll to see whether a rate is available rather than providing the available rate ranges.

    It has been noted that most (platform specific) audio APIs do a pretty bad job of allowing for device capability querying. Even the better APIs (ALSA is perhaps one) don't necessarily provide accurate information. This proposal should seek to maximise the amount of information that can be extracted from existing APIs while remaining expressive enough to take full advantage of APIs with more advanced capability querying systems should they become available in the future.

    Proposal

    A number of options are being considered with regard to supplying clients with format information:

    -

    Use PaDeviceInfo only for representing information that can be expressed without polling the driver multiple times, or only check for "standard" formats, or leave it unchanged.

    +

    Use PaDeviceInfo only for representing information that can be expressed without querying the host API multiple times, or only check for "standard" formats, or leave it unchanged.

    And/Or

    Add a Pa_IsFormatSupported() function:

    Pa_IsFormatSupported( PaDeviceID inputDevice, 
    @@ -107,13 +106,23 @@ These bits may be set in the statusFlags parameter.
                             int numOutputChannels, 
                             PaSampleFormat outputSampleFormat, 
                             void *outputDriverInfo, 
    -                        double sampleRate );
    + double sampleRate ); + +

    At a minimum this call would need to return values indicating whether the requested format(s) are supported natively, or will undergo conversion by PortAudio. The result could be a set of flags indicating:

    + +
      +
    • Input byte order (native/converted)
    • +
    • Input sample format (native/converted)
    • +
    • Output byte order (native/converted)
    • +
    • Output sample format (native/converted)
    + +

    There also needs to be a method for accommodating host-API-specific return flags.

    Discussion

    -

    At present it seems desirable to retain Pa_GetDeviceInfo() and the PaDeviceInfo structure. At a minimum PaDeviceInfo needs to contain name and driver model type code fields:

    +

    At present it seems desirable to retain Pa_GetDeviceInfo() and the PaDeviceInfo structure. At a minimum PaDeviceInfo needs to contain name and host API type code fields:

    typedef struct{
         int structVersion; 
         const char *name;
    -    PaDriverModelTypeCode driverModel;
    +    PaHostAPITypeCode hostAPI;
     } PaDeviceInfo;

    It was suggested that we could do things the way MME does: if Pa_OpenStream() is called with a NULL stream parameter then the stream isn't opened, but it is checked to see if the device supports the specified format - if the format is supported then paNoError would be returned, otherwise an error code would be returned. However, this has been ruled to be unsatisfactory, since querying for supported formats is really a different function from opening a stream.

    Impact Analysis

    @@ -123,33 +132,36 @@ These bits may be set in the statusFlags parameter.

    Status

    This proposal is open for discussion.

    Background

    -

    The current mechanism for setting latency is not considered optimal by all clients of the API. There seems to be some tension between using the framesPerBuffer parameter of Pa_OpenStream as a latency control parameter and as a specifier for the number of frames supplied to the callback. Specifying latency as a single millisecond value would be more user friendly for some users, however some driver models need latency to be tuned by specifying buffer sizes and number of buffers. Additionally, it not clear whether separate input and output buffer counts would allow tuning of lower latencies in some circumstances.

    +

    The current mechanism for setting latency is not considered optimal by all clients of the API. There seems to be some tension between using the framesPerBuffer parameter of Pa_OpenStream as a latency control parameter and as a specifier for the number of frames supplied to the callback. Specifying latency as a single millisecond value would be more user friendly for some users, however some host APIs need latency to be tuned by specifying buffer sizes and number of buffers. Additionally, it not clear whether separate input and output buffer counts would allow tuning of lower latencies in some circumstances.

    A related issue is the need to improve the interface available to determine default latency parameters. The most recent proposal is documented below, however there is still some debate as to whether this is satisfactory.

    See this thread: http://techweb.rfa.org/pipermail/portaudio/2001-October/000196.html

    Proposal

    -

    The numBuffers parameter for Pa_OpenStream() could accept the following values in addition to the normal N>0 values.  Use PA_LATENCY_LOW for interactive performance, when response time is critical.  Use PA_LATENCY_HIGH when playing sound files or other non-interactive uses, when glitch free operation is more critical.

    -
    -#define PA_LATENCY_WHATEVER   (0) /* or _NO_OPINION or? */
    -#define PA_LATENCY_LOW       (-1)  /* For interactive performance. */
    -#define PA_LATENCY_HIGH      (-2)  /* For playing sound files. */
    -

    Currently, when numBuffers>0, Pa_OpenStream will constrain the actual numBuffers so that the latency is within a valid range determined by the driver, or an environment variables such as PA_MIN_LATENCY_MSEC. Propose changing the behaviour so that the requested value is honoured as much as possible. This will allow the user to override the minimum if they know their system can handle it. This might be used, for example on patched Linux kernels. By doing this we simplify the implementations and eliminate the need for adding a Pa_SetMinimumLatency() function.

    -
    -/* Negative return values are (double) paError */
    -double Pa_GetMinimumLatency( int deviceId, double frameRate );
    -double Pa_GetPreferredLatency( int deviceId, double frameRate );
    -double Pa_GetMaximumLatency( int deviceId, double frameRate );
    -/* the following would operate directly on streams */
    +

    The numBuffers parameter to Pa_OpenStream() could be removed, and replaced by two new parameters inputLatencySamples and outputLatencySamples. These parameters allow clients to fine-tune latency in a portable manner. PortAudio implementations should make every reasonable to select buffer sizes based on these parameters, but for various reasons they may choose the closest viable buffer size and latency instead. In such cases PortAudio implementations should round-up (ie always provide equal or higher latency than requested.)

    +

    The special latency value of 0 indicates that the implementation should use the default latency values, this will produce the same behavior as passing 0 for numBuffers in existing PortAudio implementations. Clients may retrieve recommended safe latency settings using the following two functions:

    +
     int Pa_GetRecommendedLowLatencySamples( PaDeviceID deviceID ); /* For interactive performance. */
    + int Pa_GetRecommendedHighLatencySamples( PaDeviceID deviceID ); /* For playing sound files. */
    +

     

    +

    Currently, when numBuffers>0, Pa_OpenStream will constrain the actual numBuffers so that the latency is within a valid range determined by the host API, or an environment variables such as PA_MIN_LATENCY_MSEC. Propose changing the behavior so that the requested value is honored as much as possible. This will allow the user to override the minimum if they know their system can handle it. This might be used, for example on patched Linux kernels

    +

    In addition to the portable latency setting mechanism just described, implementations may use the inputDriverInfo and outputDriverInfo Pa_OpenStream() parameters to provide host API specific latency setting mechanisms which directly reflect the underlying buffer passing scheme. For example, the MME driverInfo structure would provide a way to directly set the bufferSize and numberOfBuffers parameters for input and output. When driverInfo structures are passed to Pa_OpenStream(), using 0 values for their API specific latency settings should cause PortAudio to use Pa_OpenStream()'s latencySamples parameters.

    +

    In cases where Host API specific latency parameters may be limited to certain allowable ranges (buffer sizes in ASIO for example) a method for querying these limits should be provided. This will consist of host-API specific query functions declared in a host-api specific header file. These header files will also contain the declaration of the host API specific driverInfo structure.

    +

    The following two functions have been proposed to retrieve the estimated input and output latency of a stream. Both return the estimated latency in ms.

    +
    /* the following would operate directly on streams */
     double Pa_StreamInputLatency( PortAudioStream *stream );
     double Pa_StreamOutputLatency(PortAudioStream *stream );

    Discussion

    -

    This proposal does not yet address the question of whether there needs to be separate numInputBuffers and numOutputBuffers parameters for optimal latency specification.

    +

    This proposal provides both a high level mechanism for portable latency tuning, and suggests method for providing a host-API specific latency tuning interface. The provision of both default latency settings (via 0 valued latencySamples parameters) and query functions for recommended latency settings provide the needed flexibility for simple, and portable applications.

    +

    It is not clear whether a 0 latencySamples parameter produces the same latency as returned by Pa_GetRecommendedHighLatencySamples() or whether there is a separate default latency value, in which case there should also be a Pa_GetDefaultLatencySamples() function.

    +

    It is unclear whether the Pa_StreamInputLatency() and Pa_StreamOutputLatency() functions are needed, whether they relate directly to this proposal, and how they will be effected by the yet to be documented Improve Callback Timestamp Information proposal.

    +

    Should we provide a way of notifying the client if the latencySamples parameters have not been accurately honored?

    +

    Impact Analysis

    +

    This proposal will require all clients to alter their calls to Pa_OpenStream(). Clients who passed a 0 value for numBuffers will not need to significantly alter their code. Clients who manipulated numBuffers will need to either use the latencySamples parameters, or the host API specific interfaces, as they become available.

    ____________

    -

    Allow Callbacks to Accept Variable framesPerBuffer

    +

    Allow Callbacks to Accept Variable framesPerBuffer

    Status

    This proposal is under construction.

    Background

    -Some devices prefer, or even require, a particular value for framesPerBuffer. Some applications also prefer a particular buffer size because they may, for example, be doing FFTs. If possible, an integral number of application buffers can be fit into a device buffer. If an integral number of application buffers cannot be fit into an application buffer then some system for adapting between them is required. Stephane Letz implemented a block adapter for the ASIO driver that could perhaps be made part of a utility library for PortAudio.
    +Some devices prefer, or even require, a particular value for framesPerBuffer. Some applications also prefer a particular buffer size because they may, for example, be doing FFTs. If possible, an integral number of application buffers can be fit into a device buffer. If an integral number of application buffers cannot be fit into an application buffer then some system for adapting between them is required. Stephane Letz implemented a block adapter for the ASIO implementation that could perhaps be made part of a utility library for PortAudio.

    Adapting between different block size, unfortunately, involves extra memory movement and should be avoided. One way to avoid this is to allow an application to say "I can handle any value for framesPerBuffer". An example would be a simple algorithm like the one in "pa_tests/pa_fuzz.c". Its callback function could easily work with any value for FramesPerBuffer.

    @@ -165,12 +177,13 @@ In order to find out what value the implementation chose, and also to help the a
    int Pa_GetFramesPerBuffer( PortAudioStream* stream );
    int Pa_GetNumOutputBuffers( PortAudioStream* stream );
    -int Pa_GetNumInputBuffers( PortAudioStream* stream );

    -

    +int Pa_GetNumInputBuffers( PortAudioStream* stream );

    +

    Impact Analysis

    +

    This proposal will not effect existing client code, since all clients will currently specify a non-zero framesPerBuffer parameter. Clients whose code can operate with a flexible number of framesPerBuffer may benefit from improved efficiency in some cases simply by specifying paFramesPerBufferUnspecified.

    ____________

    -

    Blocking Read/Write API

    +

    Blocking Read/Write API

    Status

    -

    This proposal is open for comment.

    +

    This proposal is sufficiently well defined to be implemented.

    Background

    Many PortAudio users have requested a blocking read()/write() API that will be supported in addition to the current callback based API. A blocking Read/Write API would allow a more natural style of multi-threaded programming, and facilitate single-threaded reactive applications, while insulating clients from platform-specific thread synchronisation facilities.

    A blocking read/write API would also be useful when binding PortAudio to languages that don't easily support callbacks such as Python, Java, Lisp and Smalltalk. However in this case it has been noted that a blocking API is not sufficient - the host language also needs to support native threads to interact efficiently with blocking. Dannenberg observes that native thread support cannot be added without major redesign (based on a study of Python and Squeak), but given blocking calls, there are several ways to structure programs using non-native threads.

    @@ -182,11 +195,11 @@ int Pa_GetNumInputBuffers( PortAudioStream* stream );

    If a NULL callback parameter is passed to Pa_OpenStream() then the stream will be opened in blocking mode. This enables users to call Pa_WriteStream() and Pa_ReadStream() to read and write sample data. (The PaErrorNum item "paNullCallback" becomes obsolete.)

    Pa_WriteStream() writes a buffer of frames to a stream. The length of the buffer is arbitrary and specified by the frames parameter. Pa_WriteStream() returns when all samples have been copied from buffer. If necessary, Pa_WriteStream() will wait until buffer space becomes available. (Waiting on Unix will be the by-product of an I/O system call, waiting in Win32 will be implemented by waiting on an Event object, and waiting on MacOS 9 will probably require a busy wait.) High performance applications will want to match the length of the buffer to framesPerBuffer, but this is not a requirement.

    The buffer parameter has the same semantics and format as the inputbuffer and outputbuffer parameters of a PortAudioCallback function. In particular, non-interleaved data is handled in the same way.

    -

    Pa_ReadStream() is similar, but it reads rather than writes.

    PaError Pa_WriteStream( PortAudioStream *stream,
                             void *buffer,
    -                        unsigned long frames );
    -
    +                        unsigned long frames );
    +

    Pa_ReadStream() is similar, but it reads rather than writes.

    +
     PaError Pa_ReadStream( PortAudioStream *stream,
                            void *buffer,
                            unsigned long frames );
    @@ -200,10 +213,10 @@ long Pa_StreamReadAvailable( PortAudioStream *stream );

    A rejected alternative is to allow Pa_WriteStream() and Pa_ReadStream() to return the number of frames actually written or read so that a Mac implementation could return immediately and avoid blocking. This would require applications to be prepared to handle partial read/writes. It seems simpler and more consistent to use "Available" to determine in advance whether blocking or busy waiting will occur if that is a concern. Also, note that data is almost certainly copied; however, it seems likely that the copy will be folded into any format conversion.

    Implementations may want to provide a way for applications to be notified when data can be written or read. For example, one might want to know the file ID of an ALSA or OSS stream for use in a select() system call. Since this sort of information will be platform-specific and non-portable, no interface is defined here, but implementations can include a device-model-specific access function. If applications commonly need this information, we can think about how to make this more standardized.

    Implementation Notes

    -

    Implementing blocking i/o will be quite simple for driver models where the underlying API is blocking-based. Under Windows (MME), the arrival of a buffer will signal an Event passed to waveOutOpen(). Pa_WriteStream() and Pa_ReadStream() will do all the work (no server threads necessary). Writes will make waveOutWrite calls. When no buffer is available, the writer will wait on the event and try again. Reading is similar. On the Mac, a double-buffer scheme can be set up where the Mac callbacks pick up data placed in buffers by Pa_WriteStream(). The double-buffer adds to the latency. Alternatively (and preferably) callbacks can be used only for notification, and Pa_WriteStream() can issue all the calls to write samples.

    +

    Implementing blocking i/o will be quite simple for host APIs which are natively blocking-based. Under Windows (MME), the arrival of a buffer will signal an Event passed to waveOutOpen(). Pa_WriteStream() and Pa_ReadStream() will do all the work (no server threads necessary). Writes will make waveOutWrite calls. When no buffer is available, the writer will wait on the event and try again. Reading is similar. On the Mac, a double-buffer scheme can be set up where the Mac callbacks pick up data placed in buffers by Pa_WriteStream(). The double-buffer adds to the latency. Alternatively (and preferably) callbacks can be used only for notification, and Pa_WriteStream() can issue all the calls to write samples.

    PABLIO currently contains a busy-wait ring buffer in "ringbuffer.c" which is generic, used in many projects and is pretty solid. This code could be a useful starting point for implementing the new blocking API on some platforms.

    Pa_WriteStream() and Pa_ReadStream() are not thread safe. Applications wanting to call these from multiple threads should manage their own mutual exclusion. [Roger: Is any of PortAudio thread safe? I don't think so. This is good because it avoids many system calls for mutual exclusion.]

    -

    At one time it was suggested that implementations only implement blocking calls and that callbacks would be required to implement callbacks in terms of the blocking API. The current direction is that this decision should be made independently for each driver-model.

    +

    At one time it was suggested that implementations only implement blocking calls and that callbacks would be required to implement callbacks in terms of the blocking API. The current direction is that this decision should be made independently for each host API.

    Impact Analysis

    This proposal would extend the functionality of PortAudio without requiring any changes to client code with the exception that the PaErrorNum paNullCallback will no longer be defined. As noted above, implementation complexity is dependent on the target platform.

    ____________

    @@ -256,59 +269,59 @@ Pa_OpenStream(&stream,
         float *left = ((float **) inputBuffer)[0];
         float *right = ((float **) inputBuffer)[1];
    -

    This new sample format could also be used to interrogate the native driver to see if it supports interleaved or non-interleaved buffers. This would be achieved by reading the nativeSampleFormats field of the PaDeviceInfo structure.

    +

    This new sample format could also be used to interrogate the host API to see if it supports interleaved or non-interleaved buffers. This would be achieved by reading the nativeSampleFormats field of the PaDeviceInfo structure.

    Impact Analysis

    This proposal extends the functionality of PortAudio without any impact on existing client code. It will require new conversion functions and all existing PortAudio implementations will have to be modified to reference these new conversion functions.

    ____________

    -

    Support For Multiple Driver Models in a Single Build

    +

    Support For Multiple Host APIs in a Single Build

    Status

    This proposal is currently being discussed. Its final form depends on a number of other unfinished proposals.

    Dependencies

    -

    The API changes described in this proposal are independent of all other proposals. However, changes to the host error mechanism defined in Handling of Host-Specific Error Codes, and the addition of new API functions due to the Blocking Read/Write API proposal may effect the implementation of this proposal. Changes to the API defined by the Improve Device Format Query System and the Improve the Latency Setting Mechanism proposals will need to be multi-driver-model capable.

    +

    The API changes described in this proposal are independent of all other proposals. However, changes to the host error mechanism defined in Handling of Host-Specific Error Codes, and the addition of new API functions due to the Blocking Read/Write API proposal may effect the implementation of this proposal. Changes to the API defined by the Improve Device Format Query System and the Improve the Latency Setting Mechanism proposals will need to be multi-host-API capable.

    Background

    -

    As the number of supported driver models available on each platform grows (WMME, ASIO, and DirectSound under Windows for example) client applications need to be able to select between different driver models at run-time. At least four platforms supported by PortAudio have multiple native driver models. At present PortAudio allows clients to link in support for at most one driver model.

    +

    As the number of supported host APIs on each platform grows (WMME, ASIO, and DirectSound under Windows for example) client applications need to be able to select between different host APIs at run-time. At least four platforms supported by PortAudio have multiple host audio APIs. At present PortAudio allows clients to link in support for at most one host API.

    This proposal is based this email: http://techweb.rfa.org/pipermail/portaudio/2001-December/000308.html

    Requirements

    -

    It will be necessary to supply clients with a method of displaying a textual description of the driver model for each PortAudio device.

    -

    Some PortAudio functions do not operate on PortAudioStreams, but rather they operate on or return the global state of the PortAudio library as a whole. If multiple driver-models were present, some of these functions would have different implementations, or would return different values depending on which the driver model they applied to. These functions include:

    +

    It will be necessary to supply clients with a method of displaying a textual description of the host API for each PortAudio device.

    +

    Some PortAudio functions do not operate on PortAudioStreams, but rather they operate on or return the global state of the PortAudio library as a whole. If multiple host APIs were present, some of these functions would have different implementations, or would return different values depending on which host API they applied to. These functions include:

        int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
         PaDeviceID Pa_GetDefaultInputDeviceID( void );
         PaDeviceID Pa_GetDefaultOutputDeviceID( void );
         
    -

    Note that Pa_CountDevices() could also be interpreted as applying to a specific driver model.

    -

    PortAudio currently implements a per-driver-model extension mechanism via the inputDriverInfo and outputDriverInfo parameters to Pa_OpenStream(). For code to take advantage of driver-model-specific extensions when multiple driver models are present there needs to be a way to establish which (statically named) driver model is associated with each device. This is because driver-model-specific extensions should only be used in combination with devices supplied by that driver model.

    -

    PortAudio should present clients with all of the devices made available by each driver model. This means that some physical devices may be accessible though multiple driver models. Since it will not be possible to open a full duplex stream with input and output devices from different driver models, some clients may want to enumerate the available driver models and only display devices from one driver model at a time.

    -

    Introducing a new PortAudioDriverModel abstraction could fulfil the above requirements. At a minimum, this abstraction would need to have the following attributes:

    +

    Note that Pa_CountDevices() could also be interpreted as applying to a specific host API.

    +

    PortAudio currently defines a per-host-API extension mechanism via the inputDriverInfo and outputDriverInfo parameters to Pa_OpenStream(). For code to take advantage of host-API-specific extensions when multiple host APIs are present there needs to be a way to establish which (statically identified) host API is associated with each device. This is because host-API -specific extensions must only be used in combination with devices supplied by that host API.

    +

    PortAudio should present clients with all of the devices made available by each host API. This means that some physical devices may be accessible though multiple host APIs. Since it will not be possible to open a full duplex stream with input and output devices from different host APIs, some clients may want to enumerate the available host APIs and only display devices from one host API at a time.

    +

    Introducing a new PortAudioHostAPI abstraction could fulfil the above requirements. At a minimum, this abstraction would need to have the following attributes:

    • A textual description for display on user interfaces
    • -
    • Functions for querying default device ids and latency parameters for each driver model
    • -
    • A unique identifier published in portaudio.h for use in code which takes advantage of driver model specific extensions
    +
  • Functions for querying default device ids and latency parameters for each host API
  • +
  • A unique identifier for each host API published in portaudio.h for use in code which takes advantage of host API specific extensions
  • Additionally, the following features could be present:

      -
    • A method for querying the default PortAudioDriverModel (perhaps the "best" driver model which has more than 0 devices available)
    • -
    • A method for enumerating 'currently available' PortAudioDriverModels. 'Currently available' could be interpreted as meaning the driver models linked into the current PortAudio implementation, or it could mean the driver models which currently have more than zero devices available.
    • -
    • A method of enumerating PortAudioDevices independently for each available PortAudioDriverModel
    +
  • A method for querying the default PortAudioHostAPI (perhaps the "best" host API which has more than 0 devices available)
  • +
  • A method for enumerating 'currently available' PortAudioHostAPIs. 'Currently available' could be interpreted as meaning the host APIs linked into the current PortAudio implementation, or it could mean the host APIs which currently have more than zero devices available.
  • +
  • A method of enumerating PortAudioDevices independently for each available PortAudioHostAPI
  • Proposal

    This proposal consists of the 7 modifications to the PortAudio API listed below.

    -

    1. Define a new PaDriverModelTypeID enumeration, with fixed values for each driver model:

    +

    1. Define a new PaHostAPITypeID enumeration, with fixed values for each host API:

     /*
    -    The PaDriverModelTypeID enumeration contains constants for uniquely 
    -    Identifying each driver model supported by PortAudio. This type
    -    is used in the PaDriverModelInfo structure below. Driver model type ids
    +    The PaHostAPITypeID enumeration contains constants for uniquely 
    +    Identifying each host API supported by PortAudio. This type
    +    is used in the PaHostAPIInfo structure below. Host API type ids
         are guaranteed to never change, thus allowing code to be written that 
    -    conditionally uses driver model specific extensions.
    -    New type ids will only be allocated when support for a new driver 
    +    conditionally uses host API specific extensions.
    +    New type ids will only be allocated when support for a host API 
         model reaches "public alpha" status, prior to that developers should
         use the paInDevelopment type id.
     */
     
     typedef enum {
    -    paInDevelopment=0, /* use while developing support for a new driver model */
    +    paInDevelopment=0, /* use while developing support for a new host API */
         paWin32DirectSound=1,
         paWin32MME=2,
         paWin32ASIO=3,
    @@ -319,91 +332,91 @@ typedef enum {
         paALSA=8,
         paIRIXAL=9,
         paBeOS=10    
    -}PaDriverModelTypeID;
    -

    2. Define a method for enumerating driver models:

    +}PaHostAPITypeID; +

    2. Define a method for enumerating host APIs:

     /*
    -    Driver model enumeration mechanism.
    +    Host API enumeration mechanism.
     
    -    Driver model ids range from 0 to Pa_CountDriverModels()-1.
    +    Host API ids range from 0 to Pa_CountHostAPIs()-1.
     
    -    The default driver model is the lowest common denominator
    -    driver model on the current platform and is unlikely to provide
    +    The default host API is the lowest common denominator
    +    Host API on the current platform and is unlikely to provide
         the best performance.
     */
     
    -typedef int PaDriverModelID;
    -#define paDefaultDriverModel 0;
    +typedef int PaHostAPIID;
    +#define paDefaultHostAPI 0;
     
     struct{
         int structVersion; 
    -    PaDriverModelTypeID typeID; /* the well known unique identifier of this driver model */
    -    const char *name; /* a textual description of the driver model for display on user interfaces */
    -}PaDriverModelInfo;
    +    PaHostAPITypeID typeID; /* the well known unique identifier of this host API */
    +    const char *name; /* a textual description of the host API for display on user interfaces */
    +}PaHostAPIInfo;
     
     
    -PaDriverModelID Pa_CountDriverModels();
    -

    3. Provide a method for retrieving information about a given driver model:

    +PaHostAPIID Pa_ CountHostAPIs (); +

    3. Provide a method for retrieving information about a given host API:

     /*
    -    Pa_ GetDriverModelInfo () returns a pointer to an immutable 
    -    PaDriverModelInfo structure referring to the device specified by driverModelID. 
    -    If driverModelID is out of range the function returns NULL. The returned structure 
    +    Pa_GetHostAPIInfo () returns a pointer to an immutable 
    +    PaHostAPIInfo structure referring to the host API specified by hostAPIID. 
    +    If hostAPIID is out of range the function returns NULL. The returned structure 
         is owned by the PortAudio implementation and must not be manipulated or 
         freed. The pointer is only guaranteed to be valid between calls 
         to Pa_Initialize() and Pa_Terminate(). 
     */ 
     
    -const PaDriverModelInfo* Pa_GetDriverModelInfo( PaDriverModelID driverModelID );
    -

    4. Add a new field to PaDeviceInfo to identify the driver model type:

    +const PaHostAPIInfo * Pa_GetHostAPIInfo(PaHostAPIID hostAPIID); +

    4. Add a new field to PaDeviceInfo to identify the host API type:

     struct{
         ...
    -    PaDriverModelID driverModel; /* note this is the run-time id */
    +    PaHostAPIID hostAPI; /* note this is the run-time id */
         ...
     }PaDeviceInfo;

    This would enable the following two code fragments to be written.

    -/* obtain the user-readable name of a device's driver model */
    -Pa_GetDriverModelInfo( deviceInfo->driverModel )->name;
    +/* obtain the user-readable name of a device's host API */
    +Pa_GetHostAPIInfo( deviceInfo->hostAPI )->name;
     
    -/* implement special behavior for a specific driver model */
    -if( Pa_GetDriverModelInfo( deviceInfo->driverModel )->typeID == paWin32MME ){
    +/* implement special behavior for a specific host API */
    +if( Pa_GetHostAPIInfo( deviceInfo->hostAPI )->typeID == paWin32MME ){
         InitialiseMMESpecificDeviceInfo();
     }
    -

    5. Provide methods for finding per-driver model default devices and latency settings:

    +

    5. Provide methods for finding per-host API default devices and latency settings:

    -PaDeviceID Pa_DriverModelDefaultInputDeviceID( PaDriverModelID driverModelID );
    -PaDeviceID Pa_DriverModelDefaultOutputDeviceID( PaDriverModelID driverModelID );
    -int Pa_DriverModelMinNumBuffers( PaDriverModelID driverModelID, int framesPerBuffer, double sampleRate );
    -

    6. Provide functions for enumerating devices on a per-driver-model basis. Note that this functionality is provided in addition to the current Pa_CountDevices() and Pa_GetDeviceInfo() functions:

    +PaDeviceID Pa_HostAPIDefaultInputDeviceID( PaHostAPIID hostAPIID ); +PaDeviceID Pa_HostAPIDefaultOutputDeviceID( PaHostAPIID hostAPIID); +int Pa_HostAPIMinNumBuffers(PaHostAPIID hostAPIID, int framesPerBuffer, double sampleRate ); +

    6. Provide functions for enumerating devices on a per-host-API basis. Note that this functionality is provided in addition to the current Pa_CountDevices() and Pa_GetDeviceInfo() functions:

    -int Pa_DriverModelCountDevices( PaDriverModelID driverModelID );
    -PaDeviceID Pa_DriverModelGetDeviceID( PaDriverModelID driverModelID, int perDriverModelIndex );
    -

    7. Re-implement the following existing functions to use the default driver model. This would be a backwards compatible change except for Pa_GetMinNumBuffers() which gains an extra parameter.

    +int Pa_HostAPICountDevices( PaHostAPIID hostAPIID ); +PaDeviceID Pa_HostAPIGetDeviceID( PaHostAPIID hostAPIID, int perHostAPIIndex ); +

    7. Re-implement the following existing functions to use the default host API. This would be a backwards compatible change except for Pa_GetMinNumBuffers() which gains an extra parameter.

    -PaDeviceID Pa_GetDefaultInputDeviceID( void ); /* returns the default device id for the default driver model */
    +PaDeviceID Pa_GetDefaultInputDeviceID( void ); /* returns the default device id for the default host API */
     PaDeviceID Pa_GetDefaultOutputDeviceID( void );
     
     int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate );
    -

    Note that Pa_GetMinNumBuffers() takes a device id, not a driver model id. This minimises the need for clients to be aware of the multiple driver model extensions.

    +

    Note that Pa_GetMinNumBuffers() takes a device id, not a host API id. This minimises the need for clients to be aware of the multiple host API extensions.

    Discussion

    The main disadvantage of this proposal it that it may make the API seem more complex for new users.

    -

    There is concern that this proposal is too complex, and that the simpler solution of simply adding a driverModel string to the device info structure of each device would be sufficient. It is true that the simple solution would allow clients to duplicate the functionality of this proposal, provided driverModel strings were published and guaranteed not to change in the future. However, the bulk of the functionality included in this proposal will need to be implemented internally to facilitate multiple driver model support anyway. This proposal is based on the assumption that it is better to expose such functionality in the PortAudio API rather than require clients to reimplement what is already present internally.

    -

    There has been discussion about supporting "pluggable" driver models - the general idea is that a client application could link against PortAudio and PortAudio would load the available Driver Models at run-time using "PortAudio Driver Model Plugins." Some people consider this to be an overly complex solution, and no significant advantages over a monolithic PortAudio dll have been submitted yet. Some people would like PortAudio to always be able to be statically linked with multiple driver model support.

    -

    The overhead (both processor and memory) of the Multiple Driver Model support should be minimised on platforms which don't have multiple driver models (such as BeOS and some handheld devices.) Essentially this means that the functionality provided in the multiple driver model façade should be easy to duplicate.

    +

    There is concern that this proposal is too complex, and that the simpler solution of simply adding a hostAPI string to the device info structure of each device would be sufficient. It is true that the simple solution would allow clients to duplicate the functionality of this proposal, provided hostAPI strings were published and guaranteed not to change in the future. However, the bulk of the functionality included in this proposal will need to be implemented internally to facilitate multiple host API support anyway. This proposal is based on the assumption that it is better to expose such functionality in the PortAudio API rather than require clients to reimplement what is already present internally.

    +

    There has been discussion about supporting "pluggable" host APIs - the general idea is that a client application could link against PortAudio and PortAudio would load the available Host APIs at run-time using "PortAudio Host API Plugins." Some people consider this to be an overly complex solution, and no significant advantages over a monolithic PortAudio dll have been submitted yet. Some people would like PortAudio to always be able to be statically linked with multiple host API support. The ability to load additional host APIs at runtime is considered desirable so long as the basic multiple host API mechanism does not require dynamic linking.

    +

    The overhead (both processor and memory) of the Multiple Host API support should be minimised on platforms which don't have multiple host APIs (such as BeOS and some handheld devices.) However, the multiple host API support will still be used on all platoforms, so as to reduce the burden on implementers if a second API becomes available, and also to allow reuse of common code in the multiple host API layer across all implementations.

    Implementation Notes

    The implementation will follow the methodology currently employed in PortMIDI described here: http://techweb.rfa.org/pipermail/portaudio/2001-December/000295.html

    -

    An implementation of the driver model neutral "Façade" of this proposal exists here:

    +

    An implementation of the host API neutral "Façade" of this proposal exists here:

    http://www.portaudio.com/docs/pa_drivermodel.c.txt

    http://www.portaudio.com/docs/pa_drivermodel.h.txt

    -

    This proposal will involve the changes described below. Note that the string <DM> will be replaced with a driver model tag for each implementation.

    -

    Each driver model will have it's own Initialize function which PortAudio will call in response to client calls to Pa_Initialize and Pa_Terminate respectively. This will be the only identifier each driver model implementation will be required to expose.

    -
    PaError Pa<DM>_MultiDriverInitialize( PaDriverModelImplementation **impl );
    -

    PaDriverModelImplementation is an internal data structure containing a set of function pointers for globally relevant functions: (function pointer type declarations omitted for simplicity:)

    +

    This proposal will involve the changes described below. Note that the string <HA> will be replaced with a host API tag for each implementation.

    +

    Each host API will have it's own Initialize function which PortAudio will call in response to client calls to Pa_Initialize and Pa_Terminate respectively. This will be the only identifier each host API implementation will be required to expose.

    +
    PaError Pa<HA>_Initialize( PaImplementation **impl );
    +

    PaImplementation is an internal data structure containing a set of function pointers for globally relevant functions: (function pointer type declarations omitted for simplicity:)

    struct{
    -    fptr terminate; /* takes the PaDriverModelImplementation* returned by initialize */
    -    fptr getDriverModelInfo;
    +    fptr terminate; /* takes the PaImplementation* returned by initialize */
    +    fptr getHostAPIInfo;
         fptr getHostError;
         fptr getHostErrorText;
         fptr countDevices;
    @@ -412,9 +425,9 @@ int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate )
         fptr getDeviceInfo;
         fptr openStream;
         fptr getMinNumBuffers;
    -} PaDriverModelImplementation;
    -

    The function pointers in PaDriverModelImplementation will point to the corresponding functions in current PortAudio implementations. The new multiple driver model support code will take care of mapping per-driver model device ids onto a single homogenous driver id range. A significant advantage of this scheme is that it will require very little change to existing PortAudio implementations.

    -

    A new PaStreamImplementation internal data structure will be defined to contain function pointers to implementations of the stream functions for each driver model. This structure will be placed at the head of implementation-specific data structures returned as PortAudioStream* in current implementations.

    +} PaImplementation; +

    The function pointers in PaImplementation will point to the corresponding functions in current PortAudio implementations. The new multiple host API support code will take care of mapping per-host API device ids onto a single homogenous device id range. A significant advantage of this scheme is that it will require very little change to existing PortAudio implementations.

    +

    A new PaStreamImplementation internal data structure will be defined to contain function pointers to implementations of the stream functions for each host API. This structure will be placed at the head of implementation-specific data structures returned as PortAudioStream* in current implementations.

    struct{
         unsigned long magic;
         fptr close;
    @@ -431,29 +444,29 @@ int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate )
     } PaStreamImplementation;

    Magic contains a unique bit pattern which should be set by implementations when a stream is opened, and cleared when it is closed. This technique will allow implementations to perform some degree of validation on PortAudioStream* passed to PortAudio.

    Impact Analysis

    -

    This proposal will significantly improve the utility of PortAudio by allowing clients to support multiple driver models in a single executable.

    -

    The only required change for existing clients will to insert an extra deviceID parameter into calls to Pa_GetMinNumBuffers().

    -

    Since multiple driver models may return devices with the same names, a minimum requirement for clients who want to be "multiple driver model aware" will be to ensure that the appropriate driver model name is displayed alongside device names in the user interface.

    +

    This proposal will significantly improve the utility of PortAudio by allowing clients to support multiple host APIs in a single executable.

    +

    The only required change for existing clients will be to insert an extra deviceID parameter into calls to Pa_GetMinNumBuffers().

    +

    Since multiple host APIs may return devices with the same names, a minimum requirement for clients who want to be "multiple host API aware" will be to ensure that the appropriate host API name is displayed alongside device names in the user interface.

    ____________

    -

    Driver Model Specific Pa_OpenStream() Parameters

    +

    Host API Specific Pa_OpenStream() Parameters

    Status

    -

    This proposal is essentially complete, but is pending the final definition of PaDriverModelTypeID (see below.)

    +

    This proposal is essentially complete, but is pending the final definition of PaHostAPITypeID (see below.)

    Dependencies

    -

    If the PaDriverModelSpecificStreamInfo structure defined in this proposal includes a PaDriverModelTypeID driver model identifier, then this proposal depends on the Support for Multiple Driver Models in a Single PortAudio Build proposal to define the form of the identifier.

    +

    If the PaHostAPISpecificStreamInfo structure defined in this proposal includes a PaHostAPITypeID host API identifier, then this proposal depends on the Support for Multiple Host APIs in a Single PortAudio Build proposal to define the form of the identifier.

    Background

    -

    Pa_OpenStream has always had the inputDriverInfo and outputDriverInfo parameters, which were defined to support passing driver-model specific information to PortAudio implementations. Currently these parameters are defined as void* and are not used by any implementation. Two uses of inputDriverInfo and outputDriverInfo are planned for the near future: passing device names to OSS drivers, and passing additional device ids for opening multichannel soundcards under MME.

    +

    Pa_OpenStream has always had the inputDriverInfo and outputDriverInfo parameters, which were defined to support passing host API specific information to PortAudio implementations. Currently these parameters are defined as void* and are not used by any implementation. Two uses of inputDriverInfo and outputDriverInfo are planned for the near future: passing device names to OSS drivers, and passing additional device ids for opening multichannel soundcards under MME.

    Proposal

    The following structure could be defined and be placed at the head of all data structures passed to the inputDriverInfo and outputDriverInfo parameters of Pa_OpenStream:

    struct{
         unsigned long size;    /* size of whole structure including this header */
    -    PaDriverModelTypeID driverModel; /* driver model for which this data is intended */
    +    PaHostAPITypeID hostAPI; /* host API for which this data is intended */
         unsigned long version; /* structure version */
    -}PaDriverModelSpecificStreamInfo;
    -

    The following driver model specific extensions should be placed in separate header files rather than being placed in portaudio.h

    +}PaHostAPISpecificStreamInfo; +

    The following host API specific extensions should be placed in separate header files rather than being placed in portaudio.h

    ___

    The following structure is proposed for passing device names to the OSS implementation:

    struct{
    -    PaDriverModelSpecificStreamInfo header;
    +    PaHostAPISpecificStreamInfo header;
         char *deviceName;
     }PaOSSSpecificStreamInfo;

    A pointer to this structure could be passed to Pa_OpenStream() to request that a device other than the default dsp device be opened. This structure could be used for opening input and/or output devices.

    @@ -461,25 +474,25 @@ int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate )

    The following structure is proposed for passing multiple interleaved device ids to the MME implementation in order to open a multichannel stream with some soundcards that support multichannel operation via multiple stereo (or other number of channels) interleaved devices. When this structure is passed, the MME implementation would ignore the deviceId parameters passed directly to Pa_OpenStream(), however it would not ignore the channelCount parameters.

    #define paWMMEPassMultipleInterleavedBuffers 0x01 /* a flag */

    struct{
    -    PaDriverModelSpecificStreamInfo header;
    +    PaHostAPISpecificStreamInfo header;
         int *deviceIdsAndChannelCounts; /* interleaved deviceIds and channelCounts */
         int deviceCount;
         int flags;
     }PaMMESpecificStreamInfo;
    -

    The deviceIdsAndChannelCounts field points to an array of ints containing multiple {deviceId, channelCount} pairs. The number of integer elements in the array must be two times the value of the deviceCount field. Specified deviceIds must have a driver model type of Windows MME. Currently only one flag is defined: paWMMEPassMultipleInterleavedBuffers, this can be used to request that the raw, multiple interleaved buffers be passed to the callback.

    +

    The deviceIdsAndChannelCounts field points to an array of ints containing multiple {deviceId, channelCount} pairs. The number of integer elements in the array must be two times the value of the deviceCount field. Specified deviceIds must have a host API type of Windows MME. Currently only one flag is defined: paWMMEPassMultipleInterleavedBuffers, this can be used to request that the raw, multiple interleaved buffers be passed to the callback.

    Discussion

    -

    The type of the inputDriverInfo and outputDriverInfo parameters could be changed to PaDriverModelSpecificStreamInfo* however this may cause more trouble that it's worth.

    +

    The type of the inputDriverInfo and outputDriverInfo parameters could be changed to PaHostAPISpecificStreamInfo* however this may cause more trouble that it's worth.

    The PaMMESpecificStreamInfo functionality may require the common buffer conversion functions defined in the Revise Internal Host API proposal to support (multiple interleave <==> unified interleave) and (multiple interleave <==> non-interleaved) conversions.

    Impact Analysis

    This proposal provides access to new platform-specific extensions. No existing client code will be modified. Only implementations that implement the extensions will be effected.

    ____________

    -

    Handling of Host-Specific Error Codes

    +

    Handling of Host API Specific Error Codes

    Status

    -

    This proposal is sufficiently well defined to be implemented immediately. However, the possibility of extending the scope of this proposal is being discussed in this thread: http://techweb.rfa.org/pipermail/portaudio/2002-January/000358.html

    +

    This proposal is sufficiently well defined to be implemented immediately. However, the possibility of extending the scope of this proposal has been discussed in this thread: http://techweb.rfa.org/pipermail/portaudio/2002-January/000358.html

    Background

    Currently the PaHostError error code is used to notify clients that a platform-specific error condition occurred. This is considered ambiguous and difficult to work with.

    Proposal

    -

    PortAudio should seek to avoid returning ambiguous paHostError error codes, and instead translate to portable PortAudio error codes instead. In the case of the pa_win_mme implementation this means translating the following MME error codes:

    +

    PortAudio should seek to avoid returning ambiguous paHostError error codes, and instead translate to portable PortAudio error codes. In the case of the pa_win_mme implementation this means translating the following MME error codes:

    MMSYSERR_ALLOCATED to paDeviceBusy (new)
    MMSYSERR_BADDEVICEID to paInvalidDeviceId (already defined)
    MMSYSERR_NODRIVER to paDriverMissing (new)
    @@ -489,7 +502,7 @@ WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined)

    It is suggested that all implementations should be audited for their use of PaHostError.

    There was some concern about polluting the PortAudio error code namespace with platform-specific error codes, and of the potential overhead of including platform specific error strings on other platforms. Another suggestion has been to add a Pa_GetHostErrorText() function.

    If all error codes are mapped to PortAudio error codes do we need a PaHostError code and the Pa_GetHostErrorCode() function?

    -

    A suggestion has been made to extend Pa_GetErrorText() so that it retrieved driver model specific error strings when a host error occurs.

    +

    A suggestion has been made to extend Pa_GetErrorText() so that it retrieved host API specific error strings when a host error occurs.

    Impact Analysis

    This proposal improves the quality of PortAudio diagnostics. Client code that depends on paHostError code to flag certain conditions may be effected.

    ____________

    @@ -505,6 +518,33 @@ WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined)

    Impact Analysis

    This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which call Pa_GetCPULoad() will need to alter their code by renaming the function call. Clients who explicitly check for the paInvalidDeviceId error code will have to edit its capitalisation.

    ____________

    +

    Additional Pa_Terminate() Behaviour

    +

    Status

    +

    This proposal is sufficiently well defined to be implemented.

    +

    Background

    +

    Some host APIs (eg ASIO, MME and DirectSound under Windows NT) can require a reboot to free devices when they are not closed properly (due to a program not calling Pa_Close() either in error, or due to a crash.) As a quality of implementation issue PortAudio should seek to avoid such circumstances.

    +

    Proposal

    +

    The definition of Pa_Terminate() should be extended as follows:

    +
    /*
    +    Pa_Terminate() is the library termination function - call this after 
    +    using the library. This function deallocates all resources allocated 
    +    by PortAudio since it was initializied using Pa_Initialize(). Any open 
    +    PortAudioStreams are closed.
    +
    +    Pa_Terminate() MUST be called before exiting a program which 
    +    uses PortAudio. Failure to do so may result in serious resource 
    +    leaks, such as audio devices not being available until the next reboot.
    +*/
    +PaError Pa_Terminate( void );
    +

    Implementation Notes

    +

    One possible implementation strategy would be to add a "next" member to the internal stream data structure thus making it a linked list node, which could be linked into a list of all open streams.

    +

    Discussion

    +

    Some concerns have been raised about the overhead involved in PortAudio having to keep track of which streams are currently open.

    +

    There has been some discussion about the behavior of nesting multiple calls to Pa_Initialize() and Pa_Terminate() - there is no intention of changing the current behaviour, which is that PortAudio has two states: "Initialized" and "Uninitialized" - in the Initialized state, Pa_Initialize() does nothing and returns an error, in the Uninitialized state Pa_Terminate() does nothing and returns an error.

    +

    Impact Analysis

    +

    This proposal changes the termination behaviour of PortAudio to reduce the likelihood of resource leaks.

    +

    On Windows, the new Pa_Terminate() behaviour would allow users who want full protection against device leakage to install a global Win32 exception handler that calls Pa_Terminate() before exiting when a crash occurs. Similar techniques (using SIGNAL handlers perhaps?) may be possible on other platforms where necessary.

    +

    ____________

    Coding Style Guidelines

    Status

    This proposal is under construction. Further suggestions and comments would be extremely welcome.

    @@ -542,38 +582,11 @@ WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined)

    Impact Analysis

    This proposal will require all existing code to be reviewed and possibly revised. This is not expected to be a "big-bang" operation. Rather it is envisaged that this will be a long term, ongoing process aimed at improving the quality of the PortAudio codebase.

    ____________

    -

    Additional Pa_Terminate() Behaviour

    -

    Status

    -

    This proposal is sufficiently well defined to be implemented.

    -

    Background

    -

    Some driver models (eg ASIO, MME and DirectSound under Windows NT) can require a reboot to free devices when they are not closed properly (due to a program not calling Pa_Close() either in error, or due to a crash.) As a quality of implementation issue PortAudio should seek to avoid such circumstances.

    -

    Proposal

    -

    The definition of Pa_Terminate() should be extended as follows:

    -
    /*
    -    Pa_Terminate() is the library termination function - call this after 
    -    using the library. This function deallocates all resources allocated 
    -    by PortAudio since it was initializied using Pa_Initialize(). Any open 
    -    PortAudioStreams are closed.
    -
    -    Pa_Terminate() MUST be called before exiting a program which 
    -    uses PortAudio. Failure to do so may result in serious resource 
    -    leaks, such as audio devices not being available until the next reboot.
    -*/
    -PaError Pa_Terminate( void );
    -

    Implementation Notes

    -

    One possible implementation strategy would be to add a "next" member to the internal stream data structure thus making it a linked list node, which could be linked into a list of all open streams.

    -

    Discussion

    -

    Some concerns have been raised about the overhead involved in PortAudio having to keep track of which streams are currently open.

    -

    There has been some discussion about the behaviour of nesting multiple calls to Pa_Initialize() and Pa_Terminate() - there is no intention of changing the current behaviour, which is that PortAudio has two states: "Initialized" and "Uninitialized" - in the Initialized state, Pa_Initialize() does nothing and returns an error, in the Uninitialized state Pa_Terminate() does nothing and returns an error.

    -

    Impact Analysis

    -

    This proposal changes the termination behaviour of PortAudio to reduce the likelihood of resource leaks.

    -

    On Windows, the new Pa_Terminate() behaviour would allow users who want full protection against device leakage to install a global Win32 exception handler that calls Pa_Terminate() before exiting when a crash occurs. Similar techniques (using SIGNAL handlers perhaps?) may be possible on other platforms where necessary.

    -

    ____________

    Revise Internal Host API

    Status

    This proposal is under construction. Ideally, someone should go through all of the existing implementations and identify code that could be factored into a common library (parameter validation code for example.)

    Dependencies

    -

    This proposal is dependent on the Support for Multiple Driver Models in a Single PortAudio Build proposal, and the Non-Interleaved Buffers proposal. The proposed conversion functions may be dependent on the MME multichannel via stereo pairs extension which is part of the Driver Model Specific Pa_OpenStream() Parameters proposal.

    +

    This proposal is dependent on the Support for Multiple Host APIs in a Single PortAudio Build proposal, and the Non-Interleaved Buffers proposal. The proposed conversion functions may be dependent on the MME multichannel via stereo pairs extension which is part of the Host API Specific Pa_OpenStream() Parameters proposal.

    Background

    PortAudio defines a set of helper functions that all implementations share. It is envisaged that these internal functions will need to be revised in response to the changes proposed in this document. It would also be beneficial to take this opportunity to refactor any other common code fragments that could be shared by multiple implementations.

    A refactoring of the buffer data conversion functions was proposed here: http://techweb.rfa.org/pipermail/portaudio/2001-November/000244.html However the proposal below is not quite the same. A significant benefit of formally specifying the interface to the buffer conversion functions is that it would facilitate the creation of optimised assembly language versions for different platforms.

    @@ -597,7 +610,7 @@ PaError Pa_Terminate( void ); PaBufferConversionFunction* Pa_GetBufferConversionFunction( PaSampleFormat destFormat, int destChannels, PaEndianness destEndianness, PaSampleFormat srcFormat, int srcChannels, PaEndianness srcEndianness ); -

    Note that the interleave/deinterleave status is encoded in the destFormat and srcFormat parameters. paHostEndian is used to represent the endianness of the current platform since some driver models (eg ASIO) allow the driver to use samples in a different endianness from the host endianness. Another alternative is to encode sample endianness in PaSampleFormat - this would allow clients to write sample data of either endianness to PortAudio (e.g. soundfile playback direct from file) and benefit from PortAudio's byte swapping code.

    +

    Note that the interleave/deinterleave status is encoded in the destFormat and srcFormat parameters. paHostEndian is used to represent the endianness of the current platform since some host APIs (eg ASIO) allow the driver to use samples in a different endianness from the host endianness. Another alternative is to encode sample endianness in PaSampleFormat - this would allow clients to write sample data of either endianness to PortAudio (e.g. soundfile playback direct from file) and benefit from PortAudio's byte swapping code.

    The redundant use of channel parameters in both the conversion functions and the factory function is intentional and would allow channel-optimised conversion functions to be supplied for common cases such as 16-bit stereo.

    Discussion

    This proposal currently only addresses buffer conversion functions, however it is important to identify other common code fragments that could be placed in the shared PortAudio library.

    @@ -606,9 +619,9 @@ PaBufferConversionFunction* Pa_GetBufferConversionFunction(

    It hasn't been established whether PortAudio will be extended to support all PaSampleFormats on all devices.

    It isn't clear whether paCustomFormat is viable under this proposal, or how it would be accommodated.

    When the client requested format and the host format are different a temporary buffer may be required to hold the converted data. However, in general PortAudio should aim to convert data in-place. Functions may be needed to establish when temporary buffers are needed, and to allocate them.

    -

    Due to a mismatch between the API buffer size and the PortAudio callback buffer size some driver models require PortAudio to shuffle data among multiple buffers in order to fulfil client requests - this has not yet been considered within the current proposal.

    +

    Due to a mismatch between the API buffer size and the PortAudio callback buffer size some Host APIs require PortAudio to shuffle data among multiple buffers in order to fulfil client requests - this has not yet been considered within the current proposal.

    Memory allocation should probably be handled with platform specific functions such as Win32 GlobalAlloc() rather than using malloc()

    Impact Analysis

    -

    This proposal only effects PortAudio implementors. Increasing the utility of shared code will improve the quality of all PortAudio implementations in terms of speed, size, and robustness. It should also reduce the effort involved in porting PortAudio to a new driver model.

    +

    This proposal only effects PortAudio implementors. Increasing the utility of shared code will improve the quality of all PortAudio implementations in terms of speed, size, and robustness. It should also reduce the effort involved in porting PortAudio to a new host API.

    ____________

    From 8f65d6cb2bb93795bde923274a4ede0156390de2 Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 15 May 2002 17:56:59 +0000 Subject: [PATCH 082/814] added note to latency proposal -> Pa_GetMinNumBuffers() will be removed from API --- docs/proposals.html | 64 +++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/docs/proposals.html b/docs/proposals.html index 782c24b..6d10fda 100644 --- a/docs/proposals.html +++ b/docs/proposals.html @@ -21,7 +21,7 @@ name=KeyWords>

    PortAudio Home Page

    -

    Updated: May 14, 2002

    +

    Updated: May 16, 2002

    Introduction

    This document describes modifications to the PortAudio API currently being considered by the developer community. It is intended to capture the current state of discussions. The authors are the various members of the PortAudio community and are too numerous to mention. Please refer to the mailing list archives to see who said what.

    We are still at the design stage with all of these proposals - if you think something is missing, could be improved, or would just like to comment please do so on the PortAudio mailing list.

    @@ -33,14 +33,14 @@ name=KeyWords>
  • Improve Device Format Query System *
  • Improve Latency Mechanisms *
  • Allow Callbacks to Accept Variable framesPerBuffer *
  • -
  • Blocking Read/Write API
  • +
  • Blocking Read/Write API
  • Non-Interleaved Buffers
  • Support for Multiple Host APIs in a Single PortAudio Build |C|
  • Host API Specific Pa_OpenStream() Parameters |C|
  • Handling of Host API Specific Error Codes *
  • Rename Pa_GetCPULoad() and paInvalidDeviceId for Consistency
  • Additional Pa_Terminate() Behaviour
  • -
  • Coding Style Guidelines *
  • +
  • Coding Style Guidelines *
  • Revise Internal Host API *
  • The proposals above which are marked with a * are under construction, those marked with |C| are essentially complete but require community approval or comment before they are considered complete. The remaining proposals are essentially complete and will be implemented as-is unless significant objections are raised.

    @@ -62,20 +62,20 @@ name=KeyWords>

    Proposal

    For streams providing input, the inputBuffer parameter will always point to a valid memory location containing framesPerBuffer frames of sample data in the requested format. The inputBuffer parameter will be NULL for output only streams. Similarly, the outputBuffer parameter will be NULL for input only streams, otherwise it will point to a valid memory location containing framesPerBuffer frames of sample data.

    A new parameter will be added to the PortAudioCallback Function that gives the status of the data as bit flags.

    -
    typedef int (PortAudioCallback)( 
    -  void *inputBuffer, void *outputBuffer, 
    -  unsigned long framesPerBuffer, 
    -  PaTimestamp outTime, 
    -  unsigned long  statusFlags,
    -  void *userData ); 
    -
    -These bits may be set in the statusFlags parameter. 
    -#define paInputUnderflow   (1<<0) /* Input data is all zeros because no real data is available. */ 
    +
    +typedef int (PortAudioCallback)(
    +  void *inputBuffer, void *outputBuffer,
    +  unsigned long framesPerBuffer,
    +  PaTimestamp outTime, 
    +  unsigned long statusFlags,
    +  void *userData );
    +

    These bits may be set in the statusFlags parameter.

    +
    +#define paInputUnderflow   (1<<0) /* Input data is all zeros because no real data is available. */ 
     #define paInputOverflow    (1<<1) /* Input data was discarded by PortAudio */
    -#define paOutputUnderflow  (1<<2) /* Output data was inserted by PortAudio because the callback is using too much CPU */
    -#define paOutputOverflow   (1<<3) /* Output data will be ignored because no room is available. */
    -
    -

    New rules will govern when the PortAudioCallback is called:

    +#define paOutputUnderflow (1<<2) /* Output data was inserted by PortAudio because the callback is using too much CPU */ +#define paOutputOverflow (1<<3) /* Output data will be ignored because no room is available. */
    +

    New rules will govern when the PortAudioCallback is called:

    • For input-only streams, the callback will be called for every available input buffer. If the callback takes too long to complete and input samples have to be discarded the paInputOverflow flag will be set the next time the callback is called. An input-only stream will never be called with the paInputUnderflow flag set.
    • @@ -106,14 +106,13 @@ These bits may be set in the statusFlags parameter. int numOutputChannels, PaSampleFormat outputSampleFormat, void *outputDriverInfo, - double sampleRate ); - + double sampleRate );

      At a minimum this call would need to return values indicating whether the requested format(s) are supported natively, or will undergo conversion by PortAudio. The result could be a set of flags indicating:

        -
      • Input byte order (native/converted)
      • -
      • Input sample format (native/converted)
      • -
      • Output byte order (native/converted)
      • +
      • Input byte order (native/converted)
      • +
      • Input sample format (native/converted)
      • +
      • Output byte order (native/converted)
      • Output sample format (native/converted)

      There also needs to be a method for accommodating host-API-specific return flags.

      @@ -136,18 +135,21 @@ These bits may be set in the statusFlags parameter.

      A related issue is the need to improve the interface available to determine default latency parameters. The most recent proposal is documented below, however there is still some debate as to whether this is satisfactory.

      See this thread: http://techweb.rfa.org/pipermail/portaudio/2001-October/000196.html

      Proposal

      -

      The numBuffers parameter to Pa_OpenStream() could be removed, and replaced by two new parameters inputLatencySamples and outputLatencySamples. These parameters allow clients to fine-tune latency in a portable manner. PortAudio implementations should make every reasonable to select buffer sizes based on these parameters, but for various reasons they may choose the closest viable buffer size and latency instead. In such cases PortAudio implementations should round-up (ie always provide equal or higher latency than requested.)

      +

      The numBuffers parameter to Pa_OpenStream() could be removed, and replaced by two new parameters inputLatencyFrames and outputLatencyFrames. These parameters allow clients to fine-tune latency in a portable manner. PortAudio implementations should select buffer sizes based on these parameters, if this is not possible they may choose the closest viable buffer size and latency instead. In such cases the PortAudio implementations should round-up (ie always provide equal or higher latency than requested.)

      The special latency value of 0 indicates that the implementation should use the default latency values, this will produce the same behavior as passing 0 for numBuffers in existing PortAudio implementations. Clients may retrieve recommended safe latency settings using the following two functions:

      -
       int Pa_GetRecommendedLowLatencySamples( PaDeviceID deviceID ); /* For interactive performance. */
      - int Pa_GetRecommendedHighLatencySamples( PaDeviceID deviceID ); /* For playing sound files. */
      +
       int Pa_GetRecommendedLowLatencyFrames( PaDeviceID deviceID ); /* For interactive performance. */
      + int Pa_GetRecommendedHighLatencyFrames( PaDeviceID deviceID ); /* For playing sound files. */

       

      Currently, when numBuffers>0, Pa_OpenStream will constrain the actual numBuffers so that the latency is within a valid range determined by the host API, or an environment variables such as PA_MIN_LATENCY_MSEC. Propose changing the behavior so that the requested value is honored as much as possible. This will allow the user to override the minimum if they know their system can handle it. This might be used, for example on patched Linux kernels

      In addition to the portable latency setting mechanism just described, implementations may use the inputDriverInfo and outputDriverInfo Pa_OpenStream() parameters to provide host API specific latency setting mechanisms which directly reflect the underlying buffer passing scheme. For example, the MME driverInfo structure would provide a way to directly set the bufferSize and numberOfBuffers parameters for input and output. When driverInfo structures are passed to Pa_OpenStream(), using 0 values for their API specific latency settings should cause PortAudio to use Pa_OpenStream()'s latencySamples parameters.

      In cases where Host API specific latency parameters may be limited to certain allowable ranges (buffer sizes in ASIO for example) a method for querying these limits should be provided. This will consist of host-API specific query functions declared in a host-api specific header file. These header files will also contain the declaration of the host API specific driverInfo structure.

      The following two functions have been proposed to retrieve the estimated input and output latency of a stream. Both return the estimated latency in ms.

      -
      /* the following would operate directly on streams */
      +
      +/* the following would operate directly on streams */
       double Pa_StreamInputLatency( PortAudioStream *stream );
      -double Pa_StreamOutputLatency(PortAudioStream *stream );
      +double Pa_StreamOutputLatency(PortAudioStream *stream ); +
      +

      The Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ); function will be removed, as it's functionality is fulfilled by the get recommended latency functions.

      Discussion

      This proposal provides both a high level mechanism for portable latency tuning, and suggests method for providing a host-API specific latency tuning interface. The provision of both default latency settings (via 0 valued latencySamples parameters) and query functions for recommended latency settings provide the needed flexibility for simple, and portable applications.

      It is not clear whether a 0 latencySamples parameter produces the same latency as returned by Pa_GetRecommendedHighLatencySamples() or whether there is a separate default latency value, in which case there should also be a Pa_GetDefaultLatencySamples() function.

      @@ -171,14 +173,14 @@ Pa_OpenStream() should be able to accept a zero value for framesPerBuffer. When
      To make the code more obvious, this constant could be used:

      -#define paFramesPerBufferUnspecified (0)
      +#define paFramesPerBufferUnspecified (0)

      In order to find out what value the implementation chose, and also to help the application determine the actual latency, the following calls could be added:

      -int Pa_GetFramesPerBuffer( PortAudioStream* stream );
      +int Pa_GetFramesPerBuffer( PortAudioStream* stream );
      int Pa_GetNumOutputBuffers( PortAudioStream* stream );
      int Pa_GetNumInputBuffers( PortAudioStream* stream );

      -

      Impact Analysis

      +

      Impact Analysis

      This proposal will not effect existing client code, since all clients will currently specify a non-zero framesPerBuffer parameter. Clients whose code can operate with a flexible number of framesPerBuffer may benefit from improved efficiency in some cases simply by specifying paFramesPerBufferUnspecified.

      ____________

      Blocking Read/Write API

      @@ -224,7 +226,7 @@ long Pa_StreamReadAvailable( PortAudioStream *stream );

      Status

      This proposal is sufficiently well defined to be implemented. No objections have been raised.

      Background

      -

      http://techweb.rfa.org/pipermail/portaudio/2001-October/000210.html

      +

      http://techweb.rfa.org/pipermail/portaudio/2001-October/000210.html

      Some native APIs use non-interleaved buffers, particularly those that support N>2 channels. Additionally, many client applications use non-interleaved buffers internally. In order to avoid adding unnecessary overhead, PortAudio should support both interleaved and non-interleaved buffers on all platforms.

      The current PortAudio/ASIO implementation works as follows : ASIO native buffers are non-interleaved and the de-interleaving, format conversion and copying the data into PortAudio interleaved buffers is done in one loop. But if PortAudio supported non-interleaved buffers then we could use efficient vector operations even for native buffer <==> port audio buffers transfers.

      Proposal

      @@ -623,5 +625,5 @@ PaBufferConversionFunction* Pa_GetBufferConversionFunction(

      Memory allocation should probably be handled with platform specific functions such as Win32 GlobalAlloc() rather than using malloc()

      Impact Analysis

      This proposal only effects PortAudio implementors. Increasing the utility of shared code will improve the quality of all PortAudio implementations in terms of speed, size, and robustness. It should also reduce the effort involved in porting PortAudio to a new host API.

      -

      ____________

      +

      ____________

      From e8279e503919ba0bdb748077857d0e5b551b2712 Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 22 May 2002 00:16:42 +0000 Subject: [PATCH 083/814] updated Rename Pa_GetCPULoad(), PaDeviceID etc. for Consistency with new namings revised multihost api and other proposals to use new naming conventions replaced paDefaultHostApi with Pa_GetDefaultHostApi() --- docs/proposals.html | 143 +++++++++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 61 deletions(-) diff --git a/docs/proposals.html b/docs/proposals.html index 6d10fda..ef75105 100644 --- a/docs/proposals.html +++ b/docs/proposals.html @@ -38,7 +38,7 @@ name=KeyWords>
    • Support for Multiple Host APIs in a Single PortAudio Build |C|
    • Host API Specific Pa_OpenStream() Parameters |C|
    • Handling of Host API Specific Error Codes *
    • -
    • Rename Pa_GetCPULoad() and paInvalidDeviceId for Consistency
    • +
    • Rename Pa_GetCPULoad(), PaDeviceID etc. for Consistency
    • Additional Pa_Terminate() Behaviour
    • Coding Style Guidelines *
    • Revise Internal Host API *
    @@ -98,11 +98,11 @@ typedef int (PortAudioCallback)(

    Use PaDeviceInfo only for representing information that can be expressed without querying the host API multiple times, or only check for "standard" formats, or leave it unchanged.

    And/Or

    Add a Pa_IsFormatSupported() function:

    -
    Pa_IsFormatSupported( PaDeviceID inputDevice, 
    +
    Pa_IsFormatSupported( PaDeviceIndex inputDevice, 
                             int numInputChannels, 
                             PaSampleFormat inputSampleFormat,
                             void *inputDriverInfo, 
    -                        PaDeviceID outputDevice, 
    +                        PaDeviceIndex outputDevice, 
                             int numOutputChannels, 
                             PaSampleFormat outputSampleFormat, 
                             void *outputDriverInfo, 
    @@ -121,7 +121,7 @@ typedef int (PortAudioCallback)(
     
    typedef struct{
         int structVersion; 
         const char *name;
    -    PaHostAPITypeCode hostAPI;
    +    PaHostApiTypeCode hostApi;
     } PaDeviceInfo;

    It was suggested that we could do things the way MME does: if Pa_OpenStream() is called with a NULL stream parameter then the stream isn't opened, but it is checked to see if the device supports the specified format - if the format is supported then paNoError would be returned, otherwise an error code would be returned. However, this has been ruled to be unsatisfactory, since querying for supported formats is really a different function from opening a stream.

    Impact Analysis

    @@ -137,8 +137,10 @@ typedef int (PortAudioCallback)(

    Proposal

    The numBuffers parameter to Pa_OpenStream() could be removed, and replaced by two new parameters inputLatencyFrames and outputLatencyFrames. These parameters allow clients to fine-tune latency in a portable manner. PortAudio implementations should select buffer sizes based on these parameters, if this is not possible they may choose the closest viable buffer size and latency instead. In such cases the PortAudio implementations should round-up (ie always provide equal or higher latency than requested.)

    The special latency value of 0 indicates that the implementation should use the default latency values, this will produce the same behavior as passing 0 for numBuffers in existing PortAudio implementations. Clients may retrieve recommended safe latency settings using the following two functions:

    -
     int Pa_GetRecommendedLowLatencyFrames( PaDeviceID deviceID ); /* For interactive performance. */
    - int Pa_GetRecommendedHighLatencyFrames( PaDeviceID deviceID ); /* For playing sound files. */
    +
     
    +unsigned long Pa_GetRecommendedLowLatencyFrames( PaDeviceIndex deviceID ); /* For interactive performance. */
    +unsigned long Pa_GetRecommendedHighLatencyFrames( PaDeviceIndex deviceID ); /* For playing sound files. */
    +

     

    Currently, when numBuffers>0, Pa_OpenStream will constrain the actual numBuffers so that the latency is within a valid range determined by the host API, or an environment variables such as PA_MIN_LATENCY_MSEC. Propose changing the behavior so that the requested value is honored as much as possible. This will allow the user to override the minimum if they know their system can handle it. This might be used, for example on patched Linux kernels

    In addition to the portable latency setting mechanism just described, implementations may use the inputDriverInfo and outputDriverInfo Pa_OpenStream() parameters to provide host API specific latency setting mechanisms which directly reflect the underlying buffer passing scheme. For example, the MME driverInfo structure would provide a way to directly set the bufferSize and numberOfBuffers parameters for input and output. When driverInfo structures are passed to Pa_OpenStream(), using 0 values for their API specific latency settings should cause PortAudio to use Pa_OpenStream()'s latencySamples parameters.

    @@ -146,10 +148,10 @@ typedef int (PortAudioCallback)(

    The following two functions have been proposed to retrieve the estimated input and output latency of a stream. Both return the estimated latency in ms.

     /* the following would operate directly on streams */
    -double Pa_StreamInputLatency( PortAudioStream *stream );
    -double Pa_StreamOutputLatency(PortAudioStream *stream );
    +double Pa_StreamInputLatency( PaStream *stream );
    +double Pa_StreamOutputLatency( PaStream *stream );
     
    -

    The Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ); function will be removed, as it's functionality is fulfilled by the get recommended latency functions.

    +

    The Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) function will be removed, as it's functionality is fulfilled by the get recommended latency functions.

    Discussion

    This proposal provides both a high level mechanism for portable latency tuning, and suggests method for providing a host-API specific latency tuning interface. The provision of both default latency settings (via 0 valued latencySamples parameters) and query functions for recommended latency settings provide the needed flexibility for simple, and portable applications.

    It is not clear whether a 0 latencySamples parameter produces the same latency as returned by Pa_GetRecommendedHighLatencySamples() or whether there is a separate default latency value, in which case there should also be a Pa_GetDefaultLatencySamples() function.

    @@ -177,9 +179,9 @@ To make the code more obvious, this constant could be used:

    In order to find out what value the implementation chose, and also to help the application determine the actual latency, the following calls could be added:

    -int Pa_GetFramesPerBuffer( PortAudioStream* stream );
    -int Pa_GetNumOutputBuffers( PortAudioStream* stream );
    -int Pa_GetNumInputBuffers( PortAudioStream* stream );

    +int Pa_GetFramesPerBuffer( PaStream* stream );
    +int Pa_GetNumOutputBuffers( PaStream* stream );
    +int Pa_GetNumInputBuffers( PaStream* stream );

    Impact Analysis

    This proposal will not effect existing client code, since all clients will currently specify a non-zero framesPerBuffer parameter. Clients whose code can operate with a flexible number of framesPerBuffer may benefit from improved efficiency in some cases simply by specifying paFramesPerBufferUnspecified.

    ____________

    @@ -197,19 +199,19 @@ int Pa_GetNumInputBuffers( PortAudioStream* stream );

    If a NULL callback parameter is passed to Pa_OpenStream() then the stream will be opened in blocking mode. This enables users to call Pa_WriteStream() and Pa_ReadStream() to read and write sample data. (The PaErrorNum item "paNullCallback" becomes obsolete.)

    Pa_WriteStream() writes a buffer of frames to a stream. The length of the buffer is arbitrary and specified by the frames parameter. Pa_WriteStream() returns when all samples have been copied from buffer. If necessary, Pa_WriteStream() will wait until buffer space becomes available. (Waiting on Unix will be the by-product of an I/O system call, waiting in Win32 will be implemented by waiting on an Event object, and waiting on MacOS 9 will probably require a busy wait.) High performance applications will want to match the length of the buffer to framesPerBuffer, but this is not a requirement.

    The buffer parameter has the same semantics and format as the inputbuffer and outputbuffer parameters of a PortAudioCallback function. In particular, non-interleaved data is handled in the same way.

    -
    PaError Pa_WriteStream( PortAudioStream *stream,
    +
    PaError Pa_WriteStream( PaStream* stream,
                             void *buffer,
                             unsigned long frames );

    Pa_ReadStream() is similar, but it reads rather than writes.

    -PaError Pa_ReadStream( PortAudioStream *stream,
    +PaError Pa_ReadStream( PaStream* stream,
                            void *buffer,
                            unsigned long frames );

    Pa_ReadStream() returns paInputUnderflow if input data was discarded by PortAudio after the previous call and before this call. Pa_WriteStream() returns paOutputUnderflow if output data was inserted after the previous call and before this call. The mode flag paNeverDropInput is ignored because Pa_ReadStream() and Pa_WriteStream() are not synchronized.

    There are two functions to determine the number of frames available for writing and reading. These functions may be called to determine whether calls to Pa_WriteStream() or Pa_ReadStream() will return immediately or will wait. The return value, if non-negative, is the maximum number of frames that can be written or read without blocking or busy waiting. A negative value is a PaErrorNum.

    -
    long Pa_StreamWriteAvailable( PortAudioStream *stream );
    +
    long Pa_StreamWriteAvailable( PaStream* stream );
     
    -long Pa_StreamReadAvailable( PortAudioStream *stream );
    +long Pa_StreamReadAvailable( PaStream* stream );

    The stream functions Pa_CloseStream(), Pa_StartStream(), Pa_StopStream(), Pa_AbortStream(), Pa_StreamActive(), and Pa_StreamTime() work with the blocking API as well as with callbacks. Pa_StreamCPULoad() does not work with the blocking API. PortAudio might be extended to give applications access to the internal routines that compute Pa_StreamCPULoad(). Applications using blocking calls could then bracket audio computation with these calls to determine the CPU load. (This additional functionality is not being proposed here.)

    Discussion

    A rejected alternative is to allow Pa_WriteStream() and Pa_ReadStream() to return the number of frames actually written or read so that a Mac implementation could return immediately and avoid blocking. This would require applications to be prepared to handle partial read/writes. It seems simpler and more consistent to use "Available" to determine in advance whether blocking or busy waiting will occur if that is a concern. Also, note that data is almost certainly copied; however, it seems likely that the copy will be folded into any format conversion.

    @@ -232,7 +234,6 @@ long Pa_StreamReadAvailable( PortAudioStream *stream );

    Proposal

    A new sample format could be defined:

    #define paNonInterleaved ((PaSampleFormat) (1<<31)) 
    -

     

    This could be used as a modifier flag to the buffer format fields of Pa_OpenStream(). When present, this flag would indicate that non-interleaved buffers would be passed to the callback. When not present, interleaved buffers would be used as is currently always the case. For example, the following code would open an interleaved stream:

     Pa_OpenStream(&stream,
    @@ -240,7 +241,7 @@ Pa_OpenStream(&stream,
         0,
         paFloat32
         NULL,
    -    Pa_GetDefaultOutputDeviceID(),
    +    Pa_GetDefaultOutputDevice(),
         2,
         paFloat32,
         NULL,
    @@ -257,7 +258,7 @@ Pa_OpenStream(&stream,
         0,
         paFloat32|paNonInterleaved,
         NULL,
    -    Pa_GetDefaultOutputDeviceID(),
    +    Pa_GetDefaultOutputDevice(),
         2,
         paFloat32|paNonInterleaved,
         NULL,
    @@ -309,12 +310,12 @@ Pa_OpenStream(&stream,
     
     

    Proposal

    This proposal consists of the 7 modifications to the PortAudio API listed below.

    -

    1. Define a new PaHostAPITypeID enumeration, with fixed values for each host API:

    +

    1. Define a new PaHostApiTypeId enumeration, with fixed values for each host API:

     /*
    -    The PaHostAPITypeID enumeration contains constants for uniquely 
    +    The PaHostApiTypeId enumeration contains constants for uniquely 
         Identifying each host API supported by PortAudio. This type
    -    is used in the PaHostAPIInfo structure below. Host API type ids
    +    is used in the PaHostApiInfo structure below. Host API type ids
         are guaranteed to never change, thus allowing code to be written that 
         conditionally uses host API specific extensions.
         New type ids will only be allocated when support for a host API 
    @@ -334,73 +335,76 @@ typedef enum {
         paALSA=8,
         paIRIXAL=9,
         paBeOS=10    
    -}PaHostAPITypeID;
    +}PaHostApiTypeId ;

    2. Define a method for enumerating host APIs:

     /*
         Host API enumeration mechanism.
     
    -    Host API ids range from 0 to Pa_CountHostAPIs()-1.
    +    Host API indicies range from 0 to Pa_CountHostApis()-1.
     
    +    Pa_GetDefaultHostApi() returns the index of the default host api.
         The default host API is the lowest common denominator
         Host API on the current platform and is unlikely to provide
         the best performance.
     */
     
    -typedef int PaHostAPIID;
    -#define paDefaultHostAPI 0;
    +typedef int PaHostApiIndex;
     
    -struct{
    -    int structVersion; 
    -    PaHostAPITypeID typeID; /* the well known unique identifier of this host API */
    -    const char *name; /* a textual description of the host API for display on user interfaces */
    -}PaHostAPIInfo;
    +PaHostApiIndex Pa_CountHostApis ();
     
    -
    -PaHostAPIID Pa_ CountHostAPIs ();
    +PaHostApiIndex Pa_GetDefaultHostApi(); +

    3. Provide a method for retrieving information about a given host API:

     /*
    -    Pa_GetHostAPIInfo () returns a pointer to an immutable 
    -    PaHostAPIInfo structure referring to the host API specified by hostAPIID. 
    -    If hostAPIID is out of range the function returns NULL. The returned structure 
    +    Pa_GetHostApiInfo() returns a pointer to an immutable 
    +    PaHostApiInfo structure referring to the host API specified by hostApi. 
    +    If hostApi is out of range the function returns NULL. The returned structure 
         is owned by the PortAudio implementation and must not be manipulated or 
         freed. The pointer is only guaranteed to be valid between calls 
         to Pa_Initialize() and Pa_Terminate(). 
     */ 
     
    -const PaHostAPIInfo * Pa_GetHostAPIInfo(PaHostAPIID hostAPIID);
    +const PaHostApiInfo * Pa_GetHostApiInfo(PaHostApiIndex hostApi); + +struct{ + int structVersion; + PaHostApiTypeId typeId; /* the well known unique identifier of this host API */ + const char *name; /* a textual description of the host API for display on user interfaces */ +}PaHostApiInfo; +

    4. Add a new field to PaDeviceInfo to identify the host API type:

     struct{
         ...
    -    PaHostAPIID hostAPI; /* note this is the run-time id */
    +    PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/
         ...
     }PaDeviceInfo;

    This would enable the following two code fragments to be written.

     /* obtain the user-readable name of a device's host API */
    -Pa_GetHostAPIInfo( deviceInfo->hostAPI )->name;
    +Pa_GetHostApiInfo( deviceInfo->hostApi )->name;
     
     /* implement special behavior for a specific host API */
    -if( Pa_GetHostAPIInfo( deviceInfo->hostAPI )->typeID == paWin32MME ){
    -    InitialiseMMESpecificDeviceInfo();
    +if( Pa_GetHostApiInfo( deviceInfo->hostApi )->typeId == paWin32MME ){
    +    InitialiseWmmeSpecificDeviceInfo();
     }

    5. Provide methods for finding per-host API default devices and latency settings:

    -PaDeviceID Pa_HostAPIDefaultInputDeviceID( PaHostAPIID hostAPIID );
    -PaDeviceID Pa_HostAPIDefaultOutputDeviceID( PaHostAPIID hostAPIID);
    -int Pa_HostAPIMinNumBuffers(PaHostAPIID hostAPIID, int framesPerBuffer, double sampleRate );
    +PaDeviceIndex Pa_HostApiDefaultInputDevice( PaHostApiIndex hostApi ); +PaDeviceIndex Pa_HostApiDefaultOutputDevice( PaHostApiIndex hostApi ); +int Pa_HostApiMinNumBuffers(PaHostApiIndex hostApi, int framesPerBuffer, double sampleRate );

    6. Provide functions for enumerating devices on a per-host-API basis. Note that this functionality is provided in addition to the current Pa_CountDevices() and Pa_GetDeviceInfo() functions:

    -int Pa_HostAPICountDevices( PaHostAPIID hostAPIID );
    -PaDeviceID Pa_HostAPIGetDeviceID( PaHostAPIID hostAPIID, int perHostAPIIndex );
    +PaDeviceIndex Pa_HostApiCountDevices( PaHostApiIndex hostApi ); +PaDeviceIndex Pa_HostAPIGetDeviceID( PaHostApiIndex hostApi, PaDeviceIndex perHostApiIndex );

    7. Re-implement the following existing functions to use the default host API. This would be a backwards compatible change except for Pa_GetMinNumBuffers() which gains an extra parameter.

    -PaDeviceID Pa_GetDefaultInputDeviceID( void ); /* returns the default device id for the default host API */
    -PaDeviceID Pa_GetDefaultOutputDeviceID( void );
    +PaDeviceIndex Pa_GetDefaultInputDevice( void ); /* returns the default device id for the default host API */
    +PaDeviceIndex Pa_GetDefaultOutputDevice( void );
     
    -int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate );
    +int Pa_GetMinNumBuffers( PaDeviceIndex id, int framesPerBuffer, double sampleRate );

    Note that Pa_GetMinNumBuffers() takes a device id, not a host API id. This minimises the need for clients to be aware of the multiple host API extensions.

    Discussion

    The main disadvantage of this proposal it that it may make the API seem more complex for new users.

    @@ -452,23 +456,23 @@ int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate )

    ____________

    Host API Specific Pa_OpenStream() Parameters

    Status

    -

    This proposal is essentially complete, but is pending the final definition of PaHostAPITypeID (see below.)

    +

    This proposal is essentially complete, but is pending the final definition of PaHostApiTypeId (see below.)

    Dependencies

    -

    If the PaHostAPISpecificStreamInfo structure defined in this proposal includes a PaHostAPITypeID host API identifier, then this proposal depends on the Support for Multiple Host APIs in a Single PortAudio Build proposal to define the form of the identifier.

    +

    If the PaHostApiSpecificStreamInfo structure defined in this proposal includes a PaHostApiTypeId host API identifier, then this proposal depends on the Support for Multiple Host APIs in a Single PortAudio Build proposal to define the form of the identifier.

    Background

    Pa_OpenStream has always had the inputDriverInfo and outputDriverInfo parameters, which were defined to support passing host API specific information to PortAudio implementations. Currently these parameters are defined as void* and are not used by any implementation. Two uses of inputDriverInfo and outputDriverInfo are planned for the near future: passing device names to OSS drivers, and passing additional device ids for opening multichannel soundcards under MME.

    Proposal

    The following structure could be defined and be placed at the head of all data structures passed to the inputDriverInfo and outputDriverInfo parameters of Pa_OpenStream:

    struct{
         unsigned long size;    /* size of whole structure including this header */
    -    PaHostAPITypeID hostAPI; /* host API for which this data is intended */
    +    PaHostApiTypeId hostApiType; /* host API for which this data is intended */
         unsigned long version; /* structure version */
    -}PaHostAPISpecificStreamInfo;
    +}PaHostApiSpecificStreamInfo;

    The following host API specific extensions should be placed in separate header files rather than being placed in portaudio.h

    ___

    The following structure is proposed for passing device names to the OSS implementation:

    struct{
    -    PaHostAPISpecificStreamInfo header;
    +    PaHostApiSpecificStreamInfo header;
         char *deviceName;
     }PaOSSSpecificStreamInfo;

    A pointer to this structure could be passed to Pa_OpenStream() to request that a device other than the default dsp device be opened. This structure could be used for opening input and/or output devices.

    @@ -476,8 +480,8 @@ int Pa_GetMinNumBuffers( PaDeviceID id, int framesPerBuffer, double sampleRate )

    The following structure is proposed for passing multiple interleaved device ids to the MME implementation in order to open a multichannel stream with some soundcards that support multichannel operation via multiple stereo (or other number of channels) interleaved devices. When this structure is passed, the MME implementation would ignore the deviceId parameters passed directly to Pa_OpenStream(), however it would not ignore the channelCount parameters.

    #define paWMMEPassMultipleInterleavedBuffers 0x01 /* a flag */

    struct{
    -    PaHostAPISpecificStreamInfo header;
    -    int *deviceIdsAndChannelCounts; /* interleaved deviceIds and channelCounts */
    +    PaHostApiSpecificStreamInfo header;
    +    int *devicesAndChannelCounts; /* interleaved devices and channelCounts */
         int deviceCount;
         int flags;
     }PaMMESpecificStreamInfo;
    @@ -508,17 +512,34 @@ WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined)

    Impact Analysis

    This proposal improves the quality of PortAudio diagnostics. Client code that depends on paHostError code to flag certain conditions may be effected.

    ____________

    -

    Rename Pa_GetCPULoad() and paInvalidDeviceId for Consistency

    +

    Rename Pa_GetCPULoad(), PaDeviceID etc. for Consistency

    Status

    Proposal is sufficiently well defined to be implemented. No objections have been raised.

    Background

    -

    PortAudio functions that return global information typically have names of the form Pa_Get*() (eg. Pa_GetDeviceInfo). Almost all functions operating on PortAudio streams conform to the following implicit naming convention: Pa_*Stream( stream ) performs an action on a stream (eg Pa_StartStream() ) and Pa_Stream*( stream ) returns a stream attribute (eg. Pa_StreamTime() ). The only exception to this convention is the confusingly named Pa_GetCPULoad() which actually returns the CPU consumption of a particular stream's callback.

    +

    +PortAudio functions that return global information typically have names of the form Pa_Get*() (eg. Pa_GetDeviceInfo). However functions retrieving information from a stream do not currently follow this convention (Pa_StreamActive() and Pa_StreamTime()), additionally the Pa_GetCPULoad() function operates on a stream, but does not contain stream in its name. +

    PortAudio functions and parameter names that operate on integer identifiers use the string ID (all uppercase.) The paInvalidDeviceId error code is an exception to this convention.

    Proposal

    -

    Rename PaGetCPULoad() to Pa_StreamCPULoad() in order to conform to the established naming conventions.

    -

    Rename the paInvalidDeviceId error code to paInvalidDeviceID to conform to the established naming conventions.

    +

    Rename the stream accessor functions as follows:

    +
    +Pa_StreamActive() -> Pa_IsStreamActive()
    +Pa_StreamTime() -> Pa_GetStreamTime()
    +Pa_GetCPULoad() -> Pa_GetStreamCpuLoad()
    +
    +

    Note that CPU becomes Cpu, the convention of only capitalising the first letter of an acronym has been adopted in other proposals too.

    + +

    Rename device identifier types and functions as follows:

    +
    +paInvalidDeviceId -> paInvalidDevice
    +PaDeviceID -> PaDeviceIndex
    +Pa_GetDefaultInputDeviceID() -> Pa_GetDefaultInputDevice()
    +Pa_GetDefaultOutputDeviceID() -> Pa_GetDefaultOutputDevice()
    +
    +

    The use of the term index in PaDeviceIndex clearly denotes that the types has values within a closed range and may be incremented or decremented to access adjacent values. The ommission of "Index" from paInvalidDevice and the Pa_GetDefault* functions is justified by the fact that the only public representation of a device is its index. +

    Impact Analysis

    -

    This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which call Pa_GetCPULoad() will need to alter their code by renaming the function call. Clients who explicitly check for the paInvalidDeviceId error code will have to edit its capitalisation.

    +

    This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which currently call Pa_GetCPULoad(), Pa_StreamTime(), Pa_StreamActive(), Pa_GetDefaultInputDevice(), or Pa_GetDefaultOutputDevice() will need to alter their code by renaming the function call. Clients who explicitly check for the paInvalidDeviceId error code, or use the PaDeviceID type will have to edit the spelling of these identifiers.

    ____________

    Additional Pa_Terminate() Behaviour

    Status

    From 51ecb8833fd62ec5e8575c49a2cf061fd68ff136 Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 22 May 2002 00:19:32 +0000 Subject: [PATCH 084/814] changed last modified date --- docs/proposals.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proposals.html b/docs/proposals.html index ef75105..0aef609 100644 --- a/docs/proposals.html +++ b/docs/proposals.html @@ -21,7 +21,7 @@ name=KeyWords>

    PortAudio Home Page

    -

    Updated: May 16, 2002

    +

    Updated: May 22, 2002

    Introduction

    This document describes modifications to the PortAudio API currently being considered by the developer community. It is intended to capture the current state of discussions. The authors are the various members of the PortAudio community and are too numerous to mention. Please refer to the mailing list archives to see who said what.

    We are still at the design stage with all of these proposals - if you think something is missing, could be improved, or would just like to comment please do so on the PortAudio mailing list.

    From 51d40fbecd680f4d3a76620fe8d62896570d88ff Mon Sep 17 00:00:00 2001 From: rossb Date: Sun, 9 Jun 2002 00:33:05 +0000 Subject: [PATCH 085/814] added readme about compiling the ASIO sdk with borland compilers --- pa_asio/borland_asio_readme.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 pa_asio/borland_asio_readme.txt diff --git a/pa_asio/borland_asio_readme.txt b/pa_asio/borland_asio_readme.txt new file mode 100644 index 0000000..56e472b --- /dev/null +++ b/pa_asio/borland_asio_readme.txt @@ -0,0 +1,6 @@ +Steinberg's ASIO 2 SDK will compile but crash on +initialization if compiled with a Borland compiler. + +The problem is described, and a solution provided on +the following page: +http://www.audiomulch.com/~rossb/code/calliasio \ No newline at end of file From 320bace3efbe2c09f029caea232e54292891ec55 Mon Sep 17 00:00:00 2001 From: rossbencina Date: Wed, 12 Jun 2002 00:33:22 +0000 Subject: [PATCH 086/814] added "Clarify Stream State Machine and State Querying Functions" proposal --- docs/PaStreamStateDiagram.gif | Bin 0 -> 9544 bytes docs/proposals.html | 105 ++++++++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 docs/PaStreamStateDiagram.gif diff --git a/docs/PaStreamStateDiagram.gif b/docs/PaStreamStateDiagram.gif new file mode 100644 index 0000000000000000000000000000000000000000..b8955b35791c5f840c04e8cfa418fc91c9bb6a59 GIT binary patch literal 9544 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 +
  • Revise Internal Host API *
  • + + + +

    The proposals above which are marked with a * are under construction, those marked with |C| are essentially complete but require community approval or comment before they are considered complete. The remaining proposals are essentially complete and will be implemented as-is unless significant objections are raised.

    Status

    @@ -212,7 +217,7 @@ PaError Pa_ReadStream( PaStream* stream,
    long Pa_StreamWriteAvailable( PaStream* stream );
     
     long Pa_StreamReadAvailable( PaStream* stream );
    -

    The stream functions Pa_CloseStream(), Pa_StartStream(), Pa_StopStream(), Pa_AbortStream(), Pa_StreamActive(), and Pa_StreamTime() work with the blocking API as well as with callbacks. Pa_StreamCPULoad() does not work with the blocking API. PortAudio might be extended to give applications access to the internal routines that compute Pa_StreamCPULoad(). Applications using blocking calls could then bracket audio computation with these calls to determine the CPU load. (This additional functionality is not being proposed here.)

    +

    The stream functions Pa_CloseStream(), Pa_StartStream(), Pa_StopStream(), Pa_AbortStream(), and Pa_StreamTime() work with the blocking API as well as with callbacks. Pa_StreamCPULoad() does not work with the blocking API and will return 0 when called on a blocking stream. PortAudio might be extended to give applications access to the internal routines that compute Pa_StreamCPULoad(). Applications using blocking calls could then bracket audio computation with these calls to determine the CPU load. (This additional functionality is not being proposed here.)

    Discussion

    A rejected alternative is to allow Pa_WriteStream() and Pa_ReadStream() to return the number of frames actually written or read so that a Mac implementation could return immediately and avoid blocking. This would require applications to be prepared to handle partial read/writes. It seems simpler and more consistent to use "Available" to determine in advance whether blocking or busy waiting will occur if that is a concern. Also, note that data is almost certainly copied; however, it seems likely that the copy will be folded into any format conversion.

    Implementations may want to provide a way for applications to be notified when data can be written or read. For example, one might want to know the file ID of an ALSA or OSS stream for use in a select() system call. Since this sort of information will be platform-specific and non-portable, no interface is defined here, but implementations can include a device-model-specific access function. If applications commonly need this information, we can think about how to make this more standardized.

    @@ -511,6 +516,97 @@ WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined)

    A suggestion has been made to extend Pa_GetErrorText() so that it retrieved host API specific error strings when a host error occurs.

    Impact Analysis

    This proposal improves the quality of PortAudio diagnostics. Client code that depends on paHostError code to flag certain conditions may be effected.

    +

    ____________

    +

    Clarify Stream State Machine and State Querying Functions

    +

    Status

    +

    +This proposal is sufficiently well defined to be implemented. +

    + +

    Background

    +

    +Interaction between Pa_StartStream(), Pa_StopStream() and Pa_AbortStream(), and the ability to stop a stream +by returning non-zero from the callback function was never clearly documented. After returning non-zero from the callback it was not clear whether the stream was stopped (meaning that Pa_StartStream() could be called immediately) or whether the Stream was in some intermediate state, requiring Pa_StopStream() to be called prior to being Started again. The availability of Pa_StreamActive() implied the latter case, but it was never documented. +

    +

    +In order for the common infrastructure to manage some stream state transitions (such as automatically stopping an active stream when closing it) a function to query whether the stream is stopped is required. +

    +

    +It has been suggested that it should be possible for the callback return value to indicate whether a stream should +stop immediately or that it should stop after all queued buffers have been played (current behavior.) Thus providing similar behavior to Pa_StopStream()/Pa_AbortStream() from the callback. +

    +

    +This proposal documents the previously implicit state machine for PortAudio Streams and provides a new accessor function for determining whether the stream is stopped. It also defines 3 new constants which can be used as return values from the callback. +

    + +

    Proposal

    +

    +PortAudio streams will function according to the following state machine: +

    +

    + +

    +

    +A new function Pa_IsStreamStopped() will be added to allow clients to determine whether the Stream is in the Stopped state. +

    +

    +New error codes paStreamIsStopped and paStreamIsNotStopped will be added (see below for usage.) +

    +

    Stream functions will interact with the state machine as follows:

    + +
    +Pa_OpenStream() -> creates a stream in the Stopped state
    +Pa_CloseStream() -> always closes a stream, 
    +	if the stream is not Stopped it will be automatically
    +	aborted using Pa_AbortStream() before being closed.
    +
    +In the Stopped state:
    +Pa_StartStream() -> transitions to Active state
    +Pa_StopStream() -> returns paStreamIsStopped error
    +Pa_AbortStream()-> returns paStreamIsStopped error
    +Pa_IsStreamStopped() -> returns non-zero
    +Pa_IsStreamActive() -> returns zero
    +
    +In the Active state:
    +Pa_StartStream() -> returns paStreamIsNotStopped error
    +Pa_StopStream() -> stops calling the callback and blocks until 
    +	all buffers have been played 
    +	: transitions to Stopped state
    +Pa_AbortStream()-> if possible, discards all queued buffers instead of
    +	 waiting for them to be played, otherwise same as Pa_StopStream() 
    +	: transitions to Stopped state
    +Pa_IsStreamStopped() -> returns zero
    +Pa_IsStreamActive() -> returns non-zero
    +
    +In the Callback Finished state:
    +Pa_StartStream() -> returns paStreamIsNotStopped error
    +Pa_StopStream() -> transitions to Stopped state
    +Pa_AbortStream()-> transitions to Stopped state
    +Pa_IsStreamStopped() -> returns zero
    +Pa_IsStreamActive() -> returns non-zero
    +
    + +

    +Three new constants: paContinue(0), paFinish(1) and paAbort(2) will be defined for use as return values from the callback. Both paFinish and paAbort cause PortAudio to stop calling the callback. paFinish will cause a transition to the Callback Finished state once all buffers have been played, paAbort indicates that PortAudio may to attempt to cancel pending buffers before transitioning to the Callback Finished state. Note that returning any other non-zero value from the callback will have the same effect as returning paFinish, for maximum backwards compatibility. +

    + +
    A Note About Stop and Abort Behavior
    +

    +As the host may buffer samples, it is possible for a perceptible delay to arise between the callback generating samples and them being heard. Sometimes it is desirable to wait for all generated samples to be played before closing a stream - for example when waiting for the end of a soundfile to complete playbeck. At other times it may be desirable to stop the stream as quickly as possible, without necessarily waiting for all queued samples to be played. This latter situation can occur when exiting an application or closing a document - providing good interactive performance to the end-user may necessitate aborting the stream rather than pausing for a significant period waiting for the queued samples to complete. These two use-cases are respectively addressed by the Pa_StopStream() and Pa_AbortStream() functions, and by the paFinish and paAbort callback return values. +

    +

    +It has been noted that not all host APIs support the cancellation of already queued samples or buffers, thus making it impossible to usefully implement Pa_AbortStream. In such cases, Pa_AbortStream() will have the same behavior as Pa_StopStream(), and returning paAbort from the callback will have the behavior as returning paFinish. +

    + + +

    Discussion

    +

    The multi-host-API common infrastructure requires a function like Pa_IsStreamStopped() so that it can automatically call Pa_AbortStream() if Pa_CloseStream() is called on an Active stream. The availability of this state information may also be used to implement error results when actions are not valid for the current stream state (calling Pa_StartStream() on a Active stream for example.)

    + +

    Impact Analysis

    +

    +Clients who currently return 2 from the callback will need to change the callback return value to paFinish to retain the expected behavior. +

    +

    ____________

    Rename Pa_GetCPULoad(), PaDeviceID etc. for Consistency

    Status

    @@ -539,7 +635,7 @@ Pa_GetDefaultOutputDeviceID() -> Pa_GetDefaultOutputDevice()

    The use of the term index in PaDeviceIndex clearly denotes that the types has values within a closed range and may be incremented or decremented to access adjacent values. The ommission of "Index" from paInvalidDevice and the Pa_GetDefault* functions is justified by the fact that the only public representation of a device is its index.

    Impact Analysis

    -

    This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which currently call Pa_GetCPULoad(), Pa_StreamTime(), Pa_StreamActive(), Pa_GetDefaultInputDevice(), or Pa_GetDefaultOutputDevice() will need to alter their code by renaming the function call. Clients who explicitly check for the paInvalidDeviceId error code, or use the PaDeviceID type will have to edit the spelling of these identifiers.

    +

    This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which currently call Pa_GetCPULoad(), Pa_StreamTime(), Pa_StreamActive(), Pa_GetDefaultInputDeviceID(), or Pa_GetDefaultOutputDeviceID() will need to alter their code by renaming the function call. Clients who explicitly check for the paInvalidDeviceId error code, or use the PaDeviceID type will have to edit the spelling of these identifiers.

    ____________

    Additional Pa_Terminate() Behaviour

    Status

    @@ -648,3 +744,4 @@ PaBufferConversionFunction* Pa_GetBufferConversionFunction(

    This proposal only effects PortAudio implementors. Increasing the utility of shared code will improve the quality of all PortAudio implementations in terms of speed, size, and robustness. It should also reduce the effort involved in porting PortAudio to a new host API.

    ____________

    + \ No newline at end of file From 30007cc3c3206b215e04a458e66a528533946764 Mon Sep 17 00:00:00 2001 From: rossbencina Date: Wed, 12 Jun 2002 00:35:49 +0000 Subject: [PATCH 087/814] no message --- docs/proposals.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proposals.html b/docs/proposals.html index 572a875..a945aa8 100644 --- a/docs/proposals.html +++ b/docs/proposals.html @@ -544,7 +544,7 @@ This proposal documents the previously implicit state machine for PortAudio Stre PortAudio streams will function according to the following state machine:

    - +

    A new function Pa_IsStreamStopped() will be added to allow clients to determine whether the Stream is in the Stopped state. From 5e043763c530a3cea0122baf398d0319fb432578 Mon Sep 17 00:00:00 2001 From: rossbencina Date: Wed, 12 Jun 2002 01:15:10 +0000 Subject: [PATCH 088/814] updated modified date --- docs/proposals.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proposals.html b/docs/proposals.html index a945aa8..ea36171 100644 --- a/docs/proposals.html +++ b/docs/proposals.html @@ -21,7 +21,7 @@ name=KeyWords>

    PortAudio Home Page

    -

    Updated: May 22, 2002

    +

    Updated: June 12, 2002

    Introduction

    This document describes modifications to the PortAudio API currently being considered by the developer community. It is intended to capture the current state of discussions. The authors are the various members of the PortAudio community and are too numerous to mention. Please refer to the mailing list archives to see who said what.

    We are still at the design stage with all of these proposals - if you think something is missing, could be improved, or would just like to comment please do so on the PortAudio mailing list.

    From ec3c9aa5b32442724e2673a1e96ac51e37830fcd Mon Sep 17 00:00:00 2001 From: rossbencina Date: Wed, 12 Jun 2002 02:21:27 +0000 Subject: [PATCH 089/814] added initial draft of style guide --- docs/style.html | 156 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 docs/style.html diff --git a/docs/style.html b/docs/style.html new file mode 100644 index 0000000..8f0937c --- /dev/null +++ b/docs/style.html @@ -0,0 +1,156 @@ + + +Coding Style Guidelines for PortAudio Implementors + + + + + +  +
    + + + +
    +
    +

    Coding Style Guidelines for PortAudio Implementors

    +
    +
    +

    PortAudio Home Page

    + +

    Updated: June 12, 2002

    + +

    Introduction

    +

    +This document provides coding guidelines for PortAudio implementors. Some of the guildelines pertain to mechanical style, others to quality of implementation issues. Since the PortAudio code is commonly edited on many different platforms using different editors these guideline should be followed to improve readability and consistency. +

    + +

    PortAudio API Design Guidelines

    +

    +The design guidelines of the PortAudio project are stated here +as some of them apply to implementation as well as to API design. +

    +
      +
    • + Implementation should be possible on all common computer + music platforms. +
    • +
    • + Clients of PortAudio should be able to gain efficient, + and ideally optimal use of the audio services + on all target platforms. +
    • +
    • + The API should be simple enough to be used by music + students with minimal experience in C programming. +
    • +
    • + The API should seek to provide only low-level audio + services, and to only support those services directly + available on the host platform. +
    • +
    + +

    +Note that the final guideline has been bent with regard to audio +sample formats and user buffer sizes - PortAudio can convert between +a number of sample formats and can adapt to the user's buffer size requirements. +

    + +

    Formatting Conventions

    + +

    +The following formatting conventions should be adhered to in all PortAudio code: +

    + +
      +
    • TABs should not be used in .c and .h files; instead 4 spaces should be used. Makefiles should continue to use TABs since this is required by Make
    • +
    • Line-emd characters will be consistent with the platform on which the source has been checked out of CVS (CVS handles this.)
    • +
    • Brace placement will follow ANSI style, eg: +
      +if( aCondition )
      +{
      +	DoSomething();
      +}
      +else
      +{
      +	DoSomethingElse();
      +}
      +
      +
    • +
    + +

    AStyle ( http://astyle.sourceforge.net/ ) has been proposed as helpful tool for cleaning code, however we don't intend to use it on an ongoing basis. It is expected that contributors of each implementation will take responsibility for keeping their code clean.

    + + +

    Quality of Implementation Guidelines

    + +

    The following coding guidelines should be followed in order to establish a quality baseline for our implementations:

    + +
      +
    • All code should be written in C++-compatible plain ANSI-C (i.e. no // comments). It has been suggested that all implementations should compile silently with both "gcc -ansi -pedantic -Wall" and "g++ -ansi -pedantic -Wall"
    • +
    • Think of PortAudio as a heavyweight library rather than a lightweight wrapper. Always code defensively. Efficiency is important where it matters (eg in real-time callbacks) but safety is important everywhere.
    • +
    • All parameters passed to PortAudio by the user should be validated, and error codes returned where necessary. All reasonable efforts should be made to minimise the risk of a crash resulting from passing incorrect parameters to PortAudio.
    • +
    • Error handling should be complete. Every host function that can return an error condition should have its status checked. PortAudio may attempt to recover from errors in some cases, but generally error codes should be returned to the client.
    • +
    • In almost all cases, a PortAudio error code should be preferred to returning PaHostError. If a new PortAudio error code is needed it should be discussed with the maintainer to coordinate updating portaudio.h
    • +
    • PortAudio code should not cause resource leaks. After Pa_Terminate() is called, implementations should guarantee that all dynamically allocated resources have been freed.
    • +
    • The definition of the PortAudio API should minimise "implementation defined behaviour". For example, calling functions such as Pa_Initialize() after PortAudio is initialised, or Pa_Terminate() after PortAudio has been terminated has well defined behaviour.
    • +
    • Minimise dependence on ANSI C runtime on platforms where it would have to be loaded separately (eg on Win32 prefer Win32 API functions such as GlobalAlloc() to ANSI C functions such as malloc().)
    + +

    It has been suggested that we make an effort to minimise the use of global and static data in PortAudio implementations. Another related goal is to reduce name pollution in the global scope. Some possible guidelines in this regard are:

    + +
      +
    • Implementations should avoid exporting any symbols except where absolutely necessary. Specifically, global data must be declared statically. The next section documents naming conventions for all PortAudio symbols.
    • +
    • Implementations should minimise their use of static data.
    + +

    Naming Conventions

    + +
      +
    • All #defines begin with PA_
    • +
    • All #defines local to a file end with _
    • +
    • All global utility variables begin with paUtil
    • +
    • All global utility types begin with PaUtil (including function types)
    • +
    • All global utility functions begin with PaUtil_
    • +
    • All static variables end with _
    • +
    • All static constants begin with const and end with _ (eg: constMyMagicNumber_)
    • +
    • All static funtions have no special prefix/suffix
    • +
    • +Platform-specific shared functions should begin with Pa_ where PN is the +platform name. eg. PaWin_ for windows, PaUnix_ for unix. +
    • +
    + +

    +In general, implementations should declare all of their members static, +except for their initializer which should be exported. All exported names +should be preceeded by Pa_ where is the module name, for example +the windows mme initializer should be named PaWinMme_Initialize(). +

    + +

    +If it is necessary for implementations to define non-static symbols, they should +use the following naming conventions, where is the module name such as WinMme. +

    + +
      +
    • global variables should begin with pa
    • +
    • global types should begin with Pa
    • +
    • global utility functions should begin with Pa_
    • +
    + +

    +Two utilities for debug messages are provided. The PA_DEBUG macro defined in +pa_implementation.h provides a simple way to print debug messages to stderr. +Due to real-time performance issues, PA_DEBUG may not be suitable for use +within the portaudio processing callback, or in other threads. In such cases +the event tracing facility provided in pa_trace.h may be more appropriate. +

    +

    +If PA_LOG_API_CALLS is defined, all calls to the public PortAudio API +will be logged to stderr along with parameter and return values. +

    + + + \ No newline at end of file From 076339299e0e7fbe727c1bb98b62b9641c8b0e5d Mon Sep 17 00:00:00 2001 From: rossbencina Date: Wed, 12 Jun 2002 02:37:00 +0000 Subject: [PATCH 090/814] changed paFinish to paComplete in the stream state proposal --- docs/proposals.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/proposals.html b/docs/proposals.html index ea36171..9b35bb5 100644 --- a/docs/proposals.html +++ b/docs/proposals.html @@ -587,15 +587,15 @@ Pa_IsStreamActive() -> returns non-zero

    -Three new constants: paContinue(0), paFinish(1) and paAbort(2) will be defined for use as return values from the callback. Both paFinish and paAbort cause PortAudio to stop calling the callback. paFinish will cause a transition to the Callback Finished state once all buffers have been played, paAbort indicates that PortAudio may to attempt to cancel pending buffers before transitioning to the Callback Finished state. Note that returning any other non-zero value from the callback will have the same effect as returning paFinish, for maximum backwards compatibility. +Three new constants: paContinue(0), paComplete(1) and paAbort(2) will be defined for use as return values from the callback. Both paComplete and paAbort cause PortAudio to stop calling the callback. paComplete will cause a transition to the Callback Finished state once all buffers have been played, paAbort indicates that PortAudio may to attempt to cancel pending buffers before transitioning to the Callback Finished state. Note that returning any other non-zero value from the callback will have the same effect as returning paComplete, for maximum backwards compatibility.

    A Note About Stop and Abort Behavior

    -As the host may buffer samples, it is possible for a perceptible delay to arise between the callback generating samples and them being heard. Sometimes it is desirable to wait for all generated samples to be played before closing a stream - for example when waiting for the end of a soundfile to complete playbeck. At other times it may be desirable to stop the stream as quickly as possible, without necessarily waiting for all queued samples to be played. This latter situation can occur when exiting an application or closing a document - providing good interactive performance to the end-user may necessitate aborting the stream rather than pausing for a significant period waiting for the queued samples to complete. These two use-cases are respectively addressed by the Pa_StopStream() and Pa_AbortStream() functions, and by the paFinish and paAbort callback return values. +As the host may buffer samples, it is possible for a perceptible delay to arise between the callback generating samples and them being heard. Sometimes it is desirable to wait for all generated samples to be played before closing a stream - for example when waiting for the end of a soundfile to complete playbeck. At other times it may be desirable to stop the stream as quickly as possible, without necessarily waiting for all queued samples to be played. This latter situation can occur when exiting an application or closing a document - providing good interactive performance to the end-user may necessitate aborting the stream rather than pausing for a significant period waiting for the queued samples to complete. These two use-cases are respectively addressed by the Pa_StopStream() and Pa_AbortStream() functions, and by the paComplete and paAbort callback return values.

    -It has been noted that not all host APIs support the cancellation of already queued samples or buffers, thus making it impossible to usefully implement Pa_AbortStream. In such cases, Pa_AbortStream() will have the same behavior as Pa_StopStream(), and returning paAbort from the callback will have the behavior as returning paFinish. +It has been noted that not all host APIs support the cancellation of already queued samples or buffers, thus making it impossible to usefully implement Pa_AbortStream. In such cases, Pa_AbortStream() will have the same behavior as Pa_StopStream(), and returning paAbort from the callback will have the behavior as returning paComplete.

    From 51af47878bce759b1b987a1aae9bfd365896d897 Mon Sep 17 00:00:00 2001 From: rossbencina Date: Wed, 12 Jun 2002 03:02:13 +0000 Subject: [PATCH 091/814] altered isActive and isStopped accessor documentation to say return value of 1 for true instead of non-zero, since other non-zeros may be returned on error --- docs/PaStreamStateDiagram.gif | Bin 9544 -> 9720 bytes docs/proposals.html | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/PaStreamStateDiagram.gif b/docs/PaStreamStateDiagram.gif index b8955b35791c5f840c04e8cfa418fc91c9bb6a59..d1fcae0b6e01e226b8c6d2d096360a7ca5152c1c 100644 GIT binary patch delta 8273 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 Pwby&a*L*dQfB*nHD88*+ delta 8096 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 uqcas5Hnk2Fb<>L~)3>pzIW-ukkJ8gU< transitions to Active state Pa_StopStream() -> returns paStreamIsStopped error Pa_AbortStream()-> returns paStreamIsStopped error -Pa_IsStreamStopped() -> returns non-zero -Pa_IsStreamActive() -> returns zero +Pa_IsStreamStopped() -> returns one (1), or error code +Pa_IsStreamActive() -> returns zero (0), or error code In the Active state: Pa_StartStream() -> returns paStreamIsNotStopped error @@ -575,15 +575,15 @@ Pa_StopStream() -> stops calling the callback and blocks until Pa_AbortStream()-> if possible, discards all queued buffers instead of waiting for them to be played, otherwise same as Pa_StopStream() : transitions to Stopped state -Pa_IsStreamStopped() -> returns zero -Pa_IsStreamActive() -> returns non-zero +Pa_IsStreamStopped() -> returns zero (0), or error code +Pa_IsStreamActive() -> returns one (1), or error code In the Callback Finished state: Pa_StartStream() -> returns paStreamIsNotStopped error Pa_StopStream() -> transitions to Stopped state Pa_AbortStream()-> transitions to Stopped state -Pa_IsStreamStopped() -> returns zero -Pa_IsStreamActive() -> returns non-zero +Pa_IsStreamStopped() -> returns zero (0), or error code +Pa_IsStreamActive() -> returns zero (0), or error code

    From af9a1cd36263d24b4f13e30e5d710e93b816c80d Mon Sep 17 00:00:00 2001 From: pieter Date: Tue, 2 Jul 2002 00:05:23 +0000 Subject: [PATCH 092/814] first time --- testcvs/changeme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt index 2866c3b..9149b25 100644 --- a/testcvs/changeme.txt +++ b/testcvs/changeme.txt @@ -5,4 +5,4 @@ Another tweak. philburk tweak stephane test Phil changed this again on 2/21/02. Yawn... - +pieter test (MacCVS Pro 2.5b2) From 20afdaa194a1b8f7be84bf1f151d1313c877f509 Mon Sep 17 00:00:00 2001 From: pieter Date: Thu, 4 Jul 2002 05:01:05 +0000 Subject: [PATCH 093/814] Fixed multiple user buffers, new test results in Makefile. --- pa_sgi/Makefile | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/pa_sgi/Makefile b/pa_sgi/Makefile index 6548c6c..34fcee6 100644 --- a/pa_sgi/Makefile +++ b/pa_sgi/Makefile @@ -1,5 +1,5 @@ -# Make PortAudio for Silicon Graphics IRIX (6.2) -# Pieter suurmond, september 23, 2001. (pa_sgi sub-version #0.21 for PA v15.) +# Make PortAudio for Silicon Graphics IRIX 6.2 - 6.5. +# Pieter suurmond, july 4, 2002. (for PA v18.) # Based on SGI-specific sproc()-method to spawn children, not on POSIX-threads. # Instead of "-lpthread", as with linux, @@ -15,25 +15,27 @@ CFLAGS = -O2 PASRC = ../pa_common/pa_lib.c pa_sgi.c PAINC = ../pa_common/portaudio.h -# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). -TESTC = $(PASRC) ../pa_tests/patest_record.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_saw.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK -#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. +# Tests that work (on SGI Indy with R5000 @ 180MHz running IRIX 6.2): +#TESTC = $(PASRC) ../pa_tests/patest_record.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_many.c # v18 ok (with PA_MIN_LATENCY_MSEC=250). +#TESTC = $(PASRC) ../pa_tests/patest_latency.c # v18 ok (with PA_MIN_LATENCY_MSEC=250) patest_latency.c contained // +#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # v18 ok (with PA_MIN_LATENCY_MSEC=250). -# Tests that were not yet performed. +TESTC = $(PASRC) ../pa_tests/patest_saw.c # v18 ok (with PA_MIN_LATENCY_MSEC=250). +#TESTC = $(PASRC) ../pa_tests/patest_wire.c # v18 seems ok. + +#TESTC = $(PASRC) ../pa_tests/pa_devs.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_sine.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_pink.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_clip.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_stop.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_dither.c # TODO probably ok. +#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore with v15. + +# Tests that were not yet performed: #TESTC = $(PASRC) ../pa_tests/paqa_devs.c # test?? #TESTC = $(PASRC) ../pa_tests/paqa_errs.c # test?? #TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # test?? From de2eb0e4b9c21e5ca950e332dae9210612c3ac17 Mon Sep 17 00:00:00 2001 From: pieter Date: Thu, 4 Jul 2002 05:01:26 +0000 Subject: [PATCH 094/814] Fixed multiple user buffers per host-transfer. --- pa_sgi/pa_sgi.c | 621 ++++++++++++++++++++++++++---------------------- 1 file changed, 340 insertions(+), 281 deletions(-) diff --git a/pa_sgi/pa_sgi.c b/pa_sgi/pa_sgi.c index f67b1f0..0f56237 100644 --- a/pa_sgi/pa_sgi.c +++ b/pa_sgi/pa_sgi.c @@ -3,9 +3,8 @@ * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk. * Latest Version at: http://www.portaudio.com * - * Silicon Graphics IRIX implementation by Pieter Suurmond, september 23, 2001. - * pa_sgi-sub-version number 0.21, for PortAudio v15. - * This implementation uses the sproc()-method, not the POSIX method. + * Silicon Graphics (SGI) IRIX implementation by Pieter Suurmond. + * This implementation uses sproc()-spawning, not the POSIX-threads. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -30,28 +29,31 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -Modfication History: +MODIFICATIONS: 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. - 8/17/2001 - v15 pa_sgi sub-version #0.04 (unstable alpha release) Sent to Phil & Ross. - 9/23/2001 - #0.21 Many fixes and changes: POLLIN for input, not POLLOUT. - Open and close ALports in the audio-process-thread. - Proper semaphore communication now. - Hopefully stable enough now (for beta release?). + 8/17/2001 - v15, first unstable alpha release for IRIX, sent to Phil & Ross. + 9/23/2001 - Many fixes and changes: POLLIN for input, not POLLOUT! + 7/04/2002 - Implemented multiple user buffers per host buffer to allow clients that + request smaller buffersizes. + + [v18-0.05] Try to use CVS via the Mac now to upload instead of e-mailing to Phil & Ross. + TODO: - - Test under IRIX 6.5. - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), and maybe also the other natively supported formats? (might increase performance) - - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4. + - Implement fancy callback block adapter as described in the PDF by Stephane Letz in the ASIO dir. + - Do some more tests... (see Makefile). + REFERENCES: - IRIX 6.2 man pages regarding SGI AL library. - - IRIS Digital MediaProgramming Guide (online books and man-pages come + - IRIS Digital Media Programming Guide (online books and man-pages come with IRIX 6.2 and may not be publically available on the internet). */ #include /* Standard libraries. */ #include -#include "../pa_common/portaudio.h" /* BETTER PATH !!!???? Portaudio headers. */ +#include "../pa_common/portaudio.h" /* (Makefile fails to find in subdirs, -I doesn't work?). */ #include "../pa_common/pa_host.h" #include "../pa_common/pa_trace.h" @@ -63,47 +65,49 @@ REFERENCES: #include /* For streams, ioctl(), etc. */ #include #include -#include /* System specific (IRIX 6.2). */ +#include /* System specific (IRIX 6.2-6.5). */ -/*--------------------------------------------*/ -#define PRINT(x) { printf x; fflush(stdout); } -#define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) */ -#define DBUGX(x) /* PRINT(x) */ +/*----------------- MACROS --------------------*/ +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) /* PRINT(x) */ +#define DBUGX(x) /* PRINT(x) */ -#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */ -#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */ +#define MAX_CHARS_DEVNAME (16) +#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7. */ + /* Constants used in 'Pa_GetMinNumBuffers()' below: */ +#define MIN_LATENCY_MSEC (200) /* Used if 'getenv("PA_MIN_LATENCY_MSEC")' fails. */ +#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") /* Same names as in file pa_unix.h. */ -typedef struct internalPortAudioDevice /* IRIX specific device info: */ +/*------------------------------- IRIX AL specific device info: --------------------------------------*/ +typedef struct internalPortAudioDevice { - PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ - long pad_ALdevice; /* SGI-number! */ - double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ - char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ - PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ - /* int structVersion; */ - /* const char* name; */ - /* int maxInputChannels, maxOutputChannels; */ - /* int numSampleRates; Num rates, or -1 if range supprtd. */ - /* const double* sampleRates; Array of supported sample rates, */ - /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ - struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ + PaDeviceID pad_DeviceID; /* THIS "ID" IS NEW HERE. */ + long pad_ALdevice; /* SGI-number! */ + double pad_SampleRates[MAX_SAMPLE_RATES]; /* For pointing to from pad_Info */ + char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ + PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ + struct internalPortAudioDevice* pad_Next; /* Singly linked list (NULL=end). */ } internalPortAudioDevice; -typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */ +/*----------------- Structure containing all SGI IRIX specific data: ---------------------------------------*/ +typedef struct PaHostSoundControl { - ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */ - pahsc_ALconfigOUT; /* stucts separate for input and output ports. */ - ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ - pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ - int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ - short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ - *pahsc_NativeOutputBuffer; - unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ - pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ - unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ - pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ - struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ + ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */ + pahsc_ALconfigOUT; /* stucts separate for input and output ports. */ + ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ + pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ + int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ + + unsigned int pahsc_UserBuffersPerHostBuffer, + pahsc_SamplesPerInputHostBuffer, /* Channels per frame are accounted for. */ + pahsc_SamplesPerOutputHostBuffer, + pahsc_BytesPerInputHostBuffer, /* Size per sample are accounted for. */ + pahsc_BytesPerOutputHostBuffer; + short *pahsc_InputHostBuffer, /* Allocated here, in this file, if necessary. */ + *pahsc_OutputHostBuffer; + + struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ pahsc_LastExitTime; long pahsc_InsideCountSum, pahsc_TotalCountSum; @@ -124,62 +128,62 @@ long Pa_GetHostError(void) /* (copied from source pa_linux_oss/pa_linux_oss.c) */ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { - struct itimerval itimer; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; + struct itimerval itimer; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ - getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); + getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); } static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) { - long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; - long usecs = secs * 1000000; - usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); - return usecs; + long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; + long usecs = secs * 1000000; + usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); + return usecs; } static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { - struct itimerval currentTime; - long insideCount; - long totalCount; /* Measure CPU utilization during this callback. */ + struct itimerval currentTime; + long insideCount; + long totalCount; /* Measure CPU utilization during this callback. */ #define LOWPASS_COEFFICIENT_0 (0.95) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if (pahsc == NULL) return; - if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) - { - if (past->past_IfLastExitValid) - { - insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); - pahsc->pahsc_InsideCountSum += insideCount; - totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); - pahsc->pahsc_TotalCountSum += totalCount; - /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ + if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) + { + if (past->past_IfLastExitValid) + { + insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); + pahsc->pahsc_InsideCountSum += insideCount; + totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); + pahsc->pahsc_TotalCountSum += totalCount; + /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ /* Low pass filter the result because sometimes we get called several times in a row. */ /* That can cause the TotalCount to be very low which can cause the usage to appear */ /* unnaturally high. So we must filter numerator and denominator separately!!! */ - if (pahsc->pahsc_InsideCountSum > 0) - { - past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); - past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); - past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; - pahsc->pahsc_InsideCountSum = 0; - pahsc->pahsc_TotalCountSum = 0; - } - } - past->past_IfLastExitValid = 1; - } - pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; - pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; - setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); - past->past_IfLastExitValid = 1; + if (pahsc->pahsc_InsideCountSum > 0) + { + past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); + past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + pahsc->pahsc_InsideCountSum = 0; + pahsc->pahsc_TotalCountSum = 0; + } + } + past->past_IfLastExitValid = 1; + } + pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; + pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; + setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); + past->past_IfLastExitValid = 1; } /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ @@ -247,7 +251,7 @@ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT char* name, /* (for example "SGI AL") */ internalPortAudioDevice* pad) /* Result written to pad. */ { - int format; + int format; long min, max; /* To catch hardware characteristics. */ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ /*--------------------------------------------------------------------------------------*/ @@ -259,22 +263,22 @@ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT return paHostError; } strcpy(pad->pad_DeviceName, name); /* Write name-string. */ - pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ + pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ /*--------------------------------- natively supported sample formats: -----------------*/ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ /* Then also choose other CallConvertXX()! */ /*--------------------------------- number of available i/o channels: ------------------*/ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) return translateSGIerror(); - pad->pad_Info.maxInputChannels = max; - DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) + pad->pad_Info.maxInputChannels = max; + DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) return translateSGIerror(); - pad->pad_Info.maxOutputChannels = max; - DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) + pad->pad_Info.maxOutputChannels = max; + DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) /*--------------------------------- supported samplerates: ----------------------*/ - pad->pad_Info.numSampleRates = 7; - pad->pad_Info.sampleRates = pad->pad_SampleRates; + pad->pad_Info.numSampleRates = 7; + pad->pad_Info.sampleRates = pad->pad_SampleRates; pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ pad->pad_SampleRates[1] = (double)AL_RATE_11025; pad->pad_SampleRates[2] = (double)AL_RATE_16000; @@ -294,7 +298,7 @@ weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",ma return paHostError; /* Or make it a warning and just carry on... */ } /*-------------------------------------------------------------------------------*/ - return paNoError; + return paNoError; } @@ -312,7 +316,7 @@ int Pa_CountDevices() /* Name of this function suggests it only counts and numDevices++; currentDevice = currentDevice->pad_Next; } - return numDevices; + return numDevices; } /*-------------------------------------------------------------------------------*/ @@ -320,7 +324,7 @@ static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) { int numDevices = 0; internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; - internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ + internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ while (pad) /* pad may be NULL, that's ok, return 0. */ { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ if (pad->pad_DeviceID == id) /* This the device we were looking for? */ @@ -337,16 +341,16 @@ static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ #endif } - return res; + return res; } /*----------------------------------------------------------------------*/ const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) { PaDeviceInfo* res = (PaDeviceInfo*)NULL; - internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ + internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ if (pad) - res = &pad->pad_Info; /* Not finding the specified ID is not */ + res = &pad->pad_Info; /* Not finding the specified ID is not */ if (!res) /* the same as &pad->pad_Info == NULL. */ ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); return res; /* So (maybe) a second/third ERR_RPT(). */ @@ -355,12 +359,12 @@ const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultInputDeviceID(void) { - return 0; /* 0 is the default device ID. */ + return 0; /* 0 is the default device ID. */ } /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultOutputDeviceID(void) { - return 0; + return 0; } /*-------------------------------------------------------------------------------------------------*/ @@ -368,7 +372,7 @@ PaDeviceID Pa_GetDefaultOutputDeviceID(void) PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ { internalPortAudioDevice* pad; - PaError r = paNoError; + PaError r = paNoError; int audioLibFileID; /* To test for the presence of audio. */ if (sDeviceList) /* Allow re-init, only warn, no error. */ @@ -384,24 +388,24 @@ PaError PaHost_Init(void) /* Called by Pa_Initializ return paHostError; } close(audioLibFileID); /* Allocate fast mem to hold device info. */ - pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); - if (pad == NULL) + pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); + if (pad == NULL) return paInsufficientMemory; memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ - r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ + r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ "AL default", /* A suitable name. */ pad); /* Write args and queried info into pad. */ - if (r != paNoError) - { + if (r != paNoError) + { ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ - } + PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ + } else sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ /*---------------------------------------------------------------------------------------------*/ - return r; + return r; } /*--------------------------------------------------------------------------------------------*/ @@ -414,10 +418,12 @@ void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_S short evtLoop; /* Reset by parent indirectly, or at local errors. */ PaError result; struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */ - internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument.*/ + internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument. */ PaHostSoundControl *pahsc; - short inputEvent, outputEvent, /* .revents members are of type short. */ - semaEvent = 0; + short n, inputEvent, outputEvent, semaEvent; /* .revents are shorts. */ + short *inBuffer, *outBuffer; /* FIX: Only 16 bit for now, may change... */ + unsigned int samplesPerInputUserBuffer, samplesPerOutputUserBuffer; + DBUG(("Entering sproc-thread.\n")); if (!past) { @@ -426,7 +432,7 @@ void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_S goto skip; } pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (!pahsc) + if (!pahsc) { sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */ ERR_RPT(("past_DeviceData NULL!\n")); @@ -434,7 +440,7 @@ void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_S } /*----------------------------- open AL-ports here, after sproc(): -----------------------*/ if (past->past_NumInputChannels > 0) /* Open input port. */ - { + { pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN); if (!pahsc->pahsc_ALportIN) { @@ -443,9 +449,11 @@ void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_S goto skip; } DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels)); - } + samplesPerInputUserBuffer = pahsc->pahsc_SamplesPerInputHostBuffer / + pahsc->pahsc_UserBuffersPerHostBuffer; + } if (past->past_NumOutputChannels > 0) /* Open output port. */ - { + { pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT); if (!pahsc->pahsc_ALportOUT) { @@ -454,9 +462,12 @@ void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_S goto skip; /* same for IN and OUT in case */ } /* both ports are opened (bidir). */ DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels)); - } + samplesPerOutputUserBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer / + pahsc->pahsc_UserBuffersPerHostBuffer; + DBUG(("samplesPerOutputUserBuffer = %d\n", samplesPerOutputUserBuffer)); + } /*-----------------------------------------------------------------------*/ - past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ + past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */ PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */ PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT); @@ -469,26 +480,26 @@ void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_S while (evtLoop) { /*---------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ----------*/ - if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */ + if (pahsc->pahsc_InputHostBuffer) /* Then pahsc_ALportIN should also be there! */ /* For input port, fill point is number of locations in the sample queue that must be */ /* filled in order to trigger a return from select(). (or poll()) */ /* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/ - if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputBuffer)) - { /* Same amount as transferred per time. */ + if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputHostBuffer)) + { /* Multiple amount as transferred per time. */ ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n")); sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ goto skip; } - if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */ + if (pahsc->pahsc_OutputHostBuffer) /* Then pahsc_ALportOUT should also be there! */ /* For output port, fill point is number of locations that must be free in order to */ /* wake up from select(). (or poll()) */ - if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputBuffer)) + if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputHostBuffer)) { ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n")); sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ goto skip; } /* poll() with timeout=-1 makes it block until a requested */ - poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */ + poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */ /* array <0, events is ignored and revents is set to 0. */ /*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/ semaEvent = PollFD[kPollSEMA].revents & POLLIN; @@ -498,13 +509,13 @@ void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_S evtLoop = 0; if (past->past_StopNow) goto skip; - } + } /*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/ inputEvent = PollFD[kPollIN].revents & POLLIN; - if (inputEvent) /* Don't need to check (pahsc->pahsc_NativeInputBuffer): */ + if (inputEvent) /* Don't need to check (pahsc->pahsc_InputHostBuffer): */ { /* if buffer was not there, ALport not there, no events! */ - if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer, - pahsc->pahsc_SamplesPerInputBuffer)) + if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_InputHostBuffer, + pahsc->pahsc_SamplesPerInputHostBuffer)) { /* Here again: number of samples instead of number of frames. */ ERR_RPT(("ALreadsamps() failed.\n")); sPaHostError = paInternalError; @@ -516,28 +527,31 @@ void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_S if (inputEvent | outputEvent) /* (Bitwise is ok.) */ { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */ /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */ - Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ - result = Pa_CallConvertInt16(past, /* user data and call user routine. */ - pahsc->pahsc_NativeInputBuffer, - pahsc->pahsc_NativeOutputBuffer); - Pa_EndUsageCalculation(past); - if (result) - { - DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); - goto skip; /* This is apparently NOT an error! */ - } /* Just letting the userCallBack stop us. */ + Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ + /* user data and call user routine. */ + inBuffer = pahsc->pahsc_InputHostBuffer; /* Short pointers for now, care! */ + outBuffer = pahsc->pahsc_OutputHostBuffer; + n = pahsc->pahsc_UserBuffersPerHostBuffer; /* 'n' may never start at NULL ! */ + do { + result = Pa_CallConvertInt16(past, inBuffer, outBuffer); + if (result) /* This is apparently NOT an error! Just letting the userCallBack stop us. */ + { DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); goto skip; } + inBuffer += samplesPerInputUserBuffer; /* Num channels is accounted for. */ + outBuffer += samplesPerOutputUserBuffer; + } while (--n); + Pa_EndUsageCalculation(past); } /*------------------------------------- FREE-EVENT FROM OUTPUT BUFFER: ---------------------------*/ - if (outputEvent) /* Don't need to check (pahsc->pahsc_NativeOutputBuffer) */ + if (outputEvent) /* Don't need to check (pahsc->pahsc_OutputHostBuffer) */ { /* because if filedescriptor not there, no event for it. */ - if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer, - pahsc->pahsc_SamplesPerOutputBuffer)) + if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_OutputHostBuffer, + pahsc->pahsc_SamplesPerOutputHostBuffer)) { ERR_RPT(("ALwritesamps() failed.\n")); /* Better use SEMAS for messaging back to parent! */ sPaHostError = paInternalError; goto skip; } - } + } } skip: /*------------------------------- close AL-ports ----------------------------*/ @@ -559,64 +573,79 @@ skip: if (semaEvent) { uspsema(SendSema); /* StopEngine() was still waiting for this acknowledgement. */ - usvsema(RcvSema); /* (semaEvent initialized with 0.) */ + usvsema(RcvSema); /* (semaEvent initialized with 0.) */ } DBUG(("Leaving sproc-thread.\n")); } -#define kALinternalQueuesizeFact 4L /* Internal queue 4 times as large as transferSize. */ - /* Used below, twice: for input and for output. */ /*--------------------------------------------------------------------------------------*/ PaError PaHost_OpenStream(internalPortAudioStream *past) { - PaError result = paNoError; - PaHostSoundControl *pahsc; - unsigned int minNumBuffers; - internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ - long pvbuf[8]; /* To get/set hardware configs. */ - long sr; + PaError result = paNoError; + PaHostSoundControl *pahsc; + unsigned int minNumBuffers; + internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ + long pvbuf[8], sr, alq; /* To get/set hardware configs. */ + DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ if (!past) { ERR_RPT(("Streampointer NULL!\n")); - result = paBadStreamPtr; goto done; + result = paBadStreamPtr; goto done; } - pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); - if (pahsc == NULL) - { - ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ - result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ - } - memset(pahsc, 0, sizeof(PaHostSoundControl)); + pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); + if (pahsc == NULL) + { + ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ + result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ + } + memset(pahsc, 0, sizeof(PaHostSoundControl)); pahsc->pahsc_threadPID = -1; /* Should pahsc_threadPID be inited to */ - past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ + past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ pvbuf[0] = AL_INPUT_RATE; pvbuf[2] = AL_INPUT_COUNT; pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ pvbuf[6] = AL_OUTPUT_COUNT; - sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */ - /*---------------------------------------------------- SET INPUT CONFIGURATION: ------------------------*/ + sr = (long)(past->past_SampleRate + 0.5); /* Common for both input and output :-) */ + /*-----------------------------------------------------------------------------*/ + /* OVERWRITE 'past_NumUserBuffers'-field in the struct supplied by the caller. */ + /* This field may be set to zero by a client application to ask for minimum */ + /* latency. It is used below, to set both input- and output-AL-queuesizes. */ + minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, + past->past_SampleRate); /* Take biggest. */ + past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ? + minNumBuffers : past->past_NumUserBuffers; + DBUG(("past->past_NumUserBuffers=%d\n", past->past_NumUserBuffers)); + /*----------------------------------------------------------------------------------*/ + pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers >> 1; + DBUG(("pahsc_UserBuffersPerHostBuffer=%d\n",pahsc->pahsc_UserBuffersPerHostBuffer)); + /* 1 is minimum because Pa_GetMinNumBuffers() returns >= 2. + Callback will be called 'pahsc_UserBuffersPerHostBuffer' times (with 'past_FramesPerUserBuffer') + per host transfer. */ + /*---------------------------------------------------- SET INPUT CONFIGURATION: ---------------------*/ if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ { /* sponding native AL-number(s). */ - /*--------------------------------------------------- Allocate native buffers: --------*/ - pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumInputChannels; /* audio-thread. */ - pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); - pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer); - if (!pahsc->pahsc_NativeInputBuffer) - { + /*--------------------------------------------------- Allocate native buffers: --------------*/ + pahsc->pahsc_SamplesPerInputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * + past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumInputChannels; /* audio-thread. */ + DBUG(("pahsc_SamplesPerInputHostBuffer=%d\n", pahsc->pahsc_SamplesPerInputHostBuffer)); + pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_SamplesPerInputHostBuffer * sizeof(short); + pahsc->pahsc_InputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer); + if (!pahsc->pahsc_InputHostBuffer) + { ERR_RPT(("Fast memory allocation failed (in).\n")); - result = paInsufficientMemory; + result = paInsufficientMemory; goto done; - } + } padIN = Pa_GetInternalDevice(past->past_InputDeviceID); if (!padIN) { ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); - result = paHostError; + result = paHostError; goto done; } if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ @@ -626,7 +655,7 @@ PaError PaHost_OpenStream(internalPortAudioStream *past) if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ { ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ -another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); +another process is currently using input at %ld Hz.\n", sr, pvbuf[1])); result = paHostError; goto done; } @@ -646,33 +675,34 @@ another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); goto sgiError; if (ALsetfloatmax (pahsc_ALconfigIN, 1.0)) Only meaningful when sample format for config goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ - /*--------- Set internal AL queuesize (in samples) -------------------------------*/ - if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, (long)pahsc->pahsc_SamplesPerInputBuffer * - (long)kALinternalQueuesizeFact)) - goto sgiError; /* Or should we use past_NumUserBuffers here? */ - /* Do 4 timea, using 2 times may give glitches. */ + /*--------- Set internal AL queuesize (in samples, not in frames!) -------------------------------*/ + alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumInputChannels; + DBUG(("AL input queuesize = %ld samples.\n", alq)); + if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, alq)) + goto sgiError; if (ALsetchannels (pahsc->pahsc_ALconfigIN, (long)(past->past_NumInputChannels))) goto sgiError; /* Returns 0 on success, -1 on failure. */ } /*---------------------------------------------------- SET OUTPUT CONFIGURATION: ------------------------*/ if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ - { /* We use padOUT/IN later on, or at least 1 of both. */ - pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumOutputChannels; /* audio-thread. */ - pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); - - pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer); - if (!pahsc->pahsc_NativeOutputBuffer) - { + { /* We use padOUT/IN later on, or at least 1 of both. */ + pahsc->pahsc_SamplesPerOutputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * + past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumOutputChannels; /* audio-thread. */ + DBUG(("pahsc_SamplesPerOutputHostBuffer=%d\n", pahsc->pahsc_SamplesPerOutputHostBuffer)); + pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer * sizeof(short); + pahsc->pahsc_OutputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer); + if (!pahsc->pahsc_OutputHostBuffer) + { ERR_RPT(("Fast memory allocation failed (out).\n")); - result = paInsufficientMemory; + result = paInsufficientMemory; goto done; - } + } padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); if (!padOUT) { ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); - result = paHostError; + result = paHostError; goto done; } if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) @@ -682,7 +712,7 @@ another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ { ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ -another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); +another process is currently using output at %ld Hz.\n", sr, pvbuf[5])); result = paHostError; goto done; /* Will free again the inputbuffer */ } /* that was just created above. */ @@ -690,29 +720,25 @@ another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) goto sgiError; } - pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */ + pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */ if (pahsc->pahsc_ALconfigOUT == (ALconfig)0) goto sgiError; - if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ + if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ + goto sgiError; + if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */ + goto sgiError; /* config is set to two's complement format. */ + /** Future versions might (dynamically) switch to 32-bit floats. **/ + alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumOutputChannels; + DBUG(("AL output queuesize = %ld samples.\n", alq)); + if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, alq)) goto sgiError; - if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */ - goto sgiError; /* config is set to two's complement format. */ - /************************************ Future versions might (dynamically) switch to 32-bit floats? *******/ - if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, (long)pahsc->pahsc_SamplesPerOutputBuffer * - (long)kALinternalQueuesizeFact)) - goto sgiError; /* Or should we use past_NumUserBuffers here?*/ if (ALsetchannels (pahsc->pahsc_ALconfigOUT, (long)(past->past_NumOutputChannels))) goto sgiError; } - /*---------- ?? --------------------*/ - /* 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; /* I don't yet use past_NumUserBuffers */ /*----------------------------------------------- TEST DEVICE ID's: --------------------*/ - if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */ - (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) - { + if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */ + (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) + { ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); result = paHostError; goto done; @@ -729,17 +755,17 @@ done: /*-----------------------------------------------------*/ PaError PaHost_StartOutput(internalPortAudioStream *past) { - return paNoError; /* Hmm, not implemented yet? */ + return paNoError; /* Hmm, not implemented yet? */ } PaError PaHost_StartInput(internalPortAudioStream *past) { - return paNoError; + return paNoError; } /*------------------------------------------------------------------------------*/ PaError PaHost_StartEngine(internalPortAudioStream *past) { - PaHostSoundControl *pahsc; + PaHostSoundControl *pahsc; usptr_t *arena; if (!past) /* Test argument. */ { @@ -752,8 +778,8 @@ PaError PaHost_StartEngine(internalPortAudioStream *past) ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n")); return paHostError; } - past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ - past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */ + past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ + past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */ past->past_IsActive = 1; /* Although the pthread_create() function, as well as , may be */ @@ -796,10 +822,10 @@ PaError PaHost_StartEngine(internalPortAudioStream *past) /*------------------------------------------------------------------------------*/ PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) { - int hres; - long timeOut; - PaError result = paNoError; - PaHostSoundControl *pahsc; + int hres; + long timeOut; + PaError result = paNoError; + PaHostSoundControl *pahsc; DBUG(("PaHost_StopEngine() called.\n")); if (!past) @@ -825,8 +851,8 @@ PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) } #if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */ - if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */ - { + if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */ + { DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n")); if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */ { /* Returns -1 in case of error. */ @@ -836,33 +862,33 @@ PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) } else pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */ - } + } #endif past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */ - return result; + return result; } /*---------------------------------------------------------------*/ PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) { - return paNoError; /* Not implemented yet? */ + return paNoError; /* Not implemented yet? */ } PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) { - return paNoError; + return paNoError; } /*******************************************************************/ PaError PaHost_CloseStream(internalPortAudioStream *past) { - PaHostSoundControl *pahsc; + PaHostSoundControl *pahsc; PaError result = paNoError; DBUG(("PaHost_CloseStream() called.\n")); - if (!past) + if (!past) return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ return result; /* This test prevents from freeing NULL-pointers. */ if (pahsc->pahsc_ALconfigIN) @@ -875,68 +901,101 @@ PaError PaHost_CloseStream(internalPortAudioStream *past) ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */ pahsc->pahsc_ALconfigOUT = NULL; } - if (pahsc->pahsc_NativeInputBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer); - pahsc->pahsc_NativeInputBuffer = NULL; - } - if (pahsc->pahsc_NativeOutputBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); - pahsc->pahsc_NativeOutputBuffer = NULL; - } - PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); + if (pahsc->pahsc_InputHostBuffer) + { + PaHost_FreeFastMemory(pahsc->pahsc_InputHostBuffer, pahsc->pahsc_BytesPerInputHostBuffer); + pahsc->pahsc_InputHostBuffer = NULL; + } + if (pahsc->pahsc_OutputHostBuffer) + { + PaHost_FreeFastMemory(pahsc->pahsc_OutputHostBuffer, pahsc->pahsc_BytesPerOutputHostBuffer); + pahsc->pahsc_OutputHostBuffer = NULL; + } + PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */ - return result; + 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 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. -*/ -#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") -int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) +/*------------------------------------------------------------------------*/ +/* Determine minimum number of buffers required for (SGI) host based on */ +/* minimum latency. Latency can be optionally set by user by setting an */ +/* environment variable. For example, to set my latency to 200 msec, I've */ +/* put this line in my '.cshrc' file: setenv PA_MIN_LATENCY_MSEC 200 */ +/* It always calls the 'PRINT' macro. */ +/* The minimum number that is returned is 2. */ +/* This number is directly proportional to the AL-queue sizes to set up. */ +/* It is one more than the number of user buffers per host buffer - in */ +/* case minimum is returned, or, twice the user buffers per host buffer. */ +/*------------------------------------------------------------------------*/ +int Pa_GetMinNumBuffers(int framesPerUserBuffer, double framesPerSecond) { - return 2; + int minBuffers, minLatencyMsec; + char *minLatencyText; + double actualLatency; + + minLatencyText = getenv(PA_LATENCY_ENV_NAME); /* Defined at top of file. */ + if (minLatencyText) + { + minLatencyMsec = atoi(minLatencyText); + if (minLatencyMsec < 10) + { /* 10 is the minimum. */ + minLatencyMsec = 10; + PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' below minimum of %d milliseconds.\n", + minLatencyMsec)); + } + else if (minLatencyMsec > 4000) + { /* 4000 is the maximum. */ + minLatencyMsec = 4000; + PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' above maximum of %d milliseconds.\n", + minLatencyMsec)); + } + else + PRINT (("Using environment variable 'PA_MIN_LATENCY_MSEC' (set to %d milliseconds).\n", + minLatencyMsec)); + } + else + { + minLatencyMsec = MIN_LATENCY_MSEC; /* Defined at top of this file. */ + PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' not found.\nUsing default of %d milliseconds\n", + minLatencyMsec)); + } + minBuffers = (int)((minLatencyMsec * framesPerSecond) / + (1000.0 * framesPerUserBuffer)); + if (minBuffers < 2) + minBuffers = 2; + actualLatency = 1000.0 * minBuffers * framesPerUserBuffer / framesPerSecond; + PRINT (("Actual AL latency set to %.2f milliseconds\n", actualLatency)); + return minBuffers; } -/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */ -/* Do we HAVE to do it this way under IRIX???.... */ -/*--------------------------------------------------------------*/ - /*---------------------------------------------------------------------*/ PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ { /* Called by Pa_Terminate() from pa_lib.c. */ - internalPortAudioDevice *pad = sDeviceList, + internalPortAudioDevice *pad = sDeviceList, *nxt; - while (pad) - { - DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); + while (pad) + { + DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); nxt = pad->pad_Next; - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); - pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ - } - sDeviceList = (internalPortAudioDevice*)NULL; - return 0; /* Got rid of sNumDevices=0; */ + PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); + pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ + } + sDeviceList = (internalPortAudioDevice*)NULL; + return 0; /* Got rid of sNumDevices=0; */ } /***********************************************************************/ void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ { #if 0 - struct timeval timeout; - timeout.tv_sec = msec / 1000; - timeout.tv_usec = (msec % 1000) * 1000; - select(0, NULL, NULL, NULL, &timeout); + 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 ); + long usecs = msec * 1000; + usleep( usecs ); #endif } @@ -946,8 +1005,8 @@ void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ /* a call to PaHost_FreeFastMemory(). */ void *PaHost_AllocateFastMemory(long numBytes) { - void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */ - if (addr) /* range and locks the pages into memory. A counter */ + void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */ + if (addr) /* range and locks the pages into memory. A counter */ { /* is incremented each time the page is locked. The */ if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */ { /* others are limited to the configurable PLOCK_MA. */ @@ -959,7 +1018,7 @@ void *PaHost_AllocateFastMemory(long numBytes) } /* call at PaHost_FreeFastMemory(), below. */ memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */ } /* a child process after a fork. Furthermore, IRIX- */ - return addr; /* man-pages warn against mixing both mpin and mlock */ + return addr; /* man-pages warn against mixing both mpin and mlock */ } /* in 1 piece of code, so stick to mpin()/munpin() ! */ @@ -968,7 +1027,7 @@ void *PaHost_AllocateFastMemory(long numBytes) /* call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory(void *addr, long numBytes) { - if (addr) + if (addr) { if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */ ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n")); @@ -979,21 +1038,21 @@ void PaHost_FreeFastMemory(void *addr, long numBytes) /*----------------------------------------------------------*/ PaError PaHost_StreamActive( internalPortAudioStream *past ) { - PaHostSoundControl *pahsc; - if (past == NULL) + PaHostSoundControl *pahsc; + if (past == NULL) return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if (pahsc == NULL) return paInternalError; - return (PaError)(past->past_IsActive != 0); + return (PaError)(past->past_IsActive != 0); } /*-------------------------------------------------------------------*/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { - internalPortAudioStream *past = (internalPortAudioStream *) stream; + internalPortAudioStream *past = (internalPortAudioStream *) stream; /* FIXME - return actual frames played, not frames generated. ** Need to query the output device somehow. */ - return past->past_FrameCount; + return past->past_FrameCount; } From df554d47e3872c5e03337bb4803885f5e8505fa7 Mon Sep 17 00:00:00 2001 From: pieter Date: Thu, 4 Jul 2002 05:05:34 +0000 Subject: [PATCH 095/814] Changed some C++ comments (//) to C comments (/**/). --- pa_tests/patest_latency.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pa_tests/patest_latency.c b/pa_tests/patest_latency.c index 66820bc..30c8160 100644 --- a/pa_tests/patest_latency.c +++ b/pa_tests/patest_latency.c @@ -56,7 +56,7 @@ #define TABLE_SIZE (400) typedef struct { - float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation + float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */ float phase_increment; float left_phase; float right_phase; @@ -117,7 +117,7 @@ int main(void) { data.sine[i] = 0.90f * (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); } - data.sine[TABLE_SIZE] = data.sine[0]; // set guard point + data.sine[TABLE_SIZE] = data.sine[0]; /* set guard point */ data.left_phase = data.right_phase = 0.0; data.phase_increment = CalcPhaseIncrement(MIN_FREQ); From 97f637b143c0104a5012df3dfb61b7fa44b73ca2 Mon Sep 17 00:00:00 2001 From: dmazzoni Date: Mon, 15 Jul 2002 00:36:04 +0000 Subject: [PATCH 096/814] Added an autoconf-based configure/make system -DMM --- Makefile.in | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ config.guess | Bin 0 -> 38293 bytes config.sub | Bin 0 -> 28332 bytes configure | Bin 0 -> 81108 bytes configure.in | 55 ++++++++++++++++++++++++++++++ install-sh | Bin 0 -> 5598 bytes 6 files changed, 148 insertions(+) create mode 100644 Makefile.in create mode 100755 config.guess create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100755 install-sh diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..6b47156 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,93 @@ +# +# PortAudio Makefile.in +# +# Dominic Mazzoni +# + +CC = @CC@ +CFLAGS = @CFLAGS@ -Ipa_common +LIBS = @LIBS@ +AR = @AR@ +RANLIB = @RANLIB@ +INSTALL = @INSTALL@ +PREFIX = @prefix@ + +OTHER_OBJS = @OTHER_OBJS@ + +PALIB = libportaudio.a +PADLL = libportaudio.so +PADLLV = libportaudio.so.0.0.18 +PAINC = pa_common/portaudio.h + +COMMON_OBJS = \ + pa_common/pa_convert.o \ + pa_common/pa_lib.o + +TESTS = \ + bin/patest_buffer \ + bin/patest_clip \ + bin/patest_dither \ + bin/patest_hang \ + bin/patest_latency \ + bin/patest_leftright \ + bin/patest_longsine \ + bin/patest_many \ + bin/patest_maxsines \ + bin/patest_multi_sine \ + bin/patest_pink \ + bin/patest_record \ + bin/patest_ringmix \ + bin/patest_saw \ + bin/patest_sine8 \ + bin/patest_sine \ + bin/patest_sine_formats \ + bin/patest_sine_time \ + bin/patest_stop \ + bin/patest_sync \ + bin/patest_toomanysines \ + bin/patest_underflow \ + bin/patest_wire + +OBJS = $(COMMON_OBJS) $(OTHER_OBJS) + +all: lib/$(PALIB) lib/$(PADLLV) tests + +tests: bin/ $(TESTS) + +lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC) + $(AR) ruv lib/$(PALIB) $(OBJS) + $(RANLIB) lib/$(PALIB) + +lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC) + $(CC) -shared -o lib/$(PADLLV) $(OBJS) + +$(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c + $(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS) + +install: lib/$(PALIB) lib/$(PADLLV) + $(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PADLLV) + $(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB) + cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL) + $(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h + @echo "" + @echo "------------------------------------------------------------" + @echo "PortAudio was successfully installed." + @echo "" + @echo "On some systems (e.g. Linux) you should run 'ldconfig' now" + @echo "to make the shared object available. You may also need to" + @echo "modify your LD_LIBRARY_PATH environment variable to include" + @echo "the directory $(PREFIX)/lib" + @echo "------------------------------------------------------------" + @echo "" + +clean: + rm -f $(OBJS) $(TESTS) lib/$(PALIB) + +%.o: %.c Makefile $(PAINC) + $(CC) -c $(CFLAGS) $< -o $@ + +bin: + mkdir bin + +lib: + mkdir lib diff --git a/config.guess b/config.guess new file mode 100755 index 0000000000000000000000000000000000000000..297e5c30f41b65e95341322c77994c4d1d447134 GIT binary patch literal 38293 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 U)O!4AX9|J+poD;K<7?sn03Xu03;+NC literal 0 HcmV?d00001 diff --git a/config.sub b/config.sub new file mode 100755 index 0000000000000000000000000000000000000000..791bcded7c3bf807b4ecb7521fcd2ef9ad175b2c GIT binary patch literal 28332 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 GJO3Y7hsiGh literal 0 HcmV?d00001 diff --git a/configure b/configure new file mode 100755 index 0000000000000000000000000000000000000000..a06d81d8790a7bb252dd78f6028e5b897e899255 GIT binary patch literal 81108 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 literal 0 HcmV?d00001 diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..5abd189 --- /dev/null +++ b/configure.in @@ -0,0 +1,55 @@ +dnl +dnl PortAudio configure.in script +dnl +dnl Dominic Mazzoni +dnl + +dnl Require autoconf >= 2.13 +AC_PREREQ(2.13) + +dnl Init autoconf and make sure configure is being called +dnl from the right directory +AC_INIT([pa_common/portaudio.h]) + +dnl Checks for programs +AC_PROG_CC +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_PATH_PROG(AR, ar, no) +if [[ $AR = "no" ]] ; then + AC_MSG_ERROR("Could not find ar - needed to create a library"); +fi + +dnl Extra variables we want to substitute +AC_SUBST(OTHER_OBJS) +TARGETS="tests" + +dnl Determine the host operating system / platform +AC_CANONICAL_HOST + +case "${host_os}" in + darwin* ) + dnl Mac OS X configuration + + OTHER_OBJS="pa_mac_core/pa_mac_core.o"; + LIBS="-lm"; + ;; + + *) + dnl Unix OSS configuration + + AC_CHECK_LIB(pthread, pthread_create, + , + AC_MSG_ERROR([libpthread not found!])) + + OTHER_OBJS="pa_unix_oss/pa_unix_oss.o"; + LIBS="-lm -lpthread"; +esac + +AC_OUTPUT([Makefile]) + +echo "" +echo "Finished configure." + +echo "" +echo "Type 'make' to build PortAudio and examples." diff --git a/install-sh b/install-sh new file mode 100755 index 0000000000000000000000000000000000000000..e9de23842dcd44d2953129c866b1ad25f7e1f1d9 GIT binary patch literal 5598 zcmbVQZExH*68^mU6_fR*TL=3RUoUsp7zToC(AGFO3GCo{K#`oe5_iQ~5(Sa+W|8K< z-!nr}yH1>@xd6e+A~`S5%seyH(Szm6G)q@zN7)gX#(7m$G#{Q6wVmB`s-BU{JJb3Z z*^Ub3)!I}VM_!l4QEqGPXx-VG{&RA2`Gmf$jbHZORLgM6Eu-j#D~}hV>j&HJIbGnmot zW>nk4tnphI=R32)=^3e}AgAG(XLFrh`>pDC)*8|Q(XA=))|bjd7(1d?_Ew8U!O6yYljC*UYSjT=Vw_>H z0dQ;`AElM`WfH>9+&wD0U`o69{1d6JZ(G}W(`-I=Du5tr*uF;9g6hTMeDQig5JW4@ zFcxB5ajPN4K@Q>#QEk7fOl~|d!GbakuK@P}WQGkvV$lP<2_)C*+^kJLgP?6^yw?pd zGXQz-%7Q4GQmY$a(pc(r+i91A0+?2eI5a?v>y1|{Q?W&&_Asm;g%6_7J;!i}(^xtD zJ!W%a9Q8Za@#)1U^3QrB0hc=Apo0fDR{E-%WVR00ypQVPtljBN=Bfdq0GegUfs$mAoz zSSiX-dAyGDY$10AiR`Zg>7Q56lZiuRqgLRxOEH2T(Fj4x=VgE~SBP^{?S{j)(ZN{c zuOe@1E;q!Ei!bMDf*4n#+CtG#&4u;yYKjO%wuubm7Fou7wWsGV&tJc~eEAathpM;y z>md=AbDRZz-uv7(Q_o3DPv?YWMS=Zw@g2LyC51vmAUkMBLSZvg_A=gQfNnFq*~uysv4+eaCtLTLm2nm6J#@)(;=IeFL?-P|tdR(0%9 zeaqglo{N98NAvm?dh#~C{o$3o&0Bt3g1UxAMe zu|NNG86}r^jb#qUuzdCU@;ofdYbzl%KY2o5u&(AMqO1l=|#W5H$=<;2!zp%SLCUHM%Na3f+Uq03I zS(TQBB+MrA$PxQGAsZHwz=n{RN?#|$9n(HalOf?g_2n*R{_N2)4VlC_b1gNGF#HZS zC}`@IbAPs6POra!=jx86At&zW8ML5(p99MI86y@i!o z$P+^3JP=EdKnpcZ7;z87Kgf)h1hY5=j_7=S=NK|t4ftWm z=6P1;QZ&^ex409W#+HfpyK`RG5HSoewYqg_BBgP1k zDlos}l0g{%O+H|o5^VsKb25OjyiWBmK!Q3xc24|@<;pY@bA@!>R|?YxCoj7ylX6NV zD8Q@4P@Ls~qvjekHT(7L^39{kYCB9|7u&SgVk-!Dg8>3Wx!}*Uqg_Oeq>FUO`zzkO@49VEwWuz3e z*}LBL3bzn6y+x?@2b`n=AOwwv3NG|o^_4&W@#<_k%BC4VV5Gs%eDZ$3_7nt;FcGpyA88a!E{5_R6=o>}2e!z~A29FRF&IYJ7J z-3~ktkPc^ODT#!U`&usmX}TTCWL!m9k41;YVCOb27?5D zW5Q` Date: Mon, 15 Jul 2002 00:50:44 +0000 Subject: [PATCH 097/814] Fixed the configure/make scripts to work on Mac OS X --- Makefile.in | 9 +++++---- configure | Bin 81108 -> 41084 bytes configure.in | 9 +++++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Makefile.in b/Makefile.in index 6b47156..e948d74 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,19 +4,20 @@ # Dominic Mazzoni # +PREFIX = @prefix@ CC = @CC@ CFLAGS = @CFLAGS@ -Ipa_common LIBS = @LIBS@ AR = @AR@ RANLIB = @RANLIB@ INSTALL = @INSTALL@ -PREFIX = @prefix@ +SHARED_FLAGS = @SHARED_FLAGS@ OTHER_OBJS = @OTHER_OBJS@ PALIB = libportaudio.a -PADLL = libportaudio.so -PADLLV = libportaudio.so.0.0.18 +PADLL = @PADLL@ +PADLLV = $(PADLL).0.0.18 PAINC = pa_common/portaudio.h COMMON_OBJS = \ @@ -59,7 +60,7 @@ lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC) $(RANLIB) lib/$(PALIB) lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC) - $(CC) -shared -o lib/$(PADLLV) $(OBJS) + $(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c $(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS) diff --git a/configure b/configure index a06d81d8790a7bb252dd78f6028e5b897e899255..5472eb3342c7f51b24aee1531707683cefa3e4f1 100755 GIT binary patch literal 41084 zcmeHwZF>_(vi4{6D>}lCz-vjEKz1=v7RQ*EvjliB$!6CATb9PM7D=OMB(N8Je*1IZ zRn?m5@FmITzV)zxp+Rn=8JSHE)2e`79lEW`k~L zI6QarY%uOiS~ne^xVOnP8>C}*v$6G!L$%#>ay}jOPiOAh?sd0y=g!Sdcjp`Yy@kKG z@%LNzV45UuKRubf>r4~(Af1nUfS!&w-Q#f=O#{ly(?RA4f6$+!OxB$aCNqb$6V}bF z?p-%K1%MUc0H!~9iyqF$!@+34o=lSIXpjlMvlQ?r=bNrK$Y#^Q@f`i

    j;v;N;v5 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≶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 diff --git a/configure.in b/configure.in index 5abd189..8b3a1e2 100644 --- a/configure.in +++ b/configure.in @@ -22,7 +22,8 @@ fi dnl Extra variables we want to substitute AC_SUBST(OTHER_OBJS) -TARGETS="tests" +AC_SUBST(PADLL) +AC_SUBST(SHARED_FLAGS) dnl Determine the host operating system / platform AC_CANONICAL_HOST @@ -32,7 +33,9 @@ case "${host_os}" in dnl Mac OS X configuration OTHER_OBJS="pa_mac_core/pa_mac_core.o"; - LIBS="-lm"; + LIBS="-framework CoreAudio -lm"; + PADLL="libportaudio.dylib"; + SHARED_FLAGS="-framework CoreAudio -dynamiclib"; ;; *) @@ -44,6 +47,8 @@ case "${host_os}" in OTHER_OBJS="pa_unix_oss/pa_unix_oss.o"; LIBS="-lm -lpthread"; + PADLL="libportaudio.so"; + SHARED_FLAGS="-shared"; esac AC_OUTPUT([Makefile]) From 7ecb7f4ace17ade6c0f4b69363dfa49e5776188f Mon Sep 17 00:00:00 2001 From: dmazzoni Date: Sat, 20 Jul 2002 00:01:35 +0000 Subject: [PATCH 098/814] Added Bill Eldridge's changes to get it to work on MingW. --- Makefile.in | 3 ++- configure | Bin 41084 -> 81487 bytes configure.in | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index e948d74..7acc5a5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -12,6 +12,7 @@ AR = @AR@ RANLIB = @RANLIB@ INSTALL = @INSTALL@ SHARED_FLAGS = @SHARED_FLAGS@ +DLL_LIBS = @DLL_LIBS@ OTHER_OBJS = @OTHER_OBJS@ @@ -60,7 +61,7 @@ lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC) $(RANLIB) lib/$(PALIB) lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC) - $(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) + $(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(DLL_LIBS) $(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c $(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS) diff --git a/configure b/configure index 5472eb3342c7f51b24aee1531707683cefa3e4f1..4d5ee9502e27f5a4ad4bb10f9c9250c07a206877 100755 GIT binary patch literal 81487 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%0AIlnp@&>Pf6PYk2!%5ZFZ$3G>hH9> zU5y8xbw@J{bXBrRYX}39BY$5N(VcS=HSv!O<_IC377A5dnx)*}MFsyc4bpNkBb118 zQm@o21X8KgPifH>MYwaNOa`Ku76omc2~P9F+2Hjmh41;eX7fe^Ss|-w-l#X58w~*4 ztklP{0MP)5|Cr(8Q!bYGUK~96O-7|Vk^xHx=d#XxcC*py zxkhsnfV*r#2N6~2D1x@Z_25K5Ao58+OqA82D67FidG-F|YZYV3)dzTj=0Xk&a1uw9D+|s8P=hb&%f%N7=?{CWI0W|R%T0Zyc4sw;F*Dtei7q`e%VQ7Qsh7c7u z$hVO0YVwZ(P&CEgxGOB#a2&kZkd#87B`5+7mI41yjhmzbyP`$osYgdog^lR^`HSbf z;MsBBVU);TOzQ;dAB+Nlq1lD#SHWi-i4Be*R1RTkO{HXj8AN6P2l2eX)ndFaUW$I* zqe>9GjbeOwmYag)QuR*!{mGLDtd)B+NV0PY8!fM>qOGX>Ex*@~k3t21(vP21*+#(w z12mSLN4duPU{Ks~1eBHS2^~UHyuwmv)E|MSu$v&CxY5xKnWPlTO=z5)g#lEdCiDew2 zO3a1;A+R9cjzRw#mHO|mqHkWWN)sg1sJ|~I^{v&WADpe#`d0mcMY=%>BHd8=D3L&8 z*){}V^9B+icUB0?bqW0b>UW<(qA-nQPU-W$Jxm}K83;NX6D}nA;qIdYZjO66_k+ww z?Nf3@kP8b3ClU-{v!>&~X!RLTvY%&5;0yhZ?c~RdJs(pYz zpqG82`I(IasGwDW(ypj-Vt+J(+5{y#0*||CTev3P@j0)%y;-FUrvqj|#;NtM^C4~2xTodUG(v{wKr5J}-Lhtw@? zd6>v~^naF?fB$}U<;MGu&E|&(mGTci{`vJgY6)%sW_oLoLrnb&Ia#0 zfFU9ti0sxxS$G?e2u#Ma18OCW)T1v|qoG9w4Jv3T$&wQm6{CV~yn`dlb7`BFP7aUJtf7-62^ubA6bh@bWi zyH^P2r{?EA1y_zLQ4JSH>6R1}E&)&A-|5BkM^AofK|l8JVoq0aWK@vD*rs0=( z7*Ft82p$1}t8>UMd(?frh@b+hqaYgcOVK{gY5q7xqy^`!&y0}Pb!K2Bfx)f_zz8*r zcFfh5p(SOT^ffO`rpt^2jU8u60=x0?>=gQ?r)XS|1Lz3k(}-H1TBvf)6&-G#&7@f4 zq)lE*j13yibY36tK7Cr%F6(S2P;`Df0uO{{Hpo6}_@zRHpX2Cf zC<{Wulj`mJT~st;-v903aqHLJ{evejo*UB%US}m9fI{Hxk(}Mgt7G`xHqC>r_xa1G zPj{X@Y|xj2+orXGpSKHZ;9(ALn2bkB?|g9`VJ_QApYt71oI*LFxC!8aQm~b*-)OIu>oiK1d4*JTB2(Y2#6eg&hP$=56qglX$r}okH&I>4IHe zmYH8(rWa%vhEFykGqQsybeO#uffrmv}kzBQ~ z2XaOi%oh%+4Y30sCy0)3ka`br-xZy54fQ&hEIko-Of&%o4jczh-0%f6qC05;iG$>r zXL(AI1|X6EwxS7}we?$aTJ#gG)J{9@o6LG1I(=XE7Q8$b?E^A?Dg_XQao&Ikcr*+w zT+-?fTS=qR!I@-C(YNRFeUc0ulQ8^(ZHVBKyTUL!82w=|p_vLZr-H>ZN_0!HuQhIz zW!$T<%m76=(4kWakcfMT=n2hcgo|By^x{PW|G`lXWkeBzi`M{Zl3We>8?;+vQ%qcn zo=!=ioovJvhL~9ONo+(Zw~m)NB4jdju~y z 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 literal 41084 zcmeHwZF>_(vi4{6D>}lCz-vjEKz1=v7RQ*EvjliB$!6CATb9PM7D=OMB(N8Je*1IZ zRn?m5@FmITzV)zxp+Rn=8JSHE)2e`79lEW`k~L zI6QarY%uOiS~ne^xVOnP8>C}*v$6G!L$%#>ay}jOPiOAh?sd0y=g!Sdcjp`Yy@kKG z@%LNzV45UuKRubf>r4~(Af1nUfS!&w-Q#f=O#{ly(?RA4f6$+!OxB$aCNqb$6V}bF z?p-%K1%MUc0H!~9iyqF$!@+34o=lSIXpjlMvlQ?r=bNrK$Y#^Q@f`i

    j;v;N;v5 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≶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 Date: Mon, 22 Jul 2002 15:40:09 +0000 Subject: [PATCH 099/814] Added Cygwin to the list of supported platforms --- configure | Bin 81487 -> 81647 bytes configure.in | 10 ++++++++++ 2 files changed, 10 insertions(+) diff --git a/configure b/configure index 4d5ee9502e27f5a4ad4bb10f9c9250c07a206877..105c7ede3273821ca43cf317c0a2430a87aa420e 100755 GIT binary patch delta 183 zcmX^AhvofWmJJ@Sn3F5hC%u%IeE8)ICPSmmv9IhHnT!l3J8oCmeDHN6BctVH`IX+x zmL^7%C%&y>GBKTeV2LM?YcYA_X1&RLJB23CeD|Bta`V*pTtKy(7ks$O&tz$^wVv^U z5R<9J_CR4q6DB5e^XU&n8NH{^6lN6P{!)}tf|<$Cc)Ft`qrrA#Nk&~MCS#-RNydy< jn3zlrrZZYFs&9`sW6Wk`GBXDArUQ9#+XF2a|FHr9a@LANBcVeEkc0WgyvsY?SnGc%Jh z?s@?;lfR@&li=+JleDudlMcBOlR5AE0Wh;Q@CpF|Ftb4M-46mdF}EK90nicxGN z69F^=0ya38fEEEumpK#x7q^KP0T=@UFf^Cp838c2(-{FR8Uiviw*oW))B*xDF_)n@ e0VlWrHUVn^0yQ+3p*R62m;W{aUbpc$0saLIa6e4| diff --git a/configure.in b/configure.in index ec07383..f5b31a0 100644 --- a/configure.in +++ b/configure.in @@ -49,6 +49,16 @@ case "${host_os}" in DLL_LIBS="-lwinmm"; ;; + cygwin* ) + dnl Cygwin configuration + + OTHER_OBJS="pa_win_wmme/pa_win_wmme.o"; + LIBS="-lwinmm -lm"; + PADLL="portaudio.dll"; + SHARED_FLAGS="-shared -mthreads"; + DLL_LIBS="-lwinmm"; + ;; + *) dnl Unix OSS configuration From 4e18034910139b9b4df5cef9b016deeaa8ca1b3f Mon Sep 17 00:00:00 2001 From: dmazzoni Date: Thu, 25 Jul 2002 07:51:04 +0000 Subject: [PATCH 100/814] Fixed install of .so file. (Thanks Bill) --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 7acc5a5..2a3cc34 100644 --- a/Makefile.in +++ b/Makefile.in @@ -67,7 +67,7 @@ $(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c $(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS) install: lib/$(PALIB) lib/$(PADLLV) - $(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PADLLV) + $(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV) $(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB) cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL) $(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h From b0d6234ae0d543f93041801b11b8d81610447de5 Mon Sep 17 00:00:00 2001 From: rossbencina Date: Fri, 26 Jul 2002 19:35:31 +0000 Subject: [PATCH 101/814] removed proposal documentation and changed proposals.html to document new location for proposals --- docs/PaStreamStateDiagram.gif | Bin 9720 -> 0 bytes docs/pa_drivermodel.c.txt | 488 ---------------------------------- docs/pa_drivermodel.h.txt | 143 ---------- docs/proposals.html | Bin 74012 -> 1085 bytes 4 files changed, 631 deletions(-) delete mode 100644 docs/PaStreamStateDiagram.gif delete mode 100644 docs/pa_drivermodel.c.txt delete mode 100644 docs/pa_drivermodel.h.txt diff --git a/docs/PaStreamStateDiagram.gif b/docs/PaStreamStateDiagram.gif deleted file mode 100644 index d1fcae0b6e01e226b8c6d2d096360a7ca5152c1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9720 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 Z807|4Pmw}-G@?9vQC^@pzh}>Q{|6L$0{s90 diff --git a/docs/pa_drivermodel.c.txt b/docs/pa_drivermodel.c.txt deleted file mode 100644 index 956f664..0000000 --- a/docs/pa_drivermodel.c.txt +++ /dev/null @@ -1,488 +0,0 @@ -/* - This file contains the host-neutral code for implementing multiple driver model - support in PortAudio. - - It has not been compiled, but it is supplied only for example purposes at this stage. - - TODO: use of CHECK_DRIVER_MODEL is bogus in some instances since some - of those functions don't return a PaError - - -*/ - -#include "pa_drivermodel.h.txt" - - -#ifndef PA_MULTIDRIVER -/* single driver support, most functions will stay in the implementation files */ - -PaDriverModelID Pa_CountDriverModels() -{ - return 1; -} - -/* -Perhaps all drivers should define this with this signature -const PaDriverModelInfo* Pa_GetDriverModelInfo( PaDriverModelID driverModelID ) -{ -} -*/ - -PaDeviceID Pa_DriverModelDefaultInputDeviceID( PaDriverModelID driverModelID ) -{ - return Pa_GetDefaultInputDeviceID(); -} - - -PaDeviceID Pa_DriverModelDefaultOutputDeviceID( PaDriverModelID driverModelID ) -{ - return Pa_GetDefaultInputDeviceID(); -} - -/* -Perhaps all drivers should define with this signature -int Pa_DriverModelMinNumBuffers( PaDriverModelID driverModelID, int framesPerBuffer, double sampleRate ) -{ - -} -*/ - -int Pa_DriverModelCountDevices( PaDriverModelID driverModelID ) -{ - return Pa_CountDevices(); -} - -PaDeviceID Pa_DriverModelGetDeviceID(PaDriverModelID driverModelID, int perDriverModelIndex ) -{ - return perDriverModelIndex; -} - - -#else -/* multidriver support */ - - -typedef PaError (*PaInitializeFunPtr)( PaDriverModelImplementation** ); - -/* - the initializers array is a static table of function pointers - to all the available driverModels on the current platform. - - the order of pointers in the array is important. the first - pointer is always considered to be the "default" driver model. -*/ - -static PaInitializeFunPtr driverModelInitializers[] = { -#ifdef WINDOWS - PaWin32WMME_MultiDriverInitialize, - PaWin32DS_MultiDriverInitialize, - PaASIO_MultiDriverInitialize -#endif -#ifdef MAC - PaMacSM_MultiDriverInitialize, - PaMacCA_MultiDriverInitialize, - PaASIO_MultiDriverInitialize -#endif -/* other platforms here */ - (PaInitializeFunPtr*)0 /* NULL terminate the list */ -}; - - -/* - the driverModels array is a dynamically created table of - currently available driverModels. -*/ -static PaDriverModelImplementation* driverModels = 0; -static int numDriverModels = 0; - - -#define PA_CHECK_INITIALIZED\ - if( driverModels == 0 ) - return paLibraryNotInitialised - -#define PA_CHECK_DRIVER_MODEL_ID( id ) - if( id < 0 || id >= numDriverModels ) - return paBadDriverModelID; - - -/* - ConvertPublicDeviceIdToImplementationDeviceId converts deviceId - from a public device id, to a device id for a particular - PortAudio implementation. On return impl will either point - to a valid implementation or will be NULL. -*/ -static void ConvertPublicDeviceIDToImplementationDeviceID( - PaDriverModelImplementation *impl, PaDeviceID deviceID ) -{ - int i, count; - - impl = NULL; - - for( i=0; i < numDriverModels; ++i ){ - count = driverModels[i]->countDevices(); - if( deviceID < count ){ - impl = driverModels[i]; - return NULL; - }else{ - deviceID -= count; - } - } -} - -static PaDeviceID ConvertImplementationDeviceIDToPublicDeviceID( - PaDriverModelID driverModelID, PaDeviceID deviceID ) -{ - int i; - - for( i=0; i < driverModelID; ++i ) - deviceID += driverModels[i]->countDevices(); -} - - -PaError Pa_Initialize( void ) -{ - PaError result = paNoError; - int i, initializerCount; - PaDriverModelImplementation *impl; - - if( driverModels != 0 ) - return paAlreadyInitialized; - - /* count the number of driverModels */ - initializerCount=0; - while( driverModelInitializers[initializerCount] != 0 ){ - ++initializerCount; - } - - driverModels = malloc( sizeof(PaDriverModelImplementation*) * initializerCount ); - if( driverModels == NULL ) - return paInsufficientMemory; - - numDriverModels = 0; - for( i=0; iterminate( driverModels[i] ); -} - - -long Pa_GetHostError( void ) -{ - PA_CHECK_INITIALIZED; - - under construction. depends on error text proposal. -} - - -const char *Pa_GetErrorText( PaError errnum ) -{ - PA_CHECK_INITIALIZED; - - under construction. may need to call driver model specific code - depending on how the error text proposal pans out. -} - - - -int Pa_CountDevices() -{ - int i, result; - - PA_CHECK_INITIALIZED; - - result = 0; - for( i=0; i < numDriverModels; ++i ) - result += driverModels[i]->countDevices(); - - return result; -} - - -PaDeviceID Pa_GetDefaultInputDeviceID( void ) -{ - PA_CHECK_INITIALIZED; - - return driverModels[0]->getDefaultInputDeviceID(); -} - -PaDeviceID Pa_GetDefaultOutputDeviceID( void ) -{ - PA_CHECK_INITIALIZED; - - return driverModels[0]->getDefaultInputDeviceID(); -} - - -const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID deviceID ) -{ - PaDriverModelImplementation *impl; - - PA_CHECK_INITIALIZED; - - ConvertPublicDeviceIDToImplementationDeviceID( impl, deviceID ); - if( impl == NULL ) - return paInvalidDeviceID; - - return impl->getDeviceInfo( deviceID ); -} - -/* NEW MULTIPLE DRIVER MODEL FUNCTIONS ---------------------------------- */ - -PaDriverModelID Pa_CountDriverModels() -{ - PA_CHECK_INITIALIZED; - - return numDriverModels; -} - - -const PaDriverModelInfo* Pa_GetDriverModelInfo( PaDriverModelID driverModelID ) -{ - PA_CHECK_INITIALIZED; - PA_CHECK_DRIVER_MODEL_ID( driverModelID ); - - return driverModels[ driverModelID ]->getDriverModelInfo(); -} - - -PaDeviceID Pa_DriverModelDefaultInputDeviceID( PaDriverModelID driverModelID ) -{ - PA_CHECK_INITIALIZED; - PA_CHECK_DRIVER_MODEL_ID( driverModelID ); - - return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, - driverModels[ driverModelID ]->getDefaultInputDeviceID(); -} - - -PaDeviceID Pa_DriverModelDefaultOutputDeviceID( PaDriverModelID driverModelID ) -{ - PA_CHECK_INITIALIZED; - PA_CHECK_DRIVER_MODEL_ID( driverModelID ); - - return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, - driverModels[ driverModelID ]->getDefaultOutputDeviceID(); -} - - -int Pa_DriverModelMinNumBuffers( PaDriverModelID driverModelID, int framesPerBuffer, double sampleRate ) -{ - PA_CHECK_INITIALIZED; - PA_CHECK_DRIVER_MODEL_ID( driverModelID ); - - return driverModels[ driverModelID ]->getMinNumBuffers( int framesPerBuffer, double sampleRate ); -} - - -int Pa_DriverModelCountDevices( PaDriverModelID driverModelID ) -{ - PA_CHECK_INITIALIZED; - PA_CHECK_DRIVER_MODEL_ID( driverModelID ); - - return driverModels[ driverModelID ]->coundDevices(); -} - -PaDeviceID Pa_DriverModelGetDeviceID(PaDriverModelID driverModelID, int perDriverModelIndex ) -{ - PA_CHECK_INITIALIZED; - PA_CHECK_DRIVER_MODEL_ID( driverModelID ); - - return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, perDriverModelIndex ); -} - -/* END NEW MULTIPLE DRIVER MODEL FUNCTIONS ------------------------------ */ - - -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 ) -{ - PaError result; - PaDriverModelImplementation *inputImpl, *outputImpl, impl; - - PA_CHECK_INITIALIZED; - - if( inputDevice != paNoDevice ){ - ConvertPublicDeviceIDToImplementationDeviceID( inputImpl, inputDevice ); - if( inputImpl == NULL ) - return paInvalidDeviceID; - else - impl = inputImpl; - } - - if( outputDevice != paNoDevice ){ - ConvertPublicDeviceIDToImplementationDeviceID( outputImpl, outputDevice ); - if( outputImpl == NULL ) - return paInvalidDeviceID; - else - impl = outputImpl; - } - - if( inputDevice != paNoDevice && outputDevice != paNoDevice ){ - if( inputImpl != outputImpl ) - return paDevicesMustBelongToTheSameDriverModel; - } - - - result = impl->openStream( stream, inputDevice, numInputChannels, inputSampleFormat, inputDriverInfo, - outputDevice, numOutputChannels, outputSampleFormat, outputDriverInfo, - sampleRate, framesPerBuffer, numberOfBuffers, streamFlags, callback, userData ); - - - if( result == paNoError ) - ((PaStreamImplementation*)stream)->magic = PA_STREAM_MAGIC; - - 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 ) -{ - PaError result; - int inputDevice = driverModels[0]->getDefaultInputDeviceID; - int outputDevice = driverModels[0]->getDefaultOutputDeviceID; - - result = driverModels[0]->openStream( stream, inputDevice, numInputChannels, sampleFormat, 0, - outputDevice, numOutputChannels, sampleFormat, 0, - sampleRate, framesPerBuffer, numberOfBuffers, - streamFlags, callback, userData ); - - if( result == paNoError ) - ((PaStreamImplementation*)stream)->magic = PA_STREAM_MAGIC; - - return result; -} - - -PaError Pa_CloseStream( PortAudioStream* stream ) -{ - PA_CHECK_INITIALIZED; - - PaError result = ((PaStreamImplementation*)stream)->close(); - - if( result == PaNoError ) - ((PaStreamImplementation*)stream)->magic = 0; /* clear magic number */ - - return result; -} - - -PaError Pa_StartStream( PortAudioStream *stream ); -{ - PA_CHECK_INITIALIZED; - - return ((PaStreamImplementation*)stream)->start(); -} - - -PaError Pa_StopStream( PortAudioStream *stream ); -{ - PA_CHECK_INITIALIZED; - - return ((PaStreamImplementation*)stream)->stop(); -} - - -PaError Pa_AbortStream( PortAudioStream *stream ); -{ - PA_CHECK_INITIALIZED; - - return ((PaStreamImplementation*)stream)->abort(); -} - - -PaError Pa_StreamActive( PortAudioStream *stream ) -{ - PA_CHECK_INITIALIZED; - - return ((PaStreamImplementation*)stream)->active(); -} - -PaTimestamp Pa_StreamTime( PortAudioStream *stream ) -{ - PA_CHECK_INITIALIZED; - - return ((PaStreamImplementation*)stream)->time(); -} - - -double Pa_StreamCPULoad( PortAudioStream* stream ) -{ - PA_CHECK_INITIALIZED; - - return ((PaStreamImplementation*)stream)->cpuLoad(); -} - - - -int Pa_GetMinNumBuffers( PaDeviceID deviceID, int framesPerBuffer, double sampleRate ) -{ - PaDriverModelImplementation *impl; - PA_CHECK_INITIALIZED; - - ConvertPublicDeviceIDToImplementationDeviceID( impl, deviceID ); - if( impl == NULL ) - return paInvalidDeviceID; - - return impl->getMinNumBuffers( framesPerBuffer, sampleRate ); -} - - -void Pa_Sleep( long msec ) -{ - same as existing implementaion -} - - -PaError Pa_GetSampleSize( PaSampleFormat format ) -{ - same as existing implementation -} - -#endif /* PA_MULTIDRIVER */ - - diff --git a/docs/pa_drivermodel.h.txt b/docs/pa_drivermodel.h.txt deleted file mode 100644 index f3f2ca2..0000000 --- a/docs/pa_drivermodel.h.txt +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef PA_MULTIDRIVERMODEL_H -#define PA_MULTIDRIVERMODEL_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* - This file contains the host-neutral code for implementing multiple driver model - support in PortAudio. - - It has not been compiled, but it is supplied only for example purposes at this stage. -*/ - - -#include "portaudio.h" - - -#define PA_MULTIDRIVER // for multidriver support - - - -TODO: declare function pointer types for the following function pointers - -/* - Each driver model implementation needs to implement an initialize function - which is added to the driverModelInitializers array in pa_multidrivermodel.c - - the initializer function needs to return a pointer to a - PaDriverModelImplementation structure, or NULL if initiliazation failed. TODO: need error code instead - - the function pointer members of this structure point to funtions - which operate in exactly the same way as the corresponding functions - in the PortAudio API. -*/ - -struct{ - fptr terminate; /* takes the PaDriverModelImplementation* returned by initialize */ - fptr getDriverModelInfo; - fptr getHostError; - fptr getHostErrorText; - fptr countDevices; - fptr getDefaultInputDeviceID; - fptr getDefaultOutputDeviceID; - fptr getDeviceInfo; - fptr openStream; - fptr getMinNumBuffers; -} PaDriverModelImplementation; - -/* - whenever an implementaion's openstream method is called it should return a - PortAudioStream* whose first segment is actually the following structure. - - the functions pointer members of this structure point to funcitons - which operate in exactly the same way as the corresponding functions - in the PortAudio API. -*/ -struct{ - unsigned long magic; - fptr close; - fptr start; - fptr stop; - fptr abort; - fptr active; - fptr time; - fptr cpuLoad; -} PaStreamImplementation; - -/* - Implementations should set magic to PA_STREAM_MAGIC when opening - a stream _and_ clear it to zero when closing a stream. - All functions which operate on streams should check the validity - of magic. -*/ - -#define PA_STREAM_MAGIC 0x12345678 - -#define PA_CHECK_STREAM( stream )\ - if( ((PaStreamImplementation*)stream)->magic != PA_STREAM_MAGIC )\ - return paBadStreamPtr; - - -/* - PA_API allows the same implementation to be used for single - driver model and multi-driver model operation. If - PA_MULTIDRIVER not defined, PA_API will declare api - functions as global, otherwise they will be static, and include - the drivermodel code. - - Usage would be something like: - - int PA_API(CountDevices)(); - - The PA_MULTIDRIVER_SUPPORT macro declares the initialization and - termination functions required by the multidriver support. it also - allocates and deallocates the PaDriverModelImplementation structure. - - TODO: add macros for initializing PaStreamImplementation PortAudioStream - these would be PA_INITIALIZE_STREAM and PA_TERMINATE_STREAM - they would assign and clear the magic number and assign the - interface functions if neceassary. -*/ - -#ifdef PA_MULTIDRIVER - -#define PA_API( model, name ) static Pa ## model ## _ ## name - -#define PA_MULTIDRIVER_SUPPORT( model )\ -PaError Pa_ ## model ## _MultiDriverTerminate( PaStreamImplementation *impl )\ -{\ - free( impl );\ - return Pa ## model ## _Terminate();\ -}\ -PaError Pa ## model ## _MultiDriverInitialize( PaStreamImplementation** impl )\ -{\ - PaError result = Pa ## model ## _Initialize();\ -\ - if( result == paNoError ){\ - *impl = malloc( sizeof( PaDriverModelImplementation ) );\ - if( impl == NULL ){\ - // TODO: call terminate, return an error - }else{\ - (*impl)->terminate = Pa ## model ## _MultiDriverTerminate();\ - (*impl)->getDriverModelInfo = Pa ## model ## _GetDriverModelInfo();\ - (*impl)->getHostError = Pa ## model ## _GetHostError();\ - // TODO: assign the rest of the interface functions - }\ - }\ - return result;\ -} - -#else /* !PA_MULTIDRIVER */ - -#define PA_API( model, name ) Pa_ ## name - -#define PA_MULTIDRIVER_SUPPORT - -#endif /* PA_MULTIDRIVER */ - - - -#endif /* PA_MULTIDRIVERMODEL_H */ diff --git a/docs/proposals.html b/docs/proposals.html index 7c0dc4fb99087f8435dae763778d511b581c4950..88dd2d07ce3ed33b6d0f92cc99ae31fb2c5a16b7 100644 GIT binary patch delta 297 zcmZvYze>bF7{uiek-aAnEQVAT$L*0ukR=fRKnjlwcnDUqCLd&Bvm3IT99BL=TESMk zdx2|w5i8%rJup^Q12cTT8NS!g!`<=rd-9^65ueWxFBUNb&l4uHI9XSOytR#WQafa_ zCoFAGrQjiCOf<J|c6jYP(e}^b-(d`}Sl{KiOL%oO0u`=+XVM9+i zb;{EW%0oFAyMeZa^i)Fn3pRYcpRsX9lnif^lVSUDq(@8eG_3ihUESZoQQK4d4^0`! l&|Y?$U}PQmQ6nFl5fsgt;7wo!xm;a8gfH-Hy}V7>!4GYJVz~eS literal 74012 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 g+;TGSu|LcGKf7$1_?EnA( From a47cf43a45a016f73a96ebb39adfe09b76ea000d Mon Sep 17 00:00:00 2001 From: todd Date: Thu, 24 Jun 2004 20:32:18 +0000 Subject: [PATCH 102/814] test directory settings --- testcvs/stuff/info.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 testcvs/stuff/info.txt diff --git a/testcvs/stuff/info.txt b/testcvs/stuff/info.txt new file mode 100644 index 0000000..d557202 --- /dev/null +++ b/testcvs/stuff/info.txt @@ -0,0 +1 @@ +interesting info From ecc345dde90f0be6cec4f071adf10bc8a82bf797 Mon Sep 17 00:00:00 2001 From: philburk Date: Fri, 30 Jul 2004 00:38:24 +0000 Subject: [PATCH 103/814] tweak --- testcvs/changeme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt index 9149b25..3a69b98 100644 --- a/testcvs/changeme.txt +++ b/testcvs/changeme.txt @@ -6,3 +6,4 @@ philburk tweak stephane test Phil changed this again on 2/21/02. Yawn... pieter test (MacCVS Pro 2.5b2) +phil says hi From a58a6c257b35a593ec827fe66404e7403f9cb539 Mon Sep 17 00:00:00 2001 From: bjornroche Date: Thu, 20 Mar 2008 14:14:19 +0000 Subject: [PATCH 104/814] moved pateam to tags/unknown-was-pateam and added a README.txt for the folder. --- LICENSE.txt | 65 - Makefile.in | 95 -- Makefile.linux | 19 +- Makefile.mingw | 57 - README.txt | 82 +- config.guess | Bin 38293 -> 0 bytes config.sub | Bin 28332 -> 0 bytes configure | Bin 81647 -> 0 bytes configure.in | 81 -- docs/index.html | 66 - docs/latency.html | 192 --- docs/pa_impl_guide.html | 197 --- docs/pa_impl_startstop.html | 190 --- docs/pa_tut_asio.html | 55 - docs/pa_tut_callback.html | 91 -- docs/pa_tut_devs.html | 65 - docs/pa_tut_explore.html | 42 - docs/pa_tut_init.html | 43 - docs/pa_tut_mac.html | 41 - docs/pa_tut_mac_osx.html | 46 - docs/pa_tut_open.html | 52 - docs/pa_tut_oss.html | 46 - docs/pa_tut_over.html | 92 -- docs/pa_tut_pc.html | 78 - docs/pa_tut_run.html | 56 - docs/pa_tut_rw.html | 79 - docs/pa_tut_term.html | 47 - docs/pa_tut_util.html | 55 - docs/pa_tutorial.html | 46 - docs/portaudio_h.txt | 425 ------ docs/portaudio_icmc2001.pdf | Bin 50968 -> 0 bytes docs/proposals.html | Bin 1085 -> 0 bytes docs/releases.html | 339 ----- docs/style.html | 156 -- fixfile.bat | 7 - index.html | 89 -- install-sh | Bin 5598 -> 0 bytes pa_asio/borland_asio_readme.txt | 6 - pa_asio/pa_asio.cpp | 443 +++--- pa_asio/readme_asio_sdk_patch.txt | 25 - pa_common/pa_convert.c | 402 ------ pa_common/pa_host.h | 63 +- pa_common/pa_lib.c | 102 +- pa_common/portaudio.h | 193 ++- pa_mac/pa_mac.c | 205 +-- pa_mac_core/notes.txt | 34 - pa_mac_core/pa_mac_core.c | 1068 +++++++------- pa_sgi/Makefile | 55 +- pa_sgi/pa_sgi.c | 1055 +++++++------- pa_sgi/pthread-Makefile | 52 - pa_sgi/pthread-pa_sgi.c | 908 ------------ pa_tests/debug_convert.c | 131 -- pa_tests/debug_dither_calc.c | 55 - pa_tests/debug_multi_out.c | 107 +- pa_tests/debug_record.c | 174 +-- pa_tests/debug_record_reuse.c | 351 ----- pa_tests/debug_sine.c | 2 +- pa_tests/debug_sine_amp.c | 157 -- pa_tests/debug_sine_formats.c | 202 --- pa_tests/{patest_hang.c => debug_sine_wait.c} | 77 +- pa_tests/debug_srate.c | 265 ---- pa_tests/pa_minlat.c | 46 +- pa_tests/paqa_errs.c | 25 - pa_tests/patest_dither.c | 1 - pa_tests/patest_latency.c | 21 +- pa_tests/patest_leftright.c | 15 +- pa_tests/patest_longsine.c | 15 +- pa_tests/patest_maxsines.c | 73 +- pa_tests/patest_multi_sine.c | 144 -- pa_tests/patest_record.c | 53 +- pa_tests/patest_sine.c | 1 + pa_tests/patest_sine_formats.c | 13 +- pa_tests/patest_sine_time.c | 64 +- pa_tests/patest_toomanysines.c | 172 --- pa_tests/patest_wire.c | 15 +- pa_unix_oss/Makefile | 9 +- pa_unix_oss/pa_unix_oss.c | 449 +----- pa_win_ds/pa_dsound.c | 52 +- pa_win_wmme/pa_win_wmme.c | 1270 +++++++---------- pablio/test_rw.c | 20 +- testcvs/changeme.txt | 9 - testcvs/stuff/info.txt | 1 - 82 files changed, 2322 insertions(+), 9272 deletions(-) delete mode 100644 LICENSE.txt delete mode 100644 Makefile.in delete mode 100644 Makefile.mingw delete mode 100755 config.guess delete mode 100755 config.sub delete mode 100755 configure delete mode 100644 configure.in delete mode 100644 docs/index.html delete mode 100644 docs/latency.html delete mode 100644 docs/pa_impl_guide.html delete mode 100644 docs/pa_impl_startstop.html delete mode 100644 docs/pa_tut_asio.html delete mode 100644 docs/pa_tut_callback.html delete mode 100644 docs/pa_tut_devs.html delete mode 100644 docs/pa_tut_explore.html delete mode 100644 docs/pa_tut_init.html delete mode 100644 docs/pa_tut_mac.html delete mode 100644 docs/pa_tut_mac_osx.html delete mode 100644 docs/pa_tut_open.html delete mode 100644 docs/pa_tut_oss.html delete mode 100644 docs/pa_tut_over.html delete mode 100644 docs/pa_tut_pc.html delete mode 100644 docs/pa_tut_run.html delete mode 100644 docs/pa_tut_rw.html delete mode 100644 docs/pa_tut_term.html delete mode 100644 docs/pa_tut_util.html delete mode 100644 docs/pa_tutorial.html delete mode 100644 docs/portaudio_h.txt delete mode 100644 docs/portaudio_icmc2001.pdf delete mode 100644 docs/proposals.html delete mode 100644 docs/releases.html delete mode 100644 docs/style.html delete mode 100755 fixfile.bat delete mode 100644 index.html delete mode 100755 install-sh delete mode 100644 pa_asio/borland_asio_readme.txt delete mode 100755 pa_asio/readme_asio_sdk_patch.txt delete mode 100644 pa_common/pa_convert.c delete mode 100644 pa_mac_core/notes.txt delete mode 100644 pa_sgi/pthread-Makefile delete mode 100644 pa_sgi/pthread-pa_sgi.c delete mode 100644 pa_tests/debug_convert.c delete mode 100644 pa_tests/debug_dither_calc.c delete mode 100644 pa_tests/debug_record_reuse.c delete mode 100644 pa_tests/debug_sine_amp.c delete mode 100644 pa_tests/debug_sine_formats.c rename pa_tests/{patest_hang.c => debug_sine_wait.c} (76%) delete mode 100644 pa_tests/debug_srate.c delete mode 100644 pa_tests/patest_multi_sine.c delete mode 100644 pa_tests/patest_toomanysines.c delete mode 100644 testcvs/changeme.txt delete mode 100644 testcvs/stuff/info.txt diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 105da3f..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,65 +0,0 @@ -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/ - * Implementation - * Copyright (c) 1999-2000 - * - * 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/Makefile.in b/Makefile.in deleted file mode 100644 index 2a3cc34..0000000 --- a/Makefile.in +++ /dev/null @@ -1,95 +0,0 @@ -# -# PortAudio Makefile.in -# -# Dominic Mazzoni -# - -PREFIX = @prefix@ -CC = @CC@ -CFLAGS = @CFLAGS@ -Ipa_common -LIBS = @LIBS@ -AR = @AR@ -RANLIB = @RANLIB@ -INSTALL = @INSTALL@ -SHARED_FLAGS = @SHARED_FLAGS@ -DLL_LIBS = @DLL_LIBS@ - -OTHER_OBJS = @OTHER_OBJS@ - -PALIB = libportaudio.a -PADLL = @PADLL@ -PADLLV = $(PADLL).0.0.18 -PAINC = pa_common/portaudio.h - -COMMON_OBJS = \ - pa_common/pa_convert.o \ - pa_common/pa_lib.o - -TESTS = \ - bin/patest_buffer \ - bin/patest_clip \ - bin/patest_dither \ - bin/patest_hang \ - bin/patest_latency \ - bin/patest_leftright \ - bin/patest_longsine \ - bin/patest_many \ - bin/patest_maxsines \ - bin/patest_multi_sine \ - bin/patest_pink \ - bin/patest_record \ - bin/patest_ringmix \ - bin/patest_saw \ - bin/patest_sine8 \ - bin/patest_sine \ - bin/patest_sine_formats \ - bin/patest_sine_time \ - bin/patest_stop \ - bin/patest_sync \ - bin/patest_toomanysines \ - bin/patest_underflow \ - bin/patest_wire - -OBJS = $(COMMON_OBJS) $(OTHER_OBJS) - -all: lib/$(PALIB) lib/$(PADLLV) tests - -tests: bin/ $(TESTS) - -lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC) - $(AR) ruv lib/$(PALIB) $(OBJS) - $(RANLIB) lib/$(PALIB) - -lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC) - $(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(DLL_LIBS) - -$(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c - $(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS) - -install: lib/$(PALIB) lib/$(PADLLV) - $(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV) - $(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB) - cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL) - $(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h - @echo "" - @echo "------------------------------------------------------------" - @echo "PortAudio was successfully installed." - @echo "" - @echo "On some systems (e.g. Linux) you should run 'ldconfig' now" - @echo "to make the shared object available. You may also need to" - @echo "modify your LD_LIBRARY_PATH environment variable to include" - @echo "the directory $(PREFIX)/lib" - @echo "------------------------------------------------------------" - @echo "" - -clean: - rm -f $(OBJS) $(TESTS) lib/$(PALIB) - -%.o: %.c Makefile $(PAINC) - $(CC) -c $(CFLAGS) $< -o $@ - -bin: - mkdir bin - -lib: - mkdir lib diff --git a/Makefile.linux b/Makefile.linux index 4deee60..9f67ce6 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -1,8 +1,6 @@ # Make PortAudio for Linux # Updated 2001/08/25 Bill Eldridge bill@rfa.org # Updated 2001/10/16, philburk@softsynth.com, s/unix_oss/unix_oss/ -# Updated 2002/04/30 Bill Eldridge bill@rfa.org -# Made the libinstall and tests compile a bit cleaner # A pretty bare makefile, that figures out all the test files # and compiles them against the library in the pa_unix_oss directory. @@ -21,34 +19,23 @@ CFLAGS = -g LIBINST = /usr/local/lib TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) -TESTO:= $(wildcard pa_tests/pa*.o pa_tests/debug*.o) LIBFILES:= ./pa_common/pa_lib.c ./pa_unix_oss/pa_unix_oss.c -#all: sharedlib libinstall tests -all: sharedlib libinstall testo testq - .c.o: -gcc -c -I./pa_common $< -o $*.o - -.o: -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio -#.c.o: -# -gcc -c -I./pa_common $< -o $*.o -# -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio - +all: sharedlib tests sharedlib: $(LIBFILES:.c=.o) gcc -shared -o ./pa_unix_oss/libportaudio.so ./pa_common/pa_lib.o ./pa_unix_oss/pa_unix_oss.o libinstall: ./pa_unix_oss/libportaudio.so @cp -f ./pa_unix_oss/libportaudio.so $(LIBINST) - @/sbin/ldconfig + @/sbin/ldconfig -v -testo: $(TESTS:.c=.o) - -testq: $(TESTO:.o=) +tests: $(TESTS:.c=.o) clean: -@rm -f $(TESTS:.c=.o) diff --git a/Makefile.mingw b/Makefile.mingw deleted file mode 100644 index 2043a16..0000000 --- a/Makefile.mingw +++ /dev/null @@ -1,57 +0,0 @@ - -# Makefile for PortAudio on mingw (http://mingw.sourceforge.net) - -# Contributed by Bill Eldridge, bill@rfa.org, Radio Free Asia -# Copyright 2002/02/20, GPL - -# Uses a common mingw32 cross-compiler that defaults -# to everything in /usr/local/cross-tools - -# First edit your path with -# export PATH=/usr/local/cross-tools/bin:$PATH - -# Usage: make -f Makefile.mingw all -# or make -f Makefile.mingw sharedlib -# make -f Makefile.mingw tests -# -# Then copy executables & portaudio.dll to your Windows machine -# -# To make work with pa_win_ds, you'll have to substitue -# all the pa_win_wmme files with pa_win_ds files, no biggie. - -CC= i586-mingw32msvc-gcc -DLLTOOL= i586-mingw32msvc-dlltool -DLLWRAP= i586-mingw32msvc-dllwrap - -ARCH= pa_win_wmme - -TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) - -.c.o: - -$(CC) -c -I./pa_common $< -o $*.o - -$(CC) $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm - -all: sharedlib tests - -sharedlib: ./pa_common/pa_lib.c - $(CC) -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o - $(CC) -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o - $(CC) -shared -mthreads -o portaudio.dll pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm - $(DLLWRAP) --export-all --output-def=libportaudio.def --output-lib=libportaudio.a --dllname=portaudio.dll --drivername=i586-mingw32msvc-gcc pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm - $(CC) -shared -Wl,--enable-auto-image-base -o portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm - - -tests: $(TESTS:.c=.o) - -sine: - $(CC) -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o - $(CC) pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm - -clean: - -rm ./pa_tests/*.exe - -rm ./pa_tests/*.o - -nothing: - $(CC) pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm - - diff --git a/README.txt b/README.txt index d1e5d7d..7125931 100644 --- a/README.txt +++ b/README.txt @@ -1,81 +1 @@ -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 +This folder may have had something to do with the original CVS import. No one else on the mailing list knew what it was either, but it was decided that we aught to keep it in tags, rather than branges, where it was originally. It was originally called "pateam" and before I touched it it was last touched by "anonymous" in 2002ish. -Bjorn Roche diff --git a/config.guess b/config.guess deleted file mode 100755 index 297e5c30f41b65e95341322c77994c4d1d447134..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38293 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 U)O!4AX9|J+poD;K<7?sn03Xu03;+NC diff --git a/config.sub b/config.sub deleted file mode 100755 index 791bcded7c3bf807b4ecb7521fcd2ef9ad175b2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28332 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 GJO3Y7hsiGh diff --git a/configure b/configure deleted file mode 100755 index 105c7ede3273821ca43cf317c0a2430a87aa420e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81647 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%0DuN1tG|I(LrTaq1 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 s5RY(R#(bqvY0u?3r1QuMn^s}hl= 2.13 -AC_PREREQ(2.13) - -dnl Init autoconf and make sure configure is being called -dnl from the right directory -AC_INIT([pa_common/portaudio.h]) - -dnl Checks for programs -AC_PROG_CC -AC_PROG_RANLIB -AC_PROG_INSTALL -AC_PATH_PROG(AR, ar, no) -if [[ $AR = "no" ]] ; then - AC_MSG_ERROR("Could not find ar - needed to create a library"); -fi - -dnl Extra variables we want to substitute -AC_SUBST(OTHER_OBJS) -AC_SUBST(PADLL) -AC_SUBST(SHARED_FLAGS) -AC_SUBST(DLL_LIBS) - -dnl Determine the host operating system / platform -AC_CANONICAL_HOST - -case "${host_os}" in - darwin* ) - dnl Mac OS X configuration - - OTHER_OBJS="pa_mac_core/pa_mac_core.o"; - LIBS="-framework CoreAudio -lm"; - PADLL="libportaudio.dylib"; - SHARED_FLAGS="-framework CoreAudio -dynamiclib"; - ;; - - mingw* ) - dnl MingW configuration - - OTHER_OBJS="pa_win_wmme/pa_win_wmme.o"; - LIBS="-lwinmm -lm"; - PADLL="portaudio.dll"; - SHARED_FLAGS="-shared -mthreads"; - DLL_LIBS="-lwinmm"; - ;; - - cygwin* ) - dnl Cygwin configuration - - OTHER_OBJS="pa_win_wmme/pa_win_wmme.o"; - LIBS="-lwinmm -lm"; - PADLL="portaudio.dll"; - SHARED_FLAGS="-shared -mthreads"; - DLL_LIBS="-lwinmm"; - ;; - - *) - dnl Unix OSS configuration - - AC_CHECK_LIB(pthread, pthread_create, - , - AC_MSG_ERROR([libpthread not found!])) - - OTHER_OBJS="pa_unix_oss/pa_unix_oss.o"; - LIBS="-lm -lpthread"; - PADLL="libportaudio.so"; - SHARED_FLAGS="-shared"; -esac - -AC_OUTPUT([Makefile]) - -echo "" -echo "Finished configure." - -echo "" -echo "Type 'make' to build PortAudio and examples." diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index dfd648e..0000000 --- a/docs/index.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - PortAudio Docs - - -  -

    - - - -
    -
    -

    -PortAudio Documentation

    -
    - -

    Copyright 2000 Phil Burk and Ross Bencina -

    -Tutorial

    - -
    -
    Describes how to write audio programs using the PortAudio API.
    - -

    -API Reference

    - -
    The Application Programmer Interface is documented in "portaudio.h".
    - -

    -Release Notes

    - -
    What changed since the last release?
    -
    - -

    -Implementation Guide

    - -
    Describes how to write an implementation of PortAudio for a -new computer platform.
    - -

    -Paper Presented at ICMC2001 (PDF)

    - -
    Describes the PortAudio API and discusses implementation issues. -Written July 2001.
    - -

    -Improving Latency

    - -
    How to tune your computer to achieve the lowest possible audio -delay.
    - -

    -Proposed Changes

    - -
    Describes API changes being considered by the developer community. -Feedback welcome.
    -Return to PortAudio Home Page - - diff --git a/docs/latency.html b/docs/latency.html deleted file mode 100644 index 87f1d12..0000000 --- a/docs/latency.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - PortAudio Implementation - Start/Stop - - -  -
    - - - -
    -
    -

    -PortAudio Latency

    -
    - -

    This page discusses the issues of audio latency for PortAudio -. It offers suggestions on how to lower latency to improve the responsiveness -of applications. -

    What is Latency? -
    PortAudio and Latency -
    Macintosh -
    Unix -
    WIndows
    -By Phil Burk, Copyright 2002 Phil Burk and Ross Bencina -

    -What is Latency?

    -Latency is basically longest time that you have to wait before you obtain -a desired result. For digital audio output it is the time between making -a sound in software and finally hearing it. -

    Consider the example of pressing a key on the ASCII keyboard to play -a note. There are several stages in this process which each contribute -their own latency. First the operating system must respond to the keypress. -Then the audio signal generated must work its way through the PortAudio -buffers. Then it must work its way through the audio card hardware. Then -it must go through the audio amplifier which is very quick and then travel -through the air. Sound travels at abous one foot per millisecond through -air so placing speakers across the room can add 5-20 msec of delay. -

    The reverse process occurs when recording or responding to audio input. -If you are processing audio, for example if you implement a software guitar -fuzz box, then you have both the audio input and audio output latencies -added together. -

    The audio buffers are used to prevent glitches in the audio stream. -The user software writes audio into the output buffers. That audio is read -by the low level audio driver or by DMA and sent to the DAC. If the computer -gets busy doing something like reading the disk or redrawing the screen, -then it may not have time to fill the audio buffer. The audio hardware -then runs out of audio data, which causes a glitch. By using a large enough -buffer we can ensure that there is always enough audio data for the audio -hardware to play. But if the buffer is too large then the latency is high -and the system feels sluggish. If you play notes on the keyboard then the -"instrument" will feel unresponsive. So you want the buffers to be as small -as possible without glitching. -

    -PortAudio and Latency

    -The only delay that PortAudio can control is the total length of its buffers. -The Pa_OpenStream() call takes two parameters: numBuffers and framesPerBuffer. -The latency is also affected by the sample rate which we will call framesPerSecond. -A frame is a set of samples that occur simultaneously. For a stereo stream, -a frame is two samples. -

    The latency in milliseconds due to this buffering  is: -

    latency_msec = 1000 * numBuffers * framesPerBuffer / framesPerSecond
    -This is not the total latency, as we have seen, but it is the part we can -control. -

    If you call Pa_OpenStream() with numBuffers equal to zero, then PortAudio -will select a conservative number that will prevent audio glitches. If -you still get glitches, then you can pass a larger value for numBuffers -until the glitching stops. if you try to pass a numBuffers value that is -too small, then PortAudio will use its own idea of the minimum value. -

    PortAudio decides on the minimum number of buffers in a conservative -way based on the frameRate, operating system and other variables. You can -query the value that PortAudio will use by calling: -

    int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate -);
    -On some systems you can override the PortAudio minimum if you know your -system can handle a lower value. You do this by setting an environment -variable called PA_MIN_LATENCY_MSEC which is read by PortAudio when it -starts up. This is supported on the PortAudio implementations for Windows -MME, Windows DirectSound, and Unix OSS. -

    -Macintosh

    -The best thing you can do to improve latency on Mac OS 8 and 9 is to turn -off Virtual Memory. PortAudio V18 will detect that Virtual Memory is turned -off and use a very low latency. -

    For Mac OS X the latency is very low because Apple Core Audio is so -well written. You can set the PA_MIN_LATENCY_MSEC variable using: -

    setenv PA_MIN_LATENCY_MSEC 4
    - -

    -Unix

    -PortAudio under Unix currently uses a backgroud thread that reads and writes -to OSS. This gives you decent but not great latency. But if you raise the -priority of the background thread to a very priority then you can get under -10 milliseconds latency. In order to raise your priority you must run the -PortAudio program as root! You must also set PA_MIN_LATENCY_MSEC using -the appropriate command for your shell. -

    -Windows

    -Latency under Windows is a complex issue because of all the alternative -operating system versions and device drivers. I have seen latency range -from 8 milliseconds to 400 milliseconds. The worst case is when using Windows -NT. Windows 98 is a little better, and Windows XP can be quite good if -properly tuned. -

    The underlying audio API also makes a lot of difference. If the audio -device has its own DirectSound driver then DirectSound can often provide -better latency than WMME. But if a real DirectSound driver is not available -for your device then it is emulated using WMME and the latency can be very -high. That's where I saw the 400 millisecond latency. The ASIO implementation -is generally very good and will give the lowest latency if available. -

    You can set the PA_MIN_LATENCY_MSEC variable to 50, for example, by -entering in MS-DOS: -

    set PA_MIN_LATENCY_MSEC=50
    -If you enter this in a DOS window then you must run the PortAudio program -from that same window for the variable to have an effect. You can add that -line to your C:\AUTOEXEC.BAT file and reboot if you want it to affect any -PortAudio based program. -

    For Windows XP, you can set environment variables as follows: -

      -
    1. -Select "Control Panel" from the "Start Menu".
    2. - -
    3. -Launch the "System" Control Panel
    4. - -
    5. -Click on the "Advanced" tab.
    6. - -
    7. -Click on the "Environment Variables" button.
    8. - -
    9. -Click "New" button under  User Variables.
    10. - -
    11. -Enter PA_MIN_LATENCY_MSEC for the name and some optimistic number for the -value.
    12. - -
    13. -Click OK, OK, OK.
    14. -
    - -

    -Improving Latency on Windows

    -There are several steps you can take to improve latency under windows. -
      -
    1. -Avoid reading or writng to disk when doing audio.
    2. - -
    3. -Turn off all automated background tasks such as email clients, virus scanners, -backup programs, FTP servers, web servers, etc. when doing audio.
    4. - -
    5. -Disconnect from the network to prevent network traffic from interrupting -your CPU.
    6. -
    -Important: Windows XP users can also tune the OS to favor background -tasks, such as audio, over foreground tasks, such as word processing. I -lowered my latency from 40 to 10 milliseconds using this simple technique. -
      -
    1. -Select "Control Panel" from the "Start Menu".
    2. - -
    3. -Launch the "System" Control Panel
    4. - -
    5. -Click on the "Advanced" tab.
    6. - -
    7. -Click on the "Settings" button in the Performance area.
    8. - -
    9. -Click on the "Advanced" tab.
    10. - -
    11. -Select "Background services" in the Processor Scheduling area.
    12. - -
    13. -Click OK, OK.
    14. -
    -Please let us know if you have others sugestions for lowering latency. -
      -
      - - diff --git a/docs/pa_impl_guide.html b/docs/pa_impl_guide.html deleted file mode 100644 index 50abc30..0000000 --- a/docs/pa_impl_guide.html +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - PortAudio Implementation - Start/Stop - - -  -
    - - - -
    -
    -

    -PortAudio Implementation Guide

    -
    - -

    This document describes how to implement the PortAudio API on a new -computer platform. Implementing PortAudio on a new platform, makes it possible -to port many existing audio applications to that platform. -

    By Phil Burk -
    Copyright 2000 Phil Burk and Ross Bencina -

    Note that the license says: "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.". -So when you have finished a new implementation, please send it back to -us at  "http://www.portaudio.com" -so that we can make it available for other users. Thank you! -

    -Download the Latest PortAudio Implementation

    -Always start with the latest implementation available at "http://www.portaudio.com". -Look for the nightly snapshot under the CVS section. -

    -Select an Existing Implementation as a Basis

    -The fastest way to get started is to take an existing implementation and -translate it for your new platform. Choose an implementation whose architecture -is as close as possible to your target. -
      -
    • -DirectSound Implementation - pa_win_ds - Uses a timer callback for the -background "thread". Polls a circular buffer and writes blocks of data -to keep it full.
    • - -
    • -Windows MME - pa_win_wmme - Spawns an actual Win32 thread. Writes blocks -of data to the HW device and waits for events that signal buffer completion.
    • - -
    • -Linux OSS - pa_linux - Spawns a real thread that writes to the "/dev/dsp" -stream using blocking I/O calls.
    • -
    -When you write a new implementation, you will be using some code that is -in common with all implementations. This code is in the folder "pa_common". -It provides various functions such as parameter checking, error code to -text conversion, sample format conversion, clipping and dithering, etc. -

    The code that you write will go into a separate folder called "pa_{os}_{api}". -For example, code specific to the DirectSound interface for Windows goes -in "pa_win_ds". -

    -Read Docs and Code

    -Famialiarize yourself with the system by reading the documentation provided. -here is a suggested order: -
      -
    1. -User Programming Tutorial
    2. - -
    3. -Header file "pa_common/portaudio.h" which defines API.
    4. - -
    5. -Header file "pa_common/pa_host.h" for host dependant code. This definces -the routine you will need to provide.
    6. - -
    7. -Shared code in "pa_common/pa_lib.c".
    8. - -
    9. -Docs on Implementation of Start/Stop -code.
    10. -
    - -

    -Implement  Output to Default Device

    -Now we are ready to crank some code. For instant gratification, let's try -to play a sine wave. -
      -
    1. -Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c" -and the implementation specific file you are creating.
    2. - -
    3. -For now, just stub out the device query code and the audio input code.
    4. - -
    5. -Modify PaHost_OpenStream() to open your default target device and get everything -setup.
    6. - -
    7. -Modify PaHost_StartOutput() to start playing audio.
    8. - -
    9. -Modify PaHost_StopOutput() to stop audio.
    10. - -
    11. -Modify PaHost_CloseStream() to clean up. Free all memory that you allocated -in PaHost_OpenStream().
    12. - -
    13. -Keep cranking until you can play a sine wave using "patest_sine.c".
    14. - -
    15. -Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".
    16. - -
    17. -To test your Open and Close code, try "patest_many.c".
    18. - -
    19. -Now test to make sure that the three modes of stopping are properly supported -by running "patest_stop.c".
    20. - -
    21. -Test your implementation of time stamping with "patest_sync.c".
    22. -
    - -

    -Implement Device Queries

    -Now that output is working, lets implement the code for querying what devices -are available to the user. Run "pa_tests/pa_devs.c". It should print all -of the devices available and their characteristics. -

    -Implement Input

    -Implement audio input and test it with: -
      -
    1. -patest_record.c - record in half duplex, play back as recorded.
    2. - -
    3. -patest_wire.c - full duplex, copies input to output. Note that some HW -may not support full duplex.
    4. - -
    5. -patest_fuzz.c - plug in your guitar and get a feel for why latency is an -important issue in computer music.
    6. - -
    7. -paqa_devs.c - try to open every device and use it with every possible format
    8. -
    - -

    -Debugging Tools

    -You generally cannot use printf() calls to debug real-time processes because -they disturb the timing. Also calling printf() from your background thread -or interrupt could crash the machine. So PA includes a tool for capturing -events and storing the information while it is running. It then prints -the events when Pa_Terminate() is called. -
      -
    1. -To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h" -from a (0) to a (1).
    2. - -
    3. -Link with "pa_common/pa_trace.c".
    4. - -
    5. -Add trace messages to your code by calling:
    6. - -
         void AddTraceMessage( char *msg, int data ); -
      for example -
         AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", -past->past_NumCallbacks ); -
    7. -Run your program. You will get a dump of events at the end.
    8. - -
    9. -You can leave the trace messages in your code. They will turn to NOOPs -when you change TRACE_REALTIME_EVENTS back to (0).
    10. -
    - -

    -Delivery

    -Please send your new code along with notes on the implementation back to -us at "http://www.portaudio.com". -We will review the implementation and post it with your name. If you had -to make any modifications to the code in "pa_common" or "pa_tests" please -send us those modifications and your notes. We will try to merge your changes -so that the "pa_common" code works with all implementations. -

    If you have suggestions for how to make future implementations easier, -please let us know. -
    THANKS! -
      - - diff --git a/docs/pa_impl_startstop.html b/docs/pa_impl_startstop.html deleted file mode 100644 index 0f2d0ce..0000000 --- a/docs/pa_impl_startstop.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - PortAudio Implementation - Start/Stop - - -  -

    - - - -
    -
    -

    -PortAudio Implementation

    -
    - -

    -Starting and Stopping Streams

    -PortAudio is generally executed in two "threads". The foreground thread -is the application thread. The background "thread" may be implemented as -an actual thread, an interrupt handler, or a callback from a timer thread. -

    There are three ways that PortAudio can stop a stream. In each case -we look at the sequence of events and the messages sent between the two -threads. The following variables are contained in the internalPortAudioStream. -

    int   past_IsActive;     -/* Background is still playing. */ -
    int   past_StopSoon;     /* Stop -when last buffer done. */ -
    int   past_StopNow;      /* -Stop IMMEDIATELY. */
    - -

    -Pa_AbortStream()

    -This function causes the background thread to terminate as soon as possible -and audio I/O to stop abruptly. -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Foreground ThreadBackground Thread
    sets StopNow
    sees StopNow
    clears IsActive, stops thread
    waits for thread to exit
    turns off audio I/O
    - -

    -Pa_StopStream()

    -This function stops the user callback function from being called and then -waits for all audio data written to the output buffer to be played. In -a system with very low latency, you may not hear any difference between -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Foreground ThreadBackground Thread
    sets StopSoon
    stops calling user callback
    continues until output buffer empty
    clears IsActive, stops thread
    waits for thread to exit
    turns off audio I/O
    - -

    -User callback returns one.

    -If the user callback returns one then the user callback function will no -longer be called. Audio output will continue until all audio data written -to the output buffer has been played. Then the audio I/O is stopped, the -background thread terminates, and the stream becomes inactive. -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Foreground ThreadBackground Thread
    callback returns 1
    sets StopSoon
    stops calling user callback
    continues until output buffer empty
    clears IsActive, stops thread
    waits for thread to exit
    turns off audio I/O
    - -
      - - diff --git a/docs/pa_tut_asio.html b/docs/pa_tut_asio.html deleted file mode 100644 index 1c3e5bf..0000000 --- a/docs/pa_tut_asio.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Compiling for ASIO (Windows or Macintosh)

    - -
    ASIO is a low latency audio API from Steinberg. To compile -an ASIO application, you must first download -the ASIO SDK from Steinberg. You also need to obtain ASIO drivers for -your audio device. -

    Note: I am using '/' as a file separator below. On Macintosh replace -'/' with ':'. On Windows, replace '/' with '\'. -

     To use ASIO with the PortAudio library add the following source -files to your project: -

    -
    pa_asio/pa_asio.cpp
    -
    -and also these files from the ASIO SDK: -
    -
    common/asio.cpp
    -host/asiodrivers.cpp
    -host/asiolist.cpp
    -
    -and add these directories to the path for include files -
    -
    asiosdk2/host/pc   (for Windows)
    -asiosdk2/common
    -asiosdk2/host
    -
    -You may try compiling the "pa_tests/patest_saw.c" file first because it -is the simplest.
    -home | -contents -| previousnext - - diff --git a/docs/pa_tut_callback.html b/docs/pa_tut_callback.html deleted file mode 100644 index f5ccaf0..0000000 --- a/docs/pa_tut_callback.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Writing a Callback Function

    - -
    To write a program using PortAudio, you must include the "portaudio.h" -include file. You may wish to read "portaudio.h" -because it contains a complete description of the PortAudio functions and -constants. -
    -
    #include "portaudio.h"
    -
    -The next task is to write your custom callback function. It is a function -that is called by the PortAudio engine whenever it has captured audio data, -or when it needs more audio data for output. -

    Your callback function is often called by an interrupt, or low level -process so you should not do any complex system activities like allocating -memory, or reading or writing files, or printf(). Just crunch numbers and -generate audio signals. What is safe or not safe will vary from platform -to platform. On the Macintosh, for example, you can only call "interrupt -safe" routines. Also do not call any PortAudio functions in the callback -except for Pa_StreamTime() and Pa_GetCPULoad(). -

    Your callback function must return an int and accept the exact parameters -specified in this typedef: -

    -
    typedef int (PortAudioCallback)(
    -               void *inputBuffer, void *outputBuffer,
    -               unsigned long framesPerBuffer,
    -               PaTimestamp outTime, void *userData );
    -
    -Here is an example callback function from the test file "patests/patest_saw.c". -It calculates a simple left and right sawtooth signal and writes it to -the output buffer. Notice that in this example, the signals are of float -data type. The signals must be between -1.0 and +1.0. You can also use -16 bit integers or other formats which are specified during setup. You -can pass a pointer to your data structure through PortAudio which will -appear as userData. -
    -
    int patestCallback(  void *inputBuffer, void *outputBuffer,
    -                     unsigned long framesPerBuffer,
    -                     PaTimestamp outTime, void *userData )
    -{
    -    unsigned int i;
    -/* Cast data passed through stream to our structure type. */
    -    paTestData *data = (paTestData*)userData;
    -    float *out = (float*)outputBuffer;
    -        
    -    for( i=0; i<framesPerBuffer; i++ )
    -    {
    -    /* Stereo channels are interleaved. */
    -        *out++ = data->left_phase;              /* left */
    -        *out++ = data->right_phase;             /* right */
    -
    -    /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
    -        data->left_phase += 0.01f;
    -    /* When signal reaches top, drop back down. */
    -        if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
    -
    -    /* higher pitch so we can distinguish left and right. */
    -        data->right_phase += 0.03f; 
    -        if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
    -    }
    -    return 0;
    -}
    -
    -
    -home | -contents -| previousnext - - diff --git a/docs/pa_tut_devs.html b/docs/pa_tut_devs.html deleted file mode 100644 index 1756992..0000000 --- a/docs/pa_tut_devs.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Querying for Available Devices

    - -
    There are often several different audio devices available in -a computer with different capabilities. They can differ in the sample rates -supported, bit widths, etc. PortAudio provides a simple way to query for -the available devices, and then pass the selected device to Pa_OpenStream(). -For an example, see the file "pa_tests/pa_devs.c". -

    To determine the number of devices: -

    -
    numDevices = Pa_CountDevices();
    -
    -You can then query each device in turn by calling Pa_GetDeviceInfo() with -an index. -
    -
    for( i=0; i<numDevices; i++ ) {
    -     pdi = Pa_GetDeviceInfo( i );
    -
    -It will return a pointer to a PaDeviceInfo structure which is -defined as: -
    -
    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 nativeSampleFormat;
    -}PaDeviceInfo;
    -
    -If the device supports a continuous range of sample rates, then numSampleRates -will equal -1, and the sampleRates array will have two values, the minimum  -and maximum rate. -

    The device information is allocated by Pa_Initialize() and freed by -Pa_Terminate() so you do not have to free() the structure returned by Pa_GetDeviceInfo().

    -home | -contents -| previousnext - - diff --git a/docs/pa_tut_explore.html b/docs/pa_tut_explore.html deleted file mode 100644 index 91c08a5..0000000 --- a/docs/pa_tut_explore.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Exploring PortAudio

    - -
    Now that you have a good idea of how PortAudio works, you can -try out the test programs. -
      -
    • -For an example of playing a sine wave, see "pa_tests/patest_sine.c".
    • - -
    • -For an example of recording and playing back a sound, see  "pa_tests/patest_record.c".
    • -
    -I also encourage you to examine the source for the PortAudio libraries. -If you have suggestions on ways to improve them, please let us know. if -you want to implement PortAudio on a new platform, please let us know as -well so we can coordinate people's efforts.
    -home | contents -| previous |  next - - diff --git a/docs/pa_tut_init.html b/docs/pa_tut_init.html deleted file mode 100644 index 91bfa8d..0000000 --- a/docs/pa_tut_init.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Initializing PortAudio

    - -
    Before making any other calls to PortAudio, you must call Pa_Initialize(). -This will trigger a scan of available devices which can be queried later. -Like most PA functions, it will return a result of type paError. -If the result is not paNoError, then an error has occurred. -
    -
    err = Pa_Initialize();
    -if( err != paNoError ) goto error;
    -
    -You can get a text message that explains the error message by passing it -to -
    -
    printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );
    -
    -
    -home | contents -| previousnext - - diff --git a/docs/pa_tut_mac.html b/docs/pa_tut_mac.html deleted file mode 100644 index bf3dafd..0000000 --- a/docs/pa_tut_mac.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Compiling for Macintosh

    - -
    To compile a Macintosh application with the PortAudio library, -add the following source files to your project: -
    -
    pa_mac:pa_mac.c
    -pa_common:pa_lib.c
    -pa_common:portaudio.h
    -pa_common:pa_host.h
    -
    -Also add the Apple SoundLib to your project. -

    You may try compiling the "pa_tests:patest_saw.c" file first because -it is the simplest.

    -home | -contents -| previousnext - - diff --git a/docs/pa_tut_mac_osx.html b/docs/pa_tut_mac_osx.html deleted file mode 100644 index 3af8c14..0000000 --- a/docs/pa_tut_mac_osx.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Compiling for Macintosh OS X

    - -
    To compile a Macintosh OS X CoreAudio application with the -PortAudio library: -

    Create a new ProjectBuilder project. You can use a "Tool" project to -run the PortAudio examples. -

    Add the following source files to your Project: -

    -
    pa_mac_core/pa_mac_core.c
    -pa_common/pa_lib.c
    -pa_common/portaudio.h
    -pa_common/pa_host.h
    -pa_common/pa_convert.c
    -
    -Add the Apple CoreAudio.framework to your project by selecting "Add FrameWorks..." -from the Project menu. -

    Compile and run the "pa_tests:patest_saw.c" file first because it is -the simplest.

    -home | -contents -| previousnext - - diff --git a/docs/pa_tut_open.html b/docs/pa_tut_open.html deleted file mode 100644 index 1621ef3..0000000 --- a/docs/pa_tut_open.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Opening a Stream using Defaults

    - -
    The next step is to open a stream which is similar to opening -a file. You can specify whether you want audio input and/or output, how -many channels, the data format, sample rate, etc. There are two calls for -opening streams, Pa_OpenStream() and Pa_OpenDefaultStream(). -

    Pa_OpenStream() takes extra  parameters which give you -more control. You can normally just use Pa_OpenDefaultStream() -which just calls Pa_OpenStream() with some reasonable -default values.  Let's open a stream for stereo output, using floating -point data, at 44100 Hz. -

    -
    err = Pa_OpenDefaultStream(
    -    &stream,        /* passes back stream pointer */
    -    0,              /* no input channels */
    -    2,              /* stereo output */
    -    paFloat32,      /* 32 bit floating point output */
    -    44100,          /* sample rate */
    -    256,            /* frames per buffer */
    -    0,              /* number of buffers, if zero then use default minimum */
    -    patestCallback, /* specify our custom callback */
    -    &data );        /* pass our data through to callback */
    -
    -If you want to use 16 bit integer data, pass paInt16 instead of -paFloat32.
    -home | contents -| previousnext - - diff --git a/docs/pa_tut_oss.html b/docs/pa_tut_oss.html deleted file mode 100644 index 1bb76f2..0000000 --- a/docs/pa_tut_oss.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Compiling for Unix OSS

    - -
    [Skip this page if you are not using Unix and OSS] -

    We currently support the OSS -audio drivers for Linux, Solaris, and FreeBSD. We hope to someday support -the newer ALSA drivers. -

      -
    1. -cd to pa_unix_oss directory
    2. - -
    3. -Edit the Makefile and uncomment one of the tests. You may try compiling -the "patest_sine.c" file first because it is very simple.
    4. - -
    5. -gmake run
    6. -
    -
    -home | -contents -| previousnext - - diff --git a/docs/pa_tut_over.html b/docs/pa_tut_over.html deleted file mode 100644 index baa9920..0000000 --- a/docs/pa_tut_over.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Overview of PortAudio

    - -
    PortAudio is a library that provides streaming audio input -and output. It is a cross-platform API (Application Programming Interface) -that works on Windows, Macintosh, Unix running OSS, SGI, BeOS, and perhaps -other platforms by the time you read this. This means that you can write -a simple 'C' program to process or generate an audio signal, and that program -can run on several different types of computer just by recompiling the -source code. -

    Here are the steps to writing a PortAudio application: -

      -
    1. -Write a callback function that will be called by PortAudio when audio processing -is needed.
    2. - -
    3. -Initialize the PA library and open a stream for audio I/O.
    4. - -
    5. -Start the stream. Your callback function will be now be called repeatedly -by PA in the background.
    6. - -
    7. -In your callback you can read audio data from the inputBuffer and/or write -data to the outputBuffer.
    8. - -
    9. -Stop the stream by returning 1 from your callback, or by calling a stop -function.
    10. - -
    11. -Close the stream and terminate the library.
    12. -
    -
    - -
    There is also another interface -provided that allows you to generate audio in the foreground. You then -simply write data to the stream and the tool will not return until it is -ready to accept more data. This interface is simpler to use but is usually -not preferred for large applications because it requires that you launch -a thread to perform the synthesis. Launching a thread may be difficult -on non-multi-tasking systems such as the Macintosh prior to MacOS X. -

    Let's continue by building a simple application that will play a sawtooth -wave. -

    Please select the page for the specific implementation you would like -to use: -

    -or continue with the next page of the programming -tutorial.
    -home | -contents -| previous - - diff --git a/docs/pa_tut_pc.html b/docs/pa_tut_pc.html deleted file mode 100644 index 87e5f9a..0000000 --- a/docs/pa_tut_pc.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Compiling for Windows (WMME or DirectSound)

    - -
    To compile PortAudio for Windows, you can choose between two -options. One implementation uses the DirectSound API. The other uses the -Windows MultiMedia Extensions API (aka WMME or WAVE). -

    Some advantages of using DirectSound are that DirectSound may have lower -latency than WMME, and supports effects processing plugins. But one disadvantage -is that DirectSound is not installed on all PCs, and is not well supported -under Windows NT. So WMME is the best choice for most projects. -

    For either implementation add the following source files to your project: -

    -
    pa_common\pa_lib.c
    -pa_common\portaudio.h
    -pa_common\pa_host.h
    -
    -Link with the system library "winmm.lib". For Visual C++: -
      -
    1. -select "Settings..." from the "Project" menu,
    2. - -
    3. -select the project name in the tree on the left,
    4. - -
    5. -choose "All Configurations" in the popup menu above the tree,
    6. - -
    7. -select the "Link" tab,
    8. - -
    9. -enter "winmm.lib", without quotes, as the first item in the "Object/library -modules:" field.
    10. -
    -WMME - To use the WMME implementation, add the following source -files to your project: -
    pa_win_wmme/pa_win_wmme.c
    -DirectSound - If you want to use the DirectSound implementation -of PortAudio then you must have a recent copy of the free -DirectX -SDK for Developers from Microsoft installed on your computer. To compile -an application add the following source files to your project: -
    -
    pa_win_ds\dsound_wrapper.c
    -pa_win_ds\pa_dsound.c
    -
    -Link with the system library "dsound.lib" using the procedure described -above for "winmm.lib".
    - -
    You might try compiling the "pa_tests\patest_saw.c" file first -because it is the simplest.
    -home | -contents -| previousnext - - diff --git a/docs/pa_tut_run.html b/docs/pa_tut_run.html deleted file mode 100644 index 5c70d08..0000000 --- a/docs/pa_tut_run.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Starting and Stopping a Stream

    - -
    The stream will not start running until you call Pa_StartStream(). -Then it will start calling your callback function to perform the audio -processing. -
    -
    err = Pa_StartStream( stream );
    -if( err != paNoError ) goto error;
    -
    -At this point, audio is being generated. You can communicate to your callback -routine through the data structure you passed in on the open call, or through -global variables, or using other interprocess communication techniques. -Please be aware that your callback function may be called at interrupt -time when your foreground process is least expecting it. So avoid sharing -complex data structures that are easily corrupted like double linked lists. -

    In many of the tests we simply sleep for a few seconds so we can hear -the sound. This is easy to do with Pa_Sleep() which will sleep for some -number of milliseconds. Do not rely on this function for accurate scheduling. -it is mostly for writing examples. -

    -
    /* Sleep for several seconds. */
    -Pa_Sleep(NUM_SECONDS*1000);
    -
    -When you are through, you can stop the stream from the foreground. -
    -
    err = Pa_StopStream( stream );
    -if( err != paNoError ) goto error;
    -
    -You can also stop the stream by returning 1 from your custom callback function.
    -home | contents -| previousnext - - diff --git a/docs/pa_tut_rw.html b/docs/pa_tut_rw.html deleted file mode 100644 index 93c7b8b..0000000 --- a/docs/pa_tut_rw.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Blocking Read/Write Functions

    - -
    [Note: These functions are not part of the official PortAudio -API. They are simply built on top of PortAudio as an extra utility. Also -note that they are under evaluation and their definition may change.] -

    There are two fundamentally different ways to design an audio API. One -is to use callback functions the way we have already shown. The callback -function operates under an interrupt or background thread This leaves the -foreground application free to do other things while the audio just runs -in the background. But this can sometimes be awkward. -

    So we have provided an alternative technique that lets a program generate -audio in the foreground and then just write it to the audio stream as if -it was a file. If there is not enough room in the audio buffer for more -data, then the write function will just block until more room is available. -This can make it very easy to write an audio example. To use this tool, -you must add the files "pablio/pablio.c" and "pablio/ringbuffer.c" to your -project. You must also: -

    -
    #include "pablio.h"
    -
    -Here is a short excerpt of a program that opens a stream for input and -output. It then reads a block of samples from input, and writes them to -output, in a loop.  The complete example can be found in "pablio/test_rw.c". -
    -
        #define SAMPLES_PER_FRAME     (2)
    -    #define FRAMES_PER_BLOCK    (1024)
    -    SAMPLE          samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
    -    PaError         err;
    -    PABLIO_Stream  *aStream;
    -
    -/* Open simplified blocking I/O layer on top of PortAudio. */
    -    err = OpenAudioStream( &rwbl, SAMPLE_RATE, paFloat32,
    -                         (PABLIO_READ_WRITE | PABLIO_STEREO) );
    -    if( err != paNoError ) goto error;
    -
    -/* Process samples in the foreground. */
    -    for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
    -    {
    -    /* Read one block of data into sample array from audio input. */
    -        ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK );
    -    /*
    -    ** At this point you could process the data in samples array,
    -    ** and write the result back to the same samples array.
    -    */
    -    /* Write that same frame of data to output. */
    -        WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK );
    -    }
    -
    -    CloseAudioStream( aStream );
    -
    -
    -home | -contents -| previousnext - - diff --git a/docs/pa_tut_term.html b/docs/pa_tut_term.html deleted file mode 100644 index 1c72209..0000000 --- a/docs/pa_tut_term.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Terminating PortAudio

    - -
    You can start and stop a stream as many times as you like. -But when you are done using it, you should close it by calling:
    - -
    -
    -
    err = Pa_CloseStream( stream );
    -if( err != paNoError ) goto error;
    -
    -Then when you are done using PortAudio, you should terminate the whole -system by calling: -
    -
    Pa_Terminate();
    -
    -That's basically it. You can now write an audio program in 'C' that will -run on multiple platforms, for example PCs and Macintosh. -

    In the rest of the tutorial we will look at some additional utility -functions, and a different way of using PortAudio that does not require -the use of a callback function.

    -home | contents -| previousnext - - diff --git a/docs/pa_tut_util.html b/docs/pa_tut_util.html deleted file mode 100644 index f4b5475..0000000 --- a/docs/pa_tut_util.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    -Utility Functions

    - -
    Here are several more functions that are not critical, but -may be handy when using PortAudio. -

    Pa_StreamActive() returns one when the stream in playing audio, zero -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 number of samples that have been generated. -PaTimeStamp is a double precision number which is a convenient way to pass -big numbers around even though we only need integers. -
    -
    PaTimestamp Pa_StreamTime( PortAudioStream *stream );
    -
    -The "CPU Load" is a fraction of total CPU time consumed by the stream's -audio processing. 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 );
    -
    -
    -home | -contents | previous -|  next - - diff --git a/docs/pa_tutorial.html b/docs/pa_tutorial.html deleted file mode 100644 index 1371c44..0000000 --- a/docs/pa_tutorial.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - PortAudio Tutorial - - -  -
    - - - -
    -
    -

    -PortAudio Tutorial

    -
    - -

    Copyright 2000 Phil Burk and Ross Bencina -

    -Table of Contents

    - -
    Overview of PortAudio -
    Compiling for Macintosh OS 7,8,9 -
    Compiling for Macintosh OS X -
    Compiling for Windows (DirectSound and WMME) -
    Compiling for ASIO on Windows or Mac OS -8,9 -
    Compiling for Unix OSS -
    Writing a Callback Function -
    Initializing PortAudio -
    Opening a Stream using Defaults -
    Starting and Stopping a Stream -
    Cleaning Up -
    Utilities -
    Querying for Devices -
    Blocking Read/Write Functions -
    Exploring the PortAudio Package
    -home | contents | -previous |  next - - diff --git a/docs/portaudio_h.txt b/docs/portaudio_h.txt deleted file mode 100644 index 6d60086..0000000 --- a/docs/portaudio_h.txt +++ /dev/null @@ -1,425 +0,0 @@ -#ifndef PORT_AUDIO_H -#define PORT_AUDIO_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * 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 -} 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 ); - -/* - Return host specific error. - This can be called after receiving a paHostError. -*/ -long Pa_GetHostError( void ); - -/* - Translate the 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 devices. - - The floating point representation uses +1.0 and -1.0 as the respective - maximum and minimum. - -*/ - -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)) /* unsigned 8 bit, 128 is "ground" */ -#define paCustomFormat ((PaSampleFormat) (1<<16)) - -/* - Device enumeration mechanism. - - Device ids range from 0 to Pa_CountDevices()-1. - - Devices may support input, output or both. Device 0 is always the "default" - device and should support at least stereo in and out if that is available - on the taget platform _even_ if this involves kludging an input/output - device on platforms that usually separate input from output. Other platform - specific devices are specified by positive device ids. -*/ - -typedef int PaDeviceID; -#define paNoDevice -1 - -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; - - -int Pa_CountDevices(); -/* - Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() - - Return the default device ID or paNoDevice if there is no devices. - 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 ID by using - the supplied application "pa_devs". -*/ -PaDeviceID Pa_GetDefaultInputDeviceID( void ); -PaDeviceID Pa_GetDefaultOutputDeviceID( void ); - -/* - PaTimestamp is used to represent a continuous sample clock with arbitrary - start time useful for syncronisation. The type is used in the outTime - argument to the callback function and the result of Pa_StreamTime() -*/ - -typedef double PaTimestamp; - -/* - Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure - referring to the device specified by id. - If id is out of range the function returns NULL. - - The returned structure is owned by the PortAudio implementation and must - not be manipulated or freed. The pointer is guaranteed to be valid until - between calls to Pa_Initialize() and Pa_Terminate(). -*/ - -const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID ); - -/* - PortAudioCallback is implemented by clients of the portable audio api. - - 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 nonzero 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 - nonzero 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. - - [ suggestions? ] -*/ - -#define paNoFlag (0) -#define paClipOff (1<<0) /* disable defult 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 - device input record for the device specified in the inputDevice parameter. - If inputDevice is paNoDevice numInputChannels is ignored. - - inputSampleFormat is the 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 sound devices 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 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. 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 behavior 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: - Apon 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 nonzero 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 ouput 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 (same 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 when the stream is playing audio, - zero 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 for the stream in samples. - This time may be used as a time reference (for example syncronising audio to - MIDI). -*/ - -PaTimestamp Pa_StreamTime( PortAudioStream *stream ); - -/* - The "CPU Load" is a fraction of total CPU time consumed by the - stream's audio processing. - 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 ); - -/* - Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for - 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 ); - -/* - Sleep for at least 'msec' milliseconds. - You may sleep longer than the requested time so don't rely - on this for accurate musical timing. -*/ -void Pa_Sleep( long msec ); - -/* - Return size in bytes of a single sample in a given PaSampleFormat - or paSampleFormatNotSupported. -*/ -PaError Pa_GetSampleSize( PaSampleFormat format ); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* PORT_AUDIO_H */ diff --git a/docs/portaudio_icmc2001.pdf b/docs/portaudio_icmc2001.pdf deleted file mode 100644 index dd074b7d334d9b0d4415330c2a123131aa130115..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50968 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
    _indHVG)3^ZrAZg!fH65_!ltCUc#av(>q zqIL4E1T4iIn%nYCtx-Cd3gPrq)Osv{=t_kE&hSyhsWXS2 znn+n^S+{qiB-ko2b>l{rA-#5}2BB*ezh9NkiysE1!Fu7MPL8-uJ;*K3K1uP7j2kR8 z=Y(w&5gW`xZz91i3|>~^9^4bpcd;1`3s)?I^511i^*aow)+xW{4G`Ok`lzO6`ADT1 zOir`A9y>zsAwD0h&wQj9RSs^VJa;BG)NxBMrY$|w!_9z$Rh;xDH0%g5!C%bF9vC#_*to0WPUkf zFAD%DTq*1qKDDYHzAd07RQzJo@(+jl^(NQOVt)HO;gV^DT@-8v67 zOYy2Fsv&#Cp)6M2b}M=wN<5fz!s-<>?+E|gp5BjuI{c&RgO(;FE!nfNZzb}AbGq5z z71cM1xp?J>CxyY~2xTVzi5~$hinUCK6sj(6h5_V?<#_F}u19Z4xQFf>_qm6v+$K!f zUezd%KI|9ZR6C0wZD&+D2|;K1T`QPRGKti}SjZ~po!c?<2W!`Bgp{5<$xSbNew{^U z;CvopecqDgvgtaxzGt3;uC^Tca$8B@YrMP&apjpP!Nk!|1^pM5g>FkpU9CFgD>1qT zcc|HB{5)`rSM@5(cxzi{=J)A{u7N(`;eB7FUb!t0>zN~HB&b&S+j693QYr4d?Qf?? zi;9LMEVPDIJ~3=13%s?M-uIk6HZ5y#u5ZrY;V$V2982TgY*Tz+(#I5)A}ErxFlX&P z7V&&+3b)u3T^ReZo|5TS>ymdT^0gKp^}KlQ)|Kg}ZV@o>#?WTa*tG|d=8TB*Yo%}f zEg_)k2nh+KDiHNf}54vtVa%*ZseIiukA}!r% zl)aj~YsG2U<5q6n=Hb)9P9*Nn(#mQfP13w@-8Fk7QLCTjwH!;2!M@tcm#)%yNjvF> zaeM52Lf!ojuY8&^dZ36e!H%yL+MWzO6+3+`^TRy7P|#FJ&n@}uw~)PWQGj&O!l_8@ z#Y3X^LbelYvSh0e5;6nyAObsw#RZ5D25q{6a7$yI*mh3kHqvS zA1hPE6c!&-#2Cz$t+%=p^-)uB5l?LP=@1G7UatBqtYxeyC-wIRId!j}7g7-bwFu

    &gNSFrDZ*$W4OAjDCKcIb)x)gQpF4a^Jqd-5UNW` zmDh_m>a8Xx?dH!|!=ZZ$32D;$b}0HeeGc*KQoAt^Oz{kt~N969_QJgN>80Nx1EBt zMHxO5bdG)t-iizCi-QiQI|pgI+FUg9JY_h{c-lSTZhzXMwCS>C{EeL1m8{HmfatTe zPn!T;gjR={2fuu&@oN%;i{aimhq<6Z?i*37kC)>T5{MEx1ruEwDJgkh0_o7zzG#7( zZsz zlU=5*tM^rqThQ=XBZU?@MN<4#OL;O&JU7If(DMW3#8m)jmufk;nNRdK!6LvVl)knK z$lcZpHDphk%W$(HUF9wXE%2{$qK^;X;-K8BfU?4`uV{=WG%O|#fO)HQQV_FD_@n?X zqrh!L;JBdB@+sAh!OX-MU_!K+>%9=Xj(9KO5w3X_-cfvfi=%!3v{$QIV#0|_;_?!@ zLY(r8D~F%Bn7sD8A8n3Gbw5|kHEwsGF?WCbb8Sy*O$W!64aM3(`@C%x)+cn1m^Grc z&n~DJs8)g6rl(s{cRgou~^pV z8qjI&8tsMRWT#Z`OD6I(p!`e+#*}S&huvF5H1?Yq-C-6T7oyXNV0?ox_C6F>D2SH^ zOg$4437D#H6@==8aGkTK>?O;N99uwB8sJK7=UbcWthM)Vyf(WL`B}LaK)uZvP{td^ z&)HLu4&p|UVWgxL`;>dHDPyncs{mkSrht!ghTNtKOLV^k#?$7yltSC7oNBhMQvUc!ei#o~u2{31`6p*z$*V znUM{9mHgr?MY!hKut$`yLtbwjcfE(@8xo3lxHTrMjVcT8McQ_KIZ++e>o)4N<)DVa zFB&izJ`#JVpC`fcm)}4AuruFPs*OrsYimH;qrW=zFE!e1X-1@6QMTXi&vN3gaEMA8 zIZT`Ou@*iF%C3LN;M48!h`<%=4rKyDHS{fEdqOf&-fhIfY3&dFJ}$oSugnUNGLE3W7rX5x$poZ$BI38&73nYghG z=Qt7bHwZ~_LFefhCzzjCvAwJP0CT8{j1Zj>trl*4!VTN~NwL?saLbkfTQiWyKX8uK zmP4&>Ng$3Pm1pni_TS@94{)T2t{lx%vAzbD+fD}hI5fD z<;}P3OTe3Eg@r0go+JC@@f?in+=@J$-9BBF_b3HpJUf>yqv$S%TVDeTjMu1fcQy4D zzncw=H>k;|buU+LR@{7Hwh_}TwihSCxpGr+n;V*@)9@69@%kk+pk7L=f}&}N4619? z;iWHS?jNorzbehgzACD@=Hni8@?B7EScoZ)lsx9l1$=h|d#B(WW;cFgTyq^majQH1 zqBqucTOGA}R;mh8z{pdovTJqQFmRsr>BlI6o<_SA)Ni+ z_?eWxg(1C%`EJHXJjYqz_0uW9lq%AqV4R0xVOi&AxsKp{ryetb@ozJOI~OXri$d*? z0^s%&9rbEw@l_B0L9O0m1N*A%rkqH_3ny%?qmGza?+JHZgoiJk4Qi^fme{S?H{UBx zTo6Jo)B~kqbN@)zO%T#78rCe<-Q)QY-#OyR#1Q6Js+fuhhYt&`D!X$k#2Q;&F&@E? z)2!4LHMW>`*G^_Obd2xgfE5hv=6s8UmR*HQQX@IDFDJM?C!`r>2-4 zg&n7iJgH$uvPQm2ws$OI?~K?#y1}fnl~R-*Wf;kOQStQIOx2odV*fTN!C?;E)d72- zVQLlWo#$b>$Lr~?L#ON5ypQ6~-*V|D;)C-VxdT-cyQ2+j$FyO`XLtZ0O zt(pZD-3Y^DPbw;2lxn7LIgSP5Y=4jGZHn{Y;zmTd&M7w6Z&lMh_d>_f$fND%Uoi;D-%{(faytaU_kLVk4-f(ac*m}bARL>V9lF@zZLU+7} zt+kz)3-MMzl`NT&vs`j1IH z>%1Q>uw?pW5;`iw#;z{y3=iIcdPV{_Rk)z=uV*e%WhV}ucc@UU!kP&D57&f-?C*{> zn&yl6FR_wNHJZOtt8G+xSD!I4^(IiKR)h6dTZ@xFS9BWV0|Pn3Z9YEmP0${ z3cXlg73qbZZOfU^nVs*wSa#l852l|#$mE<`D=F8z531rV6Y8!~$~%-*ddHO52)3UY zFF)MAM{Y#)>!qI4t!j_3(!~q?6KZ zE<9`Pbx3b}!}`uuPq|VqU%vLgmx4U2D}po5&QWsHQe`_Tsjd zEnv1m-V9F55N*bldN>(5N(wqKOXUvfvU@_HT;&3!HZs?P!=x&Uz@ zj*hE4`c7V7`}NK4#NeG_m*}^rJjc|Q`Co3wb8zaD)_41e)sVeQx5GoqBKYE*NQ z>YW}=G9m(gc#MjYr@|=i_k&DGk`0hs*DWH3nwF46bLmd>6F@RTQ=N*45wp56mCw%# z5Cjx+P6jnwLRq5#5opaeE7Gj18$5OLA;AhXSL0WcUBjkqX#j-=ez0+JZ7_ROniFLN z3l17Z6_PwxqQy^2HQ3`x(C=uUmZ01doEKz;r!f`jCd?R~6KA6!>!B@cww26cv;RmK zHSB~U)#z8EQo#8Eo~kMr(njS?(gep@b`vv~O7cg>TK4zY(%ACDl+MsUAbD>Y5eno) zq2({l$s&M_yjjpuT@MKbveeJ%1}+5?3W=P==^j3J(D;5cJ+egUnbqU)(i$^BJQ(R66BhbS7t53y|#ZcLN_~NxSfz-5ZoddPZC}+ zrp0svO?zx|CNV6nuc*VtFE9O?0)bG>)1%VY)mLxie8qPLG-U1W()7O32e#~yZ5EZ>rUZS@R(W(jB&v5SF<&kr9s22ttE!W*G{M^8x(2{Ll`8UNHv7NXZ?F zP>UA^^@`F~gz_!X;SvB`z3^MXH%--_Otuoj2=i>e$uT|J?u6bPCF|*YJMRhTLM_W9 zP^T#N8A&dma_2=Csj0O0FK`?Aq9dJV?G_5Pu1sV?FUbjCWcm_B7D;lV(401+6``QA z-K6LOERHN`H7ev~Y?X^>prF}EiA;;z?|32dW0>? zIV=azLhhQ5E1w{e191vax(1A&e?Za#Z8gJUL2oV3g(h z==wNK?}HwRV9--0B}~%0lRU?%2!=E-pDP;XPdoGIla$276Y8oU6Ez{Zm{GQOt^5LK za9S+h6rtbB9Z?)ZIh^O*RG6QJ*-clfSB-m5`Po6Db7DQx)*=Q}!CNqsLd|0GgfKx% zq-1-2G8@P3Pj^a>@LIW9Q7E4`-6fagKp;s@{>FW@TE zK;0w#Wnbs1v2Ee&+V@%6p(uJ7aolo2iOxqw{Gj19-h(_pU)KkUjh~kdhk+SrW8kRBZm3ek z{DjrQb;rC>){K4(NaHh_?1TaJY=*!(E8ob{>I#@Bb|q#wLdde(wp_f;h|Ls+bE6H8 zSIQV%yhVYG4{AkOy~zODxT-+sV6Inny_R)?RUeMN;~$sGMyo&nSSG-0d2L#h4PZ#r zyeGoR8J?7)JNYrS|2l_?m;GVlS+QN}Yuc{3CuFb9XG(l~_w|Y%tBRoWUwaKlGdRWC z42mz^X9}S&P^Yp!NM7$NOOhbF?;Yl24k(_;mo zH7~x>3^?OOi%V5^+MnsDGN?fKm!B^0GQXo4AETJl^G2G%t^_wDp}?pC zX16-pkB>QBf(m$hPx*!hGuL(w9?V(Xn0OaWWhMOUfP zb~}Ays1M;)mJ%EijZ^XX${tQ_|5)6>YTnjOZ-MFq+c=9z#~wW3TT68r=bJ|x*(KiY zN#=9#PxTqvmAwJp$9FmuYH3V!^P(kXbz8)W&$k6-3w11=B-Qjp?ff3e;*^HF(ckX8 z9VsuE?aEI=X-C+{+>y~l2{j4NQuWVV7O9PpIN1y)`}$)RmXR;QZ(5>d zTX&T@6(Y=EYQYFb*+K(nE7e}B_8yq<-SNu<5Me?Ee!VEAyDt64dfj4+`3TT|qcAbH zjFoD;DfanEE7eC}y(DlIn3;Vy1x7>TH&QBaF6eZ@-aopH>T$Oe5rve9r$;F+ zFd41&B=di;_TEuVZR`3lEf^r72BaH$LJx!v8hVG&k)retQWZO$&|9bin-Y4JCRORu zI|ztKmo803Mg7?Oo_l}i9N8b|j&c86gz>ERopU{F&N1eC-shzyY)R#%Un!#Brc4tJ zw4*I-6^hR}5on=PLQ%3mOA$NV0kzC!mu8@X>S?p@!1+!~d z#pF1=`52i)d_~=Aj_9~mB3V+hd@MXph6j|NP79mI&dx;_uS7a?V26Cmq$qRgkEu}u zG3C|SBEM*Ntdcq_C1zJUrs^cAK!cpMiA%yb(mdHo1!`-O!P&ts|NQ9IO6s##a2bP^ zY?G$x2o|_Dq(94TS_W$E1(r8!fyBVyBQ*_MA~Azl#V8Fo$^y>YJXm=3F%J#%O(DxFSXuHJ{^%Nv zXt@xVRUJ)NA^E0?P_BxgpJD7Yf^j|KVRA1OfG}9DV{oF4J-Uiup<`LM-|cFg|7@Mr zdz@Bu^3s>Kf!rP|Nf@8{Xl<)po?Gnq*E(2DQBX`Ara<%L114ZOPBycmI|}-(r^IYs zedj$&lSh#c&7NKWd%w|Hr_!Q?!^N=1cQ8?QXo&G;l@uo*q!OF% z7^tK<*jkQ(^kE=f_OVO`>Vw{s$f1{}fmCIilaGZV zbKyf}k0-D=1AmdE-4O$^t8I2IrCQyZ6=H)qb1!;?`8tc@{KIq!k6w~?i+K0o%s!Vl ze(Z<>Rx*BJDDBNz*c;7RR=|e^;z3`03u-ADVHk)W)rtUyD$7Jo@jFoxN=g^=g$W%k zvXO@26QsmN?u|}-ty_2CIC#^QMOK?G(V52Fj{XC(Igk}-6N6Bt)w7IkvrS2mld?u9 zHKB*}u7gikVx=@@4z*G;e6!G>>1;i5_Fiu^6l3v?x)jsotXHD**K$_EBjxy$wQr<& zF0l$c(a@?NOqYE_Vma_tBbh#s2Z4@B?=?PDqkX4koJcAyB_Ze(NkK1)8~fPCp(=!p zl?{LhF^p0?oX}fKHCDpr?4U|W2Po&iiXH{m;eDyd2&jmh7E>szJlFP?C zT!xt~YiO3Wk$=>n`>XvApx<|{QgSFT{fMixl!v!*iE<7r#z&ku4(NsFn9gIBSU`<3 zwakxS=6oJNy~CFGQf2kUn^weOpm|x(@#VJ_^Ys|`Qqzt(Q+v9ieW>FZ*+hK%`|*X8 ztv+G(ZyGB4GM0XP>!X-r`Yy|Uf$}DeK&Vp`q%z8>l?y^8OOmF9F9o6DA)Od|d(yAmyL{CD-89=pTo83zu93Wk=PsrIu)f7Khe4nF%(SD&MW5p23F-}`B z$kR{Yyp~J5)>*jrQmf*n_NtCfkvhXVIcowHL*k)G!PZ#Q4`$O4$7B)#s%+!p)_BQ^ zxb)DHK88dQzsf|VzH7NtQVBI;hrP6I-sVeF!K4CMac6VuDVYCfDg?=-I@FwSl2_V; zLj7a>`dLQbiKDb1FxwqF8$Lh(K2F6eSWVoKVf-z;!btnP@KehjRMC}ct`lz`XQ`D$eqr+r_^B9#+k(Syff)H303yydKIMX0f? z+zGImEg)Erby;mTk?56?Y&?|FlWXraIrSoI1RsHxBKjt*$W#25eDw8Bgw%2#+p$5t z8uQhXB88}Y#;i(dbqpqrrvm*><>5C+^UoOiQ0eMm>GfByCY=;pevv&)j(9xh(oImK zLbjQcCOJe?*1%Qp(`2jHG+Qv<$d9fjoi&?3vItMYzSB7|$di4J&pxANybQOt2u6>aW5XFcsMpGSK>cgoOG{>OLMIJ*O-EUYE)04!ibK>ys^uG zGxCj@2nJa9bC+#=%sLoP8SXRuj-6*d9ps#{9NmQzQl>0zy1;;Qh(O+82^u-rjQO)@=yN#qYmf4 zYl6;a^Pg|`--2feNwIVEe`u{K`47Rfry#QeF#$01Iy;mx=G-_YSxi9Y$}pj2I!FY)Q1Zulc3dv7iq}Cg2EBN-O>%o*qGc^wao=9#8q{TL{Gz` z$E3XIKtqMxyaXu3po9Y-6*TVBKoxfP)Q$#Ek}-O3*7YorP6?}9F`Gf3gK@@@1L)Y& z-g3k-kb-OyV%N6fAdumcz~Y=81KhsL=Vum>7>{m?^P2FSSx3K^K4G%}!_U81X6`vI z627cMIg5Xk;32e^w2^{5P;R2Q*ID#3|9j6B?SMWf2zb?pAJ>@QsLybnRMKoE)_uug zpk$vfj6r;m#tj+$ap&jvP(t7w;j2}vBTDjvYBci2$K%i6LP?*cW#uk6dj1hY@r>Y0 zF+qOgM~PB0eR^X28oHzB9!N&|FoZ1mLQIz=>a4^XuLmZfp^zdL%AYezDQ>O#Q=)N| zLx7e%7`65V?x~+r)+0|e$Sbkzb`9}rThzaxhen}>l5aW5Zn-8n9wh-j)bvJ6&soC3PmFI!9e&KiuURT=CpD>K1@B(7;TT-{1uAE3qI9^`_rFONuv) z*JAZbq_sw>FnH4T=T$hk8b!(Hhli5xJ5rnE9*n2ATbTm+z>stN74kP<_!Xm(;4ZaQ zLB8k$hvZS?icSbPrM0|#kiP=1E0V8tZf-rzqInHRbrMAphJFNjt1SGG^DTI0&`!4f zlW*)oqqo+=>zjLx=GHf=ADjMai@y%AdMU7$6xh?K`T49tca3|c-JsfL&f2Yl@hxIP zN1ZPEqmMnpN|?}pV2;9=%UUz_JFld}aN1hzf^DtesFgN^yS2N8B3Xz6+LnGJ&2?Snp zu=$2CAq5ACI*|$aU1j2=8Y$v68UaNEGo8HEg-xUZn>GBd*H1pwMnAIM3{KPf5^ zqKrSh*JVw5bJC7rkrI=}b187Kx72tkG@(xbeRDwOerKyGFFDK2@nm*SZfBdQ_c<=|Mbfms! zu4#iE>n|GK2S$;NG9^j_Ktgs;jd(fq^VR4UD-GTUV8k^XB+S)xa0m?FLU6Trchb0V zdQ^=|b2_z_uK;009}i#(pYXv9{F*?vDG@ko@yIZQF*rf$2vrYF0p&g7!;}P7*2{zA zN!tw_@V2w=)sO{d)FZBV_0|)b*=jvx5^<6rPjC1}5SUbt?2X@(o5^B`Bdb6Tqh~@U zvS&?K=3MdWzF$#cq6|#Hg7E^D5#60Y0#^m_Fp0o(NybD?ntW+M`=}<(8K|QlA|tZL zl9klH$4dA@ttd;7xBD8scCCZ$$JvFvZb=r3{sX%{mLPWZ zf8iu0L|F6TD-?65P#LYVAac|en5YfiKpn*h*(;uT64W{L6FnyUp&69STMdqy3BH9( zfzyNmZhpW`F%<`*19~O@FXN{YnIcDiolUefHfHVi4n{U*^i9n1+wsO5MxWG;>Yma@ z`I{x&moGNwZwe0Z%+nnf>*6F)pRn1>pmd=P!pp97BCEc_#j88^fZD~#Z5tM7)6Yc{ zk~Sj1`q06MkWEu$A#dl40!RfiIT6Vmx2>+j^P}uJhh0EAE!R^L_ZO3d8H?}up0KZ# zKI1d{c^laAfWz}3iKZD7>w@Sg;c_UL_FSagwm#y;uLsZq9&GX@gX^HRwkYtkioFeYSpe2I#*bx%FE7BjV03 zRR8dn4LA*3UJzzD`v~901GO%&m`+_-*3dS3gU%F@E4su);qn~hROGTxAODC|Mq09J z&V<`C+x;DjXchf*`=leODzFz`EHRUtv>TA%O=a5G#9BzlpK5Vn^uagr6CWWKhL@Y-pJ6$PN-kiS_!+CQq-mR3N8F9OR)RH z@VJYOQcfW{&vP@<^3#%yC{r@$@jmte{;L4pIrX~cp4*FU2V=hM=8|)xo*r}?08Z-ddZ;=Nv#V}`5~i+k&m>>Hm=Q}cvDz^8OR_-5!kp|lW4sz=3){MI4 z@bPBBYoKpBc8NmSH$LVy*$1g4YZ~!^(o#`SR2jEWhBmJCDh4mkoDS-Qtg>XsfPU-S3rJYg? zwmb5p;wF5Hy;l+0k$+u9$wf7y?>1E$0I$?M=KugL2J6aplm=XZdZ_7D%ee0HbcdwE z?dhC$Xo(W9E83InaF>#7=&KN&Iunu-L0ZsOzl7s!yiS`vf%=Lw0PZf(P6f0Aw@n$+ zWXr6O&lyK~?FbQH|d? zPC!+Ciyz}d!_x&t*sbF&PAPES1tEJ?se)CJ_M`U&d2=Ksoo!(<#|bcT*CPa*gF=JWh=6v4f=d%$Rfxz@opz() zg3&oENt1k~CoeUZkgCPSdMSeiu5@0RwyUgPafYPS#Lr0hqo(}leIV*W*ff_ZM@2T( z&iLz~up3K>mhQH?Yt2u>m;|G4!FvOgHOk>0ECh-lSbc&-u5jq(Z0MEo=y55K`{`@0 zG24l07$R>Q=N0K4WT=aL(w&fkcC8vsTeIUz#fLq3ydsmP1aoy8AK`g?S~UYdHLs@^#_wdewtN!CDHaJDRw$`@|(*L!VUQiZ@VkI>fC1I1r~OSS|AO6 z@`#+gHzgD*z8eSyXW-o%Rw&ZF>?ZbXI}r^>hj`S)mP)Ug_0>Md(d>d=8BUWyLhfg- zhYOi>q_BVxU2RbwXGP_4Mtxwcfs&y{)N_w}#+ZO1FoxZLvr!9g?P-b(Q_chhbyd)3 zWuUu-vKoDG1WB0fPfgDyBo?2}D#;?v;&zU$^01v{)j)xvj}b5h+|PYu>A;kveCl)G zJFa>&+{rB}y4o!eN;!oH;P4}-+xX4^@8(8*3A?$gy>NjG~z5MdvOS1({&v8$}y z8>~EXR)T=c^rj)OVMKXF=}n*GpCk~#c;o|WNbnf?_t*cd6kLo+%G)Y>?GND zD=WuK{$ThNJ9j!*{#-YCCZt}#E+~aWTF)e;Js9&AcxQ{fJO7STs#`|&(=n>Zwf5Hd zIosE1acejW7fn0KVWBI1nwTX_Jmrsq(P}lb?XG9ZsT_sMhvYZycb8Y1=}MJ z#;0Tzl2byWUe+rYI2k{6YMmgxo!j-(k?9L?>0P@fy8dR*GHmvQGlm3*4s* z3ZPGux+TQETs6alHuK$AzoGCV^W`I9Sei!A{UWn(Vdlo)ei9$ze-iL8ovG=X)nSYr z3AQ(DZr~xj#_HQj-kNf@X&z;Fs%t!JEcUu<#IXwYQY3mc5HlDg#f25L3nJe0)7!OV zU=?Y>Hq-x7p1B5fP(+zZ`M-$pyLZy$a6o?c<+jW1G3dJ_I^(3cF%Nr$Ca+eC82cd}x}DZeJ@}pvPRmFp%qpt^ zKuo2*?aUYXRmbKtM?MNmH9z>^JxhO*7*Qlpb~bFPTQig@r;ORs>+xd@!>h*}rlBZ) z-Ls&^6w^Kj{p7Mz6~EF9{U;$kRX@5L)bf5Ze|NGoDjNL++yp1wjIJ#B!@g5cdKmxu z*DrFjNA))mHn=%8&#;!l?y#VgJvqTp3?@cc*S9;#@2b&A!8@$9qIEvsSQA%5?{3TE zp4C*KcsHT1F}?U>mZu@ttk+b1vR!>uptr|byyi?_%-vo@IG7id{-|$_t#5nDr(bVx z8*R}59Koo=exj8=F|EQh(h8q0@&*o_KALMa7W>sR;*kD?VJUUx#yZmM-UGPfDLQj0 z<#U%9XR(r#qis=Gv*KJ#S%Ev(bz_)Yfmqo~=q7oycxZ8>{#w$0!qbjmpBheGFB#$b zAJWF}7<&7npMKc9MFp(S&fNp)PF2y{dpUN{YvYvPcs^o=``_uVrlKfU0B`Om0$m4v>|SK~$9qS03MR!A)Y2Sh(cAZ?Oh(Q0RY2g_(h{yyf_A zZ!t<*AQlnOXw6fSwmr2xd~Q>ho6(C({B6?&dUejM${YWk69rwBIG@W(K)J~$b^|8dwlp7!sEKtC>tDAhCe@sD0 z>RHVEDD2f{0r#?RnhzPTdQLUJTgKeIya8l&Ys0T=&*sgCQXc?-5JOrMR}S9yXe;rO z*+65(m(mdLdW8_;e(dMBs}SZ8R=9_mm}k`M)~g6d0$YKW^^YnTNvGyGcmQgeO&yJX z11%Re!*X|dF0Ko);dOtj>SH|WAm&RVBYO@sSf&sG9&CQ%?($!t6x}pXXssT35Vpma z8*jJA&&N1_+zMly6)mJFXAiA@KFC81AQWBu)Ww(dxw&D-jE*xlzRqD**vWLAr5nBm zN>kS|wTZc29tmuESyC4e$f3_9!QKORT8a~{$T%hlr7@$NQ+zI)78+Z-LUFZOFbz^x z#z)Yk03WGy+aDRxpN)L3MdLkJ5u?9N$x*IvH&2dTRhfZS%|nI@sM{TaYWdNxRXgxC zY5BE)Vk)6C$!IhpM?OOpJu)N{(m+HYqJ<@ai-=j{mQmS|MtH{6ThTMp`j9twEDI@3 zN^G6g22Tq}z0;$7XM&EiH()r#vB} z15lcw=|Uy^t|*i#6i_LIktWmEfV6%XpK%?zdN~0q9^Olo=zIHxL@BPzum`H`zkrP8 zD2sgMoWXbNjktQA&CzXZWnpabJ`eTEe{R%Py5*ZTfhlAlKb9rGJ4K5}-~A8?buH!1 z+s8+Bcbzzy_5gi5P-CBCe%Lwy98u&{dLdndu90?A@)iWi!%~7dA$*UHS z9at4sU4BZCy0vzln&EukeQ)t?qN^cR4nX_}15gk6H36PA1>5r(V*8w{gh}OK`4W>W zuqp8@jK}auSG;3D4&yUVGY|PpL*ji|2$66n6QS*OkafkopeqV@1`|zT758uQtXES$ z(rp(k2z&-ki0a#$oqP{_C|ZK22W#lvIPFXH0iLl26NLDp2)ZZzWAfr2ZanQkGmTlq@F}F zQ1N%E0a+<|J`;7^)FbhPRiq3zv&pGHXbo~z_k%`kzC`a4agnfvpu|DRaK=a4;Z(_q zQ(6p3K6AY5z5dcQe#+@GaJkpHL5Wa3*2KK;LTr6V91(ASf2a~y?m!G(FPR*=?1cc5 zG=1KH?+6r5z6A?+vHo6F^ty1dd4m>D04Alt91^&@!HGSoPToMNvjeiAT^ zSR>!1vuc^kLIDLxZ8NWme` zIcXr>sW9TcE1=na;BI@hd+m9jp6ko#uhzVRkQTdQ4gH$cn+R&Q`wrp`+#?gKj#w8} za^-ZZ+(d|3jK&fcjvjrM#6DgEXB6Dn_)J+B8?I|Z=E0fPq$}dT;l$=`5A?qd6&svmPFbMxW8oZhh~%462codcc#zh;&h}0mgK=f5T>@%>ik1G_MOaB?~B= zzY6VR8m)+JR!@LS<>&|CE9RDpm8#g1NcX+3tzl2&oHw;EWU+egY1pq3!}VJKA(_as zcNOAL*bmlua>Asbxn;!)l+M0-Kk!nLP}8(M3|0RA7Gdq%biR zt4kP_j6!uxrzANFKNvMIwoSnvp|@cQ#r4S?GnVNt$%`W<<$3~BAJkI@@SHww)yZX8 z#yGWRKJA;#EiltVWXRFg#W3~VRoYFW&w0Z?i9jFD>s6#ENBjzRAeH_EPt|DGpw27-++_R~rL?7AK&qQQx3se|i+w(g-)ii(Z9H{nOFs8L`D;j)1$3ED(1l&FL}Quw zn}wJ5jd9^)5$A!A$@i>9&2lg{W<}&Rn{DN9Qa4z<{|I|}Z%cp;JoCP_lok<tyl~~D0e~|%9xlLQc4-fb46X!UD{;tyJin!u_EaWPHn-# z<0U@tTVO{(&%DHC5mtKWi*z}l9ebR-E$nSvY!E|kDT-}uhi#iRcmCXQlr4{d0|za^ z)v)6F&gol=nG%e^cO`)>Cm+Os=Ikj>`v@8EIks=)w&&tB6czd?73Y<4E~+>)bv`pL zX1%N;Cwlzg6^K(fZG2?1=y3FGjDmgu5dA7H3PbbUy({2H)|QS?`yxdj0|~P(T@IEm zL0^!%HCb|vWiw7}O`plUS$092%ohzxzeU3aiW;&Y3^5P{G6*?^0AbQ{zBfVMco_O4 zxif1lS$h$*ut=th*`PbqiC)y23F9Rwq9(0W90$jbt)v-N5FL?CU`tDnY>T)aQO=au z0g%U1)Fv!OJ-`YZOvIriX(;31%R%*h4V|vTLFzo`+U{5%Z-%^k?5^S!lT0)v$UylQ zf?nheXi7q;>0>DC=_U5 z>iEH}WQox6*Gg1$4^I;Ff4*S))u(y2B$G&7<6(lL6N#p?y82KeGpIbWijwLiO*+4? zPgEob18>rLO=u1uyaPMr6~kskF#A!KF7vlW7ZN-hAfboQ*Qj#xBo2;7rq#CS2RvVS zk>(tpk}jk+U|m%H6nOMBPOpeU;iMi<0yRN0hzO)2^32F3PdpgHj8js;#Zr$Rbk&9M zkYv21Qaaat;x-YKG_}-ZF45mq5Uta%NSYFMCt2Y6WVTmg9)<@~Ewo@nLB7)*iut0s zeA-SB!tqs*(lpcffVQX}Hw}w6@?Ctqgm!xqh>{UFJ|o5;%S%=v$K=w2eb0MxZtt<5 zt>>B{VqP&d+rHZnpwAF#!H0)t=7bh>?VjSd7j&)(;o~#1r)6U;5Rn}Wsqr-gfjU66 zP>P*3*Fo?YN`gt7h%o=Q3JVblcA(c3A_7Yj8T!PQDNB%t>N>mLb;^*ZnKIhP#Gb~` zjo4E{ZC}+-5A>uYxX(|)Nnc3i&QV&`YedA&Yyi&OB9r<|SGo_rfBs!HA*$r1ked#0 z!LaYdLT^D2RE=fdUM94&!k~wG8IQ?0B;c^- z5he{ur?bF__Yu{S$fkFbwuJ@{o;1cs@-cDsTK$qt+zc+ek!2|vXS*#3#L;?9)y{F~ zgO&72-sQE2Vmy10v!CktHD2Va-!1mzZSpwt!=3%U(-H;#wvmYzeSODno6OY8kXh# zZB#@ov&@gW=?#)PNHRvMd2TA$Ub2v0;@Rq>rgdmtlQ_R^K2Jv=!F`BeSJx)6H^TP5Y@7% zOmjo(vS}k**#seKrjM@}0^$^*lv~bXlW)m}Fq*QKvxs+PDLOr}@1L=t`JJ{pU zwL-MCsn00jnWkN#0O2++b*G@L#!!7WvmV-fGMCzn3~3sua02QZ2*VVOmLb$;P?n-X zE8PN~-Mq>i06ZMS7+RQ}XwjbBWU-Bz4}Qx$?5EeN{)};_hw^jlyJA9+Cd*^ep@m%X z4#nQ_DIk0~!i`IX<9k_r%7QRNAwIV=k4do)Kq7mlxHp)`uAE0ZJi1b!heVKfb$5*S zLjWj^7h5qYl{r6nU0E2^#9LE9&}sS?~V$?i*<+aqOd*>{tv3iY|lyDFw{ z3^S+e^gySWlxQh9(8 z2ywFHCrrjv_=N1|r5{1OW|_)P?O^290D1{&ogl8tNzAm|)*QYQKg&TMNj3DDS`UF1 zomu&cqV5B}A<_(Kp{)R_l<+{63v6X|)xP6RSc76@9}ZpGXs7V$ETK>n7!k zY@Db)^(E<}W>w!M{O zrSqFB)Hs)0Cy?LX&^L>oA1ZnP8^mC!M-=*?@94Pi&KN7dS|g$84UuyYr!dxSOPU8g zEab`BDQ@-a+ir^*=j3ZsgDt${O)^Vztux(amz^V=k+C;iJ0 z#V)Joey{(msJjq(u_N($qxj2^;^&&+3v`p`ecLZZo_p0^g#1m3_}e(e5f>_=rG8Vh z{)Ut|*CSpO^ItWG7tYYd-qh#r(U*-=Lipkt`c2LHTejlo3g(Nl{Y}mKJMwSFc{zu~ z&s&>c5EF53RD9V$#V)oCKW}hon}+Dc z8x`WO9u{|OT)?D%wWPQZDtz(U^jFJ^|9_~+`R02OCI0G=aS8NqDDhWAjZ2^x7vUiO z>a}qR^x|3?gvjM=61muVAMsZW!X;5Ju8uI3n6Baq*r=cOSRj`i}j32|Q2bRqQewFzY$lsoaUXHBwS_iDo`?|4#|N%_ofvfSPM;|IIeM8sKHU6!-MQ!iW0 zN60E?5v55#3oG|0<`2s>4ZQGlvocVJk@Z%qBjTdg|k(L)kKB5!Jk#ov&mG>O3H% z?q*B8Dmy5P_mV&k45Q?TVgv`rzONxePsCs!bFW8fd;u|;qBs+;E8})KKd-;d0irhe zR-Mo=HMXRNrj_D)Wf$k3R45;C;;@{b{|Ew#%IF*u#wHeu3v`q&$%N+HWHZ96^R*>H zX%>PC;N_A_5@q;UPigt;2c6|gm5>*LA>?Xy>rHw2*#H%i`G<6~ypW0fXzho}s8U5s zy3PnT|Lh6m7~_10SrkYTVuY@^X^LV)Ep=FU2FxPo;%ix46@`_a0!nQg$Id#1w00|N ztd+~#E3f8{dLYTWR3CMFqHT#mUkVl$XP(O%Snn6SH@2;TnU2MR>+@?(j8wBbVTyvXp@7#oXwn;k8^193r~R zI5s#JX2uBMux|H^%zL)~t8{yFWC24wlG0+ebj)vQ7540V5hF2Q297zLEvn73)Mn+B zA=2~B`T2C_f;4x%PY8yAS20rsaWa&oQNo*xU49lqkf|aX(*?$sL^4#VHVbG=Se#Z@ zeo%F}8h>R^fTiM@$`JyT9|b+ z;swP5K%b#7D-WZWi5d z9y*~l09xTh|G{Egjg5{?4jUX!(-taNOiR>e&t1 z^msJ`0lhq7hy41CeC}13Q>t!rwDN8pllL5Te(f0W@CUn^S{RPzt8Vyc4qZ;4Ry*gi zdz?OOh9KlY2*;tmYB7DO0swjfDi)P-{z*m<#z1r1c0b0e0j^3A+hnLf>``U3+DFqw zfS;cah}|%)ystyQmVTdzI{E}^)rDj*d=9dkF;6a$wOtkAb_TB(1Qg~?%?E39Iy01s ziCmAy$GLNc;$^)SMym{4bn>%_a59TzFivUQ@K|Fjka$6~gb%p-M~qrRux*+Wi#=g1 zqRj?D9kw>9FRp{%L4h3`Fv&eG7Fx$3@`M-agZ+Jkg}*MOB0Y!G@huCLt9xJ2Ki0E@ zl-g`_HnME&zuzo11GLZe#fL9-=heJ=3IKfPP%)v1ZSs`fANHb$-=qk5-N8K-{*RG$4h~kfX)Oy8$h*RVZ^A)7e?N4S3{CT zc;i6x>idD$0P1mN?N4ULB}0Os33^J+q#EP$uR0)aMqskkEywkU{N&BeI->N46ch+` z;?PdIYqNW#bgg&E4}UVrk=m6Sd@GEf`MjE3v&@m!FHS+t$Y{Q@gBTaxtr6;kH2|Kh z!nufWANO4{pbLkZpoakJOkC2S`1YO0qQG2F$be5P*{uhr+479V5_#Gp+ua6bR-J>` z2QLHSKKWbNch)BJPFV0+To*&nv=XBh=7f_YJ?w3oa>|G;%Ameo;Gq}BsJ9`SFlUg_ zl9WkJ75NTVbOequ^7fkL-M}7WO_#lX%Ol@an>KTkyH319!YG%hQl-wYbb=Hb=w2aG zQvYhMmz}4+rHcYbrLphqHJ+zQdf%pb0bxb9GGA>=lMP=>;xSDpg*^A<{TM!Y=sKeT zwco`Ls@6p|n()RlmoZ-__m3`uGxo7~p~8ncAGnJ$ejEjyzv|~T_!JTM=9ug_)Wsbdt=EHt;ELKInVj8zmYUi&>=mH zI5`B|p;gs$sEDvT+~#dX=pUXtxs`Fr+475lJ?QyM(nKDP`io>rgykQ$o6Oh(7=P(* zJf5rGFyCvx*%@s0gvPYm$f1f}7UJ|QtZ=7ye$>9md-GFME}>wC+5^rT-gXkVuBt>B z`PVuT#PHo>m9qo+5B#XhbW`q2fNg^H$_NR#Ao2;!ZsbDO%8|~Bh- zCQu1-#wf7{4+-@hFm_}=N#zXquc62O^zu3PmC5vDyFI6i(E;wqcH2*-Nf zA}#A6t74ecqRU%4A#8LW?MdDw7HUM39_+$A#`B4OZO?}nIgz__i;t*)DLNfvUOL9r zk>B|Yz&rX?O=nNeU$A|!xbIX&DBD>fY~`{?04K^Vegvuj5>YJm3QQ;yIgxv~fCODE zDOOGaR`1wBLVF6t1BI?OlyhkR^bvPLXxN$696?U^nN@Edh1t9KN5ptuSE56KcZvac zP55|d^7h3^!l5cW!&8cv!K4R3-8#^aJV2Or*^ax4e3Y!`If!By6xl~kQAZvSQiZnz z7NV@&?pu!b*y3*B(4ER*e@OZvmr7`r%B7!5kBLHaWCKhe-u@2nb&df=6}3$ZMFjs^ ze_?q*&ab6)3IPh5fMJN{eo^dZ@lx?5-u$lvdptoc1m!#Owc_&N&9@~DRg{ez6v=@2 zllQ~T!swZ}&ZRS#PD>5{m+`l(Kl&@@ped~MNdu;!u}PHOt()=~KG!=yVqwS!!6>H7eCbT6jm>JjH{)f}*hhtimp zHfoY4z7}?%&AO||KA}ewe^wOmpo+Sd)uoT5y|fB1jU;ZBA%W3>U*S7yov4$$iaJqJ zuk!O@%@1#sw(jCjXaT)fY-jcARlIjxaVrz&e#?5=c;%+Tdis1-FC8jXY4(U7;Po?5 zyuRx7mT2r17sW}{>l|M#MWJyfVG3bE8sdt+N8~6=W{>-fBUsr4G9I@_@Yu{+f;1bi zpS~U=j-J(RclN;|HR0{n*Gm1tP=8;mVe$4(F|@vaUIBzh72>E$;S-XqI2JzsT>@(C zYh@hgx@}#P%CPgZfGVHSs}x^BQCw)sePZK_TIHO9oi>`c`MDH>h|`VyJql%O7Rt_V z$ED=~CfA;`7A2BFs}?iw{4}PHBu`M5tLm);@fKb&$KwFd*#hLAhu)~75-vaJ?y1)E zkt_;V6&?PLq!tp6?BgR?1~{s+jY$9C@?&z>spSur(-h-63M#TAN;z_sDpF;D%3tsN zEIwHpKKbPeD&|Ve91r_xpSS;)=lxRoKY39msw*uLcQp8Ga{y#2zE0NzRE<%F^Z+~~ z%{sg7DW_%FBh|bmS$8L4!-kb5J&Dei8z;*;q!Zzz%d9@Cs(D9Pf)>eMe_@Sa#Z8am z6K`R|gWZ!c-aAW^HBw?eBP*Cn*a>>~U|-naSdIE~`1lwx=tvOHRY{~tCt(uL(?ITc zRj79J0ZnC341yc6V^}A_wq$T4>FfdZ4ppU=;K~vOxz+K6wf+hYV4(9(JLvgwFOJK% z6tmd!ff<1JU6$;ZvXANTVRO#JP&xIufDy7hab9`iy_m9}>>%Gwzh{iee{f8hmKiZC zSG`llljl2ns-)q6=FEOJj88;SXT`gr!LJCm8aT6>Cn9&*{gC5`euuadFTj&ieV`0( zM}0*Dh;0D?Up-Ti6xa!AMAR3xXm|6hXKIQ2t0G_rK;FI|DH(#r_l+>wmR|$wU4rHdU^P=p9SBi8b z_{WhuWO_E0(_e`&k6|^qaylB3BvJCCo5-2s^b=-5yy&Vf0Gk_idE6cEMA9k(=_-Ph zDkAH9CJ^hDSmHPC!lNq>@T~8q3f%aDFlk4Z#;wvso72pYD^48jk=|DvO4gW`6&F?Y z*JI-RqD+W$r>ep>SGqJ;&ve?>QpZb{2P}L?y}ia6e$DOX192WTV`O$+v`~rxr|2!% z(tNnnW8eo>5~OtEDyy$&=FoH)G(MlyhL-fj7jY0UXOc5~qK%)rhpM5Q*Qf!I#|rl> zlC9)&`&{MGO?2kBU7iwm2RwR5kICvV>2@&S_8aWWdRii&aRj=S5c*~QK zg0!^~!2nENOR(?T`z8sXt60)|tp`=-W|i;g<5n?}G2ZMGzqUF=QuF3_KcG`Bkp@%> zL)+n9Y|%lJFhX}4jblHW`g`3z;cg0N?aLu=NPitiv0W8&rvK#ZpKN}YFZS+)NCo3r z`^K+R?|`*OPN^9Hl9sGe0E>)M9ww(;h0MX6@$Sd&k56{BY#IFaP?-pQk1N{ezCRyFC=9Wba_@=jIFl^BBe3 z-pkM4!}dN@T=@J?c@IZ7dnocx%M=68JH9G@9=5*DcRZj%`gi<1?7*b|-1PY04ru=? ziT`Pu{O29yp$^t=K7S^pi~gTWHAAS-KN9%2`~B;ulK;BjpDmpKyp^Ag?_Y!b^VdHI z^w&UyR7B4&l|5|l*g1PRp3mn$PLYHZtbOeNYW^%_=hD*8^=JIvraxhbdy&{n2xOL>FsTGRRe zfqn-6I`scg3bmGh^mT_GSR1j&wbETAABUUR_|fICFJdgk`EJcl&N=knpJ1enAWF zqn8<;iz?c^Gza@XH(*^;Y|Wu)?qnM^X-QF4Z3MQX<@Yd#vb`@hz~x$Q`i2za5kQVH zukXz9rf2}Ih7p&W`u@>zQ8(LLb107`*=d1;4q4T^a#K{tx|93I`@K2J#_Y)xtMKO+sON29 z;lhz$IP!}L`NcqY>B?NXGM8f+RCGC%y6E=uch}^VBe-$|S0jPE@&y7FYB<0LmiN`8 zylN}biEobhn%MMabR{$y))zX~%ED0>u0S!NE?m>aP)T9MQIKPV zX>e8mBTOd6IC3)~M*(LzWa-M3u1qbbiy9l(qYhN z)56h^oweuWgnEk@0A+xodMu`?@88rv#SaS2a-?T0*9kom_eT7%XZoL`_M=nXUt}PJ zXCnhP6nudJcdQjLa57+fQ35uVa3%r!$lVJJxX1A#2JGQs?BHHxz{S2Z4&15S3oQ8a zyoiVBSbiJ@a*6*aw{Wd?fc-;&{`^q5b5GQTap<8c8h?Glq$nZ{NTcRpoM(Z%qfRJ_ zdtWwf2R}jus4E`}0_|_Z1Dt8DEi(~Z370JXlAMXlW7pK%-p0oiNxw6w!*@Xb>-)d$ z@v6|{54#6dcYIN^znh=L1;vJ}*(hLi&8BDK>)wd#y6Mg_4Qp}UZ1!bmHeKJC=a?7{ z#W@q#2va7a@H|lj$#{ywO2?Br6X(~L;_AUP52g9@X)cm63+G8LyeNWX=+K^VF+a)w z8o01SQg$VR?-mvpixwDW@ymeuVNe;bW0*91o!Z@6# zp9~yg^uBbBDGuUOafJ0dz^FaLjn0NFh$p%60t(zvx&h;6o`W!OgK@iPnz|8xhn(R1 zch9jhCX_zOikF0E1-x5U!c@a6sSfs2ZLs8aN~h7Jv!&Uj)8P0gA|qPsT^{Z$D?mG@ z?K8Y9*bkp2G4PH|566wub|e&YxmhIRAv=RgwdL+8;FVhVOQ%#523*#In3w=0%RI?| zn|(n#Gs|N|c!B{a`ey`aWn=sQT+0gY*TyYdqX-?5e%?otIGKkLEzI4F%g&(B5JHH5 z$01-6NM4>-gTD9?@s@cmkhwkgnw*_MliwB*KWuM)dT1$wN{VY7V(pGrbt!bN}IM6$qiid&*eO&P4Yf zYeV1i2g>TVnayNK2m%-kJirw3#8^}#vKk?1g?*XbQ|7|vJ_aZe_EGWxX2QPu?LoYH zjbwB;8PN(9#NKW3UsuAWLOKZC*z86Rfmf@I9>gd6Qo9Ecm)HleJ&3S>J@%CLTGwN% zNc6M0kFG3|^zg`j;7F$e*}?;)g$nNZL!!~qu~Lm%#yVmBZML7Q6P6I>GSre`{M|)} z@O24zY%@bp?QQ`0@5n-hXhwR7*X8Pm?--oLq;1H;Wz~o87%rPCAK)BtaONM941G!_ zL!Y5n$z-%M^edT+cZQzfQrpN6`sNbFef!#{McOQP#^fQ3CtdbuoIh=9ANNccd`Qveul*;>Vx@rNx|Ve__3M30Y>{170#e% z$wUz|7$AB?e;7~9M3+75>2m=I3}3OpOePwYK^K#WPGwNWWTI6WcD$2`US;rI$yBp2 z#gnOStwhMQge=k6umS=Ey&Lrk6+yCrFPH*Mk^o`uK*|FIx^cXgq#yRqkL%x(^kXsh zAHN(Bf*o+MM3Cj~>iE*Ijic@(dKtok4+-AIA6zk@RKP$79$-TU+l+5yVTW(H`ZAmg ze89ey82mdREvylAt>aFXwRs*|3H##{7D~}2`?C-M%EYJyDe|jfn>;fq?&H|sWbj2- z!v0!46>44-L@B zgz_tlk^OZ8TNym=Fi2p2P$=qXpg_~3ErL-V4bd8=KQQtUIvyCgK7&Su57%eVl2GyW znG*Kb3aIt#Gfb3VX6H_kh)4hJHYwf~IMbw140~Bq;hf#gXbpIBO4M9EB|rE+tD7<4AiVoT6DB;WXVR zi*Y2=2$zxVk8z~15iTby8slg_MYtu|t_ZiH8+CIWTqdK1n`8ZjtBQHi7>F3RfXiWR ztW!2ddZF2P=tV|mV#c3dx>pr7hSiCaZL8`U*vJ4 zaw(a~2&c$LML12dRE#5M65%r1tcr1T`WoSK^5GF~N&Yv+(dKr9TT$E<%Sf=H(Ek#%-i&M$t@E&c>fJT#Aq|?gzAw*_RZdSIi%9OkYy0g<}4IWBQUJevD;+ z4NDCa7bPS|iN(Q=pAyuNP}>Ptz4eVi9f5WUtbk$zG*PCVSwR z>{Uv!O5Dbp$zEZa$2zXmg3VRnnCz9ZJOA^3sFcZGp(DHv6pZ;(ipftYO{;^b4bA%t z(-hB3g&}7$P&oy&QGH7`w}_S4_b9bu_CVnlGVjNlk1sAdvwpzA#rmu?Ewm&4bV}>x zInM}#SwFPmIt1~terQdBV^m+pbX@6-`8TC=+C+(Hb3SMElG#ax>B0N4qE%2--w8d% zkh6Yd3tG3%X){bXhNFv-aXB96AgZJFQdA$5m*bdiR~dxL%7H;P=NJK+5M+E zE%b%SB|G6imNVOlJfE_n6gGQ%{!95E%HW~Ix6gIm;ZHP8$7k~Lcv}Mu5U$z(Ro@t; z&0>+QjmmFU8~8r8$@1GAUa&y8^0${u_~YreLu!p%w&^95=oL~)XWScPl{VpVFJMBaB zgY9eX$GOMHcyW5W3M?;ePY-T;}oVUuOKU^(#-fR7rAWpXzG4+ z3DzD`WruK|Bn2;F)~N3`tfkg4VQCEqBjIvZ-_ zh;B+|1Ev!rEgO}gvEYhj=0P?hxA6>Ts2a^P8?GNZVT0}jqSIX4r}{Un`yy4YvAA=* znc4l~E3B4xH$FL=;Mi^nJRR)|v@a$k_#igAz5>geBj?c?qtkGwX%l;o4(F``IT6ybub-wmvD0sV^O;ZQJocZcqIfuhAjFiy&iJF-Yi+c}|FVlEAXO zBzUZIYFK^=*G<`hdv1d}nYb`~_hL6lQ4j~A(^5lB_Y7|3p5@56+h?eQcVSt+l1U`+ zHDs(pbw39}F0-aTp}kh1pc<+^$r$d%Ai0)pKy!mC;0Cw`AzLVA)*}OIE-madUPqt) z(J5BYPCdLx1WJOxQu3=~&xK_jQOutnKr^*x>JKou0E(#drewq8%7N7M+e^hUim=99 OxE%C>3=KbxH$MRkb61)G diff --git a/docs/releases.html b/docs/releases.html deleted file mode 100644 index aec80a1..0000000 --- a/docs/releases.html +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - - - - PortAudio Release Notes - - -  -

    - - - -
    -
    -

    -PortAudio - Release Notes

    -
    - -

    Link to PortAudio Home Page -

    -V18 - 5/6/02

    - -
    All source code and documentation now under CVS. -

    Ran most of the code through AStyle -to cleanup ragged indentation caused by using different editors. Used this -command: -
       astyle --style=ansi -c -o --convert-tabs --indent-preprocessor -*.c

    - -
    Added "pa_common/pa_convert.c" for Mac OS X. Start of new conversion -utilities. -

    ASIO -

      -
    • -New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables,
    • - -
    • -Cleanup of Pa_ASIO_Callback_Input
    • - -
    • -Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo
    • - -
    • -Deallocate all resources in PaHost_Term for cases where Pa_CloseStream -is not called properly
    • - -
    • -New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows. -Allows use by multiple threads.
    • - -
    • -Correct error code management in PaHost_Term, removed various compiler -warning
    • - -
    • -Add Mac includes for <Devices.h> and <Timer.h>
    • - -
    • -Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better -error handling
    • -
    -Mac OS X -
      -
    • -Major cleanup and improvements.
    • - -
    • -Fixed device queries for numChannels and sampleRates,
    • - -
    • -Audio input works if using same CoreAudio device (some HW devices make -separate CoreAudio devices).
    • - -
    • -Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.
    • - -
    • -Return error if opened in mono mode cuz not supported.
    • - -
    • -Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally.
    • - -
    • -Use getrusage() instead of gettimeofday() for CPU Load calculation.
    • -
    -Windows MME -
      -
    • -Fixed bug that caused TIMEOUT in Pa_StopStream(). Added check for past_StopSoon() -in Pa_TimeSlice(). Thanks Julien Maillard.
    • - -
    • -Detect Win XP versus NT, use lower latency.
    • - -
    • -Fix DBUG typo;
    • - -
    • -removed init of CurrentCount which was not compiling on Borland
    • - -
    • -general cleanup, factored streamData alloc and cpu usage initialization
    • - -
    • -stopped counting WAVE_MAPPER when there were no audio cards plugged in
    • -
    -Windows DirectSound -
      -
    • -Detect Win XP and Win 2K properly when determining latency.
    • -
    -Unix OSS -
      -
    • -Use high real-time priority if app is running with root priveledges. Lowers -latency.
    • - -
    • -Added watch dog thread that prevents real-time thread from hogging CPU -and hanging the computer.
    • - -
    • -Check error return from read() and write().
    • - -
    • -Check CPU endianness instead of assuming Little Endian.
    • -
    -
    - -

    -V17 - 10/15/01

    - -
    Unix OSS -
      -
    • -Set num channels back to two after device query for ALSA. This fixed a -bug in V16 that sometimes caused a failure when querying for the sample -rates. Thanks Stweart Greenhill.
    • -
    -
    - -
    -

    -Macintosh Sound Manager

    - -
      -
    • -Use NewSndCallBackUPP() for CARBON compatibility.
    • -
    -
    - -

    -V16 - 9/27/01

    - -
    Added Alpha implementations for ASIO, SGI, and BeOS! -
      -
  • -CPULoad is now calculated based on the time spent to generate a known number -of frames. This is more accurate than a simple percentage of real-time. -Implemented in pa_unix_oss, pa_win_wmme and pa_win_ds.
  • - -
  • -Fix dither and shift for recording PaUInt8 format data.
  • - -
  • -Added "patest_maxsines.c" which tests Pa_GetCPULoad().
  • -
    - -
    -

    -Windows WMME

    - -
      -
    • -sDevicePtrs now allocated using GlobalAlloc(). This prevents a -crash in Pa_Terminate() on Win2000. Thanks Mike Berry for finding this. -Thanks Mike Berry.
    • - -
    • -Pass process instead of thread to SetPriorityClass(). This fixes -a bug that caused the priority to not be increased. Thanks to Alberto di -Bene for spotting this.
    • -
    - -

    -Windows DirectSound

    - -
      -
    • -Casts for compiling with __MWERKS__ CodeWarrior.
    • -
    - -

    -UNIX OSS

    - -
      -
    • -Derived from Linux OSS implementation.
    • - -
    • -Numerous patches from Heiko Purnhagen, Stephen Brandon, etc.
    • - -
    • -Improved query mechanism which often bailed out unnecessarily.
    • - -
    • -Removed sNumDevices and potential related bugs,
    • - -
    • -Use getenv("PA_MIN_LATENCY_MSEC") in code to set desired latency. -User can set by entering:
    • - -
          export PA_MIN_LATENCY_MSEC=40
    - -

    -Macintosh Sound Manager

    - -
      -
    • -Pass unused event to WaitNextEvent instead of NULL to prevent Mac OSX crash. -Thanks Dominic Mazzoni.
    • - -
    • -Use requested number of input channels.
    • - -
       
    -
    - -

    -V15 - 5/29/01

    - -
    -
      -
    • -New Linux OSS Beta
    • -
    - -

    -Windows WMME

    - -
      -
    • - sDevicePtrs now allocated based on sizeof(pointer). Was allocating -too much space.
    • - -
    • - Check for excessive numbers of channels. Some drivers reported bogus -numbers.
    • - -
    • -Apply Mike Berry's changes for CodeWarrior on PC including condition including -of memory.h, and explicit typecasting on memory allocation.
    • -
    - -

    -Macintosh Sound Manager

    - -
      -
    • -ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID.
    • - -
    • -Device Scan was crashing for anything other than siBadSoundInDevice, but -some Macs may return other errors! Caused failure to init on some G4s under -OS9.
    • - -
    • -Fix TIMEOUT in record mode.
    • - -
    • -Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON
    • -
    -
    - -

    -V14 - 2/6/01

    - -
    -
      -
    • -Added implementation for Windows MultiMedia Extensions (WMME) by Ross and -Phil
    • - -
    • -Changed Pa_StopStream() so that it waits for the buffers to drain.
    • - -
    • -Added Pa_AbortStream() that stops immediately without waiting.
    • - -
    • -Added new test: patest_stop.c to test above two mods.
    • - -
    • -Fixed Pa_StreamTime() so that it returns current play position instead -of the write position. Added "patest_sync.c" to demo audio/video sync.
    • - -
    • -Improved stability of Macintosh implementation. Added timeouts to prevent -hangs.
    • - -
    • -Added Pa_GetSampleSize( PaSampleFormat format );
    • - -
    • -Changes some "int"s to "long"s so that PA works properly on Macintosh which -often compiles using 16 bit ints.
    • - -
    • -Added Implementation Guide
    • -
    -
    - -

    -V12 - 1/9/01

    - -
    -
      -
    • -Mac now scans for and queries all devices. But it does not yet support -selecting any other than the default device.
    • - -
    • -Blocking I/O calls renamed to separate them from the PortAudio API.
    • - -
    • -Cleaned up indentation problems with tabs versus spaces.
    • - -
    • -Now attempts to correct bogus sample rate info returned from DirectSound -device queries.
    • -
    -
    - - - diff --git a/docs/style.html b/docs/style.html deleted file mode 100644 index 8f0937c..0000000 --- a/docs/style.html +++ /dev/null @@ -1,156 +0,0 @@ - - -Coding Style Guidelines for PortAudio Implementors - - - - - -  -
    - - - -
    -
    -

    Coding Style Guidelines for PortAudio Implementors

    -
    -
    -

    PortAudio Home Page

    - -

    Updated: June 12, 2002

    - -

    Introduction

    -

    -This document provides coding guidelines for PortAudio implementors. Some of the guildelines pertain to mechanical style, others to quality of implementation issues. Since the PortAudio code is commonly edited on many different platforms using different editors these guideline should be followed to improve readability and consistency. -

    - -

    PortAudio API Design Guidelines

    -

    -The design guidelines of the PortAudio project are stated here -as some of them apply to implementation as well as to API design. -

    -
      -
    • - Implementation should be possible on all common computer - music platforms. -
    • -
    • - Clients of PortAudio should be able to gain efficient, - and ideally optimal use of the audio services - on all target platforms. -
    • -
    • - The API should be simple enough to be used by music - students with minimal experience in C programming. -
    • -
    • - The API should seek to provide only low-level audio - services, and to only support those services directly - available on the host platform. -
    • -
    - -

    -Note that the final guideline has been bent with regard to audio -sample formats and user buffer sizes - PortAudio can convert between -a number of sample formats and can adapt to the user's buffer size requirements. -

    - -

    Formatting Conventions

    - -

    -The following formatting conventions should be adhered to in all PortAudio code: -

    - -
      -
    • TABs should not be used in .c and .h files; instead 4 spaces should be used. Makefiles should continue to use TABs since this is required by Make
    • -
    • Line-emd characters will be consistent with the platform on which the source has been checked out of CVS (CVS handles this.)
    • -
    • Brace placement will follow ANSI style, eg: -
      -if( aCondition )
      -{
      -	DoSomething();
      -}
      -else
      -{
      -	DoSomethingElse();
      -}
      -
      -
    • -
    - -

    AStyle ( http://astyle.sourceforge.net/ ) has been proposed as helpful tool for cleaning code, however we don't intend to use it on an ongoing basis. It is expected that contributors of each implementation will take responsibility for keeping their code clean.

    - - -

    Quality of Implementation Guidelines

    - -

    The following coding guidelines should be followed in order to establish a quality baseline for our implementations:

    - -
      -
    • All code should be written in C++-compatible plain ANSI-C (i.e. no // comments). It has been suggested that all implementations should compile silently with both "gcc -ansi -pedantic -Wall" and "g++ -ansi -pedantic -Wall"
    • -
    • Think of PortAudio as a heavyweight library rather than a lightweight wrapper. Always code defensively. Efficiency is important where it matters (eg in real-time callbacks) but safety is important everywhere.
    • -
    • All parameters passed to PortAudio by the user should be validated, and error codes returned where necessary. All reasonable efforts should be made to minimise the risk of a crash resulting from passing incorrect parameters to PortAudio.
    • -
    • Error handling should be complete. Every host function that can return an error condition should have its status checked. PortAudio may attempt to recover from errors in some cases, but generally error codes should be returned to the client.
    • -
    • In almost all cases, a PortAudio error code should be preferred to returning PaHostError. If a new PortAudio error code is needed it should be discussed with the maintainer to coordinate updating portaudio.h
    • -
    • PortAudio code should not cause resource leaks. After Pa_Terminate() is called, implementations should guarantee that all dynamically allocated resources have been freed.
    • -
    • The definition of the PortAudio API should minimise "implementation defined behaviour". For example, calling functions such as Pa_Initialize() after PortAudio is initialised, or Pa_Terminate() after PortAudio has been terminated has well defined behaviour.
    • -
    • Minimise dependence on ANSI C runtime on platforms where it would have to be loaded separately (eg on Win32 prefer Win32 API functions such as GlobalAlloc() to ANSI C functions such as malloc().)
    - -

    It has been suggested that we make an effort to minimise the use of global and static data in PortAudio implementations. Another related goal is to reduce name pollution in the global scope. Some possible guidelines in this regard are:

    - -
      -
    • Implementations should avoid exporting any symbols except where absolutely necessary. Specifically, global data must be declared statically. The next section documents naming conventions for all PortAudio symbols.
    • -
    • Implementations should minimise their use of static data.
    - -

    Naming Conventions

    - -
      -
    • All #defines begin with PA_
    • -
    • All #defines local to a file end with _
    • -
    • All global utility variables begin with paUtil
    • -
    • All global utility types begin with PaUtil (including function types)
    • -
    • All global utility functions begin with PaUtil_
    • -
    • All static variables end with _
    • -
    • All static constants begin with const and end with _ (eg: constMyMagicNumber_)
    • -
    • All static funtions have no special prefix/suffix
    • -
    • -Platform-specific shared functions should begin with Pa_ where PN is the -platform name. eg. PaWin_ for windows, PaUnix_ for unix. -
    • -
    - -

    -In general, implementations should declare all of their members static, -except for their initializer which should be exported. All exported names -should be preceeded by Pa_ where is the module name, for example -the windows mme initializer should be named PaWinMme_Initialize(). -

    - -

    -If it is necessary for implementations to define non-static symbols, they should -use the following naming conventions, where is the module name such as WinMme. -

    - -
      -
    • global variables should begin with pa
    • -
    • global types should begin with Pa
    • -
    • global utility functions should begin with Pa_
    • -
    - -

    -Two utilities for debug messages are provided. The PA_DEBUG macro defined in -pa_implementation.h provides a simple way to print debug messages to stderr. -Due to real-time performance issues, PA_DEBUG may not be suitable for use -within the portaudio processing callback, or in other threads. In such cases -the event tracing facility provided in pa_trace.h may be more appropriate. -

    -

    -If PA_LOG_API_CALLS is defined, all calls to the public PortAudio API -will be logged to stderr along with parameter and return values. -

    - - - \ No newline at end of file diff --git a/fixfile.bat b/fixfile.bat deleted file mode 100755 index 48f6fbc..0000000 --- a/fixfile.bat +++ /dev/null @@ -1,7 +0,0 @@ -rem Use Astyle to fix style in a file -fixlines -p %1% -astyle --style=ansi -c -o --convert-tabs --indent-preprocessor %1% -del %1%.orig -@rem convert line terminators to Unix style LFs -fixlines -u %1% -del %1%.bak diff --git a/index.html b/index.html deleted file mode 100644 index 91e5b4c..0000000 --- a/index.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - PortAudio Implementations for DirectSound - - -  -
    - - - -
    -
    -

    -PortAudio - Portable Audio Library

    -
    - -

    Last updated 5/6/02. -

    PortAudio is a cross platform, open-source, audio -I/O library proposed by Ross Bencina to the music-dsp -mailing list. It lets you write simple audio programs in 'C' that will -compile and run on Windows, Macintosh, Unix, BeOS. PortAudio is -intended to promote the exchange of audio synthesis software between developers -on different platforms. -

    For complete information on PortAudio and to download the latest releases, -please visit "http://www.portaudio.com". -
      -
      -

    -

    -Click here for Documentation

    - -

    -

    - -

    -Contacts and E-Mail List

    - -
      -
    • -If you are using or implementing PortAudio then please join the PortAudio -mail list generously administered by -Bill -Eldridge.
    • - -
    • -If you find bugs in one of these implementations, or have suggestions, -please e-mail them to Phil Burk.
    • - -
    • -If you make improvements to the library, please send them to us so we can -incorporate the improvements.
    • -
    - -

    -License

    -PortAudio Portable Real-Time Audio Library -
    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 ON INFRINGEMENT. -
    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. -
      - - diff --git a/install-sh b/install-sh deleted file mode 100755 index e9de23842dcd44d2953129c866b1ad25f7e1f1d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5598 zcmbVQZExH*68^mU6_fR*TL=3RUoUsp7zToC(AGFO3GCo{K#`oe5_iQ~5(Sa+W|8K< z-!nr}yH1>@xd6e+A~`S5%seyH(Szm6G)q@zN7)gX#(7m$G#{Q6wVmB`s-BU{JJb3Z z*^Ub3)!I}VM_!l4QEqGPXx-VG{&RA2`Gmf$jbHZORLgM6Eu-j#D~}hV>j&HJIbGnmot zW>nk4tnphI=R32)=^3e}AgAG(XLFrh`>pDC)*8|Q(XA=))|bjd7(1d?_Ew8U!O6yYljC*UYSjT=Vw_>H z0dQ;`AElM`WfH>9+&wD0U`o69{1d6JZ(G}W(`-I=Du5tr*uF;9g6hTMeDQig5JW4@ zFcxB5ajPN4K@Q>#QEk7fOl~|d!GbakuK@P}WQGkvV$lP<2_)C*+^kJLgP?6^yw?pd zGXQz-%7Q4GQmY$a(pc(r+i91A0+?2eI5a?v>y1|{Q?W&&_Asm;g%6_7J;!i}(^xtD zJ!W%a9Q8Za@#)1U^3QrB0hc=Apo0fDR{E-%WVR00ypQVPtljBN=Bfdq0GegUfs$mAoz zSSiX-dAyGDY$10AiR`Zg>7Q56lZiuRqgLRxOEH2T(Fj4x=VgE~SBP^{?S{j)(ZN{c zuOe@1E;q!Ei!bMDf*4n#+CtG#&4u;yYKjO%wuubm7Fou7wWsGV&tJc~eEAathpM;y z>md=AbDRZz-uv7(Q_o3DPv?YWMS=Zw@g2LyC51vmAUkMBLSZvg_A=gQfNnFq*~uysv4+eaCtLTLm2nm6J#@)(;=IeFL?-P|tdR(0%9 zeaqglo{N98NAvm?dh#~C{o$3o&0Bt3g1UxAMe zu|NNG86}r^jb#qUuzdCU@;ofdYbzl%KY2o5u&(AMqO1l=|#W5H$=<;2!zp%SLCUHM%Na3f+Uq03I zS(TQBB+MrA$PxQGAsZHwz=n{RN?#|$9n(HalOf?g_2n*R{_N2)4VlC_b1gNGF#HZS zC}`@IbAPs6POra!=jx86At&zW8ML5(p99MI86y@i!o z$P+^3JP=EdKnpcZ7;z87Kgf)h1hY5=j_7=S=NK|t4ftWm z=6P1;QZ&^ex409W#+HfpyK`RG5HSoewYqg_BBgP1k zDlos}l0g{%O+H|o5^VsKb25OjyiWBmK!Q3xc24|@<;pY@bA@!>R|?YxCoj7ylX6NV zD8Q@4P@Ls~qvjekHT(7L^39{kYCB9|7u&SgVk-!Dg8>3Wx!}*Uqg_Oeq>FUO`zzkO@49VEwWuz3e z*}LBL3bzn6y+x?@2b`n=AOwwv3NG|o^_4&W@#<_k%BC4VV5Gs%eDZ$3_7nt;FcGpyA88a!E{5_R6=o>}2e!z~A29FRF&IYJ7J z-3~ktkPc^ODT#!U`&usmX}TTCWL!m9k41;YVCOb27?5D zW5Q` and : Phil Burk - 13-04-02 Removes another compiler warning : Stephane Letz - 30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz + 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk + 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz TO DO : - Check Pa_StopSteam and Pa_AbortStream - Optimization for Input only or Ouput only (really necessary ??) + - Opening of several streams */ #include #include -#include #include "portaudio.h" #include "pa_host.h" @@ -77,10 +71,7 @@ #include "asio.h" #include "asiodrivers.h" - #if MAC -#include -#include #include #else #include @@ -176,6 +167,16 @@ typedef struct PaHostSoundControl //---------------------------------------------------------- +// name of the ASIO device to be used +#if WINDOWS + //#define ASIO_DRIVER_NAME "ASIO Multimedia Driver" + #define ASIO_DRIVER_NAME "ASIO Sample" +#elif MAC + //#define ASIO_DRIVER_NAME "Apple Sound Manager" + #define ASIO_DRIVER_NAME "ASIO Delta1010" + //#define ASIO_DRIVER_NAME "DigiDesign DirectIO" +#endif + #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) @@ -218,51 +219,51 @@ static bool swap = false; #endif // Prototypes -static void bufferSwitch(long index, ASIOBool processNow); -static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); -static void sampleRateChanged(ASIOSampleRate sRate); -static long asioMessages(long selector, long value, void* message, double* opt); +void bufferSwitch(long index, ASIOBool processNow); +ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); +void sampleRateChanged(ASIOSampleRate sRate); +long asioMessages(long selector, long value, void* message, double* opt); static void Pa_StartUsageCalculation( internalPortAudioStream *past ); static void Pa_EndUsageCalculation( internalPortAudioStream *past ); -static void Pa_ASIO_Convert_Inter_Input( +void Pa_ASIO_Convert_Inter_Input( ASIOBufferInfo* nativeBuffer, void* inputBuffer, - long NumInputChannels, - long NumOuputChannels, - long framePerBuffer, - long hostFrameOffset, - long userFrameOffset, + short NumInputChannels, + short NumOuputChannels, + short framePerBuffer, + short hostFrameOffset, + short userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, - long index); + short index); -static void Pa_ASIO_Convert_Inter_Output( +void Pa_ASIO_Convert_Inter_Output( ASIOBufferInfo* nativeBuffer, void* outputBuffer, - long NumInputChannels, - long NumOuputChannels, - long framePerBuffer, - long hostFrameOffset, - long userFrameOffset, + short NumInputChannels, + short NumOuputChannels, + short framePerBuffer, + short hostFrameOffset, + short userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, - long index); + short index); -static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, + void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, ASIOSampleType nativeFormat, - long NumInputChannels, - long NumOuputChannels, - long index, - long hostFrameOffset, - long frames); + short NumInputChannels, + short NumOuputChannels, + int index, + int hostFrameOffset, + int frames); -static void Pa_ASIO_Callback_Input(long index); -static void Pa_ASIO_Callback_Output(long index, long framePerBuffer); -static void Pa_ASIO_Callback_End(); -static void Pa_ASIO_Clear_User_Buffers(); +void Pa_ASIO_Callback_Input(long index); +void Pa_ASIO_Callback_Output(long index, long framePerBuffer); +void Pa_ASIO_Callback_End(); +void Pa_ASIO_Clear_User_Buffers(); // Some external references extern AsioDrivers* asioDrivers ; @@ -270,6 +271,34 @@ bool loadAsioDriver(char *name); unsigned long get_sys_reference_time(); +// For callback debugging on Mac : to be removed in the final version + +/* +#define MidiSharePPC_68k +#include + +void SendVal (long val) +{ + MidiEvPtr ev = MidiNewEv(typeTempo); + if (ev) { + Tempo(ev) = val; + MidiSendIm(0,ev); + } +} + +void MidiPrintText ( char * s) +{ + MidiEvPtr e; + long c = 0; + + if (e = MidiNewEv(typeTextual)){ + for (c = 0 ; *s ; s++,c++) MidiAddField (e ,*s); + MidiSendIm (0, e); + } +} +*/ + + /************************************************************************************/ /****************** Macro ************************************************************/ /************************************************************************************/ @@ -290,22 +319,12 @@ unsigned long get_sys_reference_time(); #endif -static bool Pa_ASIO_loadAsioDriver(char *name) -{ - #ifdef WINDOWS - CoInitialize(0); - #endif - return loadAsioDriver(name); -} - - - // Utilities for alignement buffer size computation -static int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);} -static int PPCM (int a, int b) {return (a*b) / PGCD (a,b);} +int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);} +int PPCM (int a, int b) {return (a*b) / PGCD (a,b);} // Takes the size of host buffer and user buffer : returns the number of frames needed for buffer alignement -static int Pa_ASIO_CalcFrameShift (int M, int N) +int Pa_ASIO_CalcFrameShift (int M, int N) { int res = 0; for (int i = M; i < PPCM (M,N) ; i+=M) { res = max (res, i%N); } @@ -433,16 +452,12 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) int i; int numDrivers; ASIOError asioError; - - /* Allocate names */ - for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) { - names[i] = (char*)PaHost_AllocateFastMemory(32); - /* check memory */ - if(!names[i]) return paInsufficientMemory; - } + + /* Allocate names */ + for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) names[i] = (char*)PaHost_AllocateFastMemory(32); /* MUST BE CHECKED : to force fragments loading on Mac */ - Pa_ASIO_loadAsioDriver("dummy"); + loadAsioDriver("dummy"); /* Get names of all available ASIO drivers */ asioDrivers->getDriverNames(names,PA_MAX_DEVICE_INFO); @@ -464,7 +479,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) #endif /* If the driver can be loaded : */ - if ( !Pa_ASIO_loadAsioDriver(names[driver]) ) + if ( !loadAsioDriver(names[driver]) ) { DBUG(("PaASIO_QueryDeviceInfo could not loadAsioDriver %s\n", names[driver])); } @@ -478,8 +493,9 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) } else { - /* Gets the name */ - dev = &(ipad[sNumDevices].pad_Info); + + /* Gets the name */ + dev = &(ipad[driver].pad_Info); dev->name = names[driver]; names[driver] = 0; @@ -491,12 +507,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) DBUG(("PaASIO_QueryDeviceInfo: OutputChannels = %d\n", OutputChannels )); /* Make room in case device supports all rates. */ - sampleRates = (double*)PaHost_AllocateFastMemory(MAX_NUMSAMPLINGRATES * sizeof(double)); - /* check memory */ - if (!sampleRates) { - ASIOExit(); - return paInsufficientMemory; - } + sampleRates = (double*)PaHost_AllocateFastMemory( MAX_NUMSAMPLINGRATES * sizeof(double)); dev->sampleRates = sampleRates; dev->numSampleRates = 0; @@ -504,7 +515,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) { if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) { DBUG(("PortAudio : possible sample rate = %d\n", (long)possibleSampleRates[index])); - dev->numSampleRates += 1; + dev->numSampleRates+=1; *sampleRates = possibleSampleRates[index]; sampleRates++; } @@ -518,7 +529,9 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) dev->nativeSampleFormats = Pa_ASIO_Convert_SampleFormat(channelInfos.type); /* unload the driver */ + ASIODisposeBuffers(); ASIOExit(); + sNumDevices++; } } @@ -531,7 +544,7 @@ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) //---------------------------------------------------------------------------------- // TAKEN FROM THE ASIO SDK: -static void sampleRateChanged(ASIOSampleRate sRate) +void sampleRateChanged(ASIOSampleRate sRate) { // do whatever you need to do if the sample rate changed // usually this only happens during external sync. @@ -623,13 +636,13 @@ long asioMessages(long selector, long value, void* message, double* opt) #endif -static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow) +ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow) { // the actual processing callback. // Beware that this is normally in a seperate thread, hence be sure that you take care // about thread synchronization. This is omitted here for simplicity. - // static processedSamples = 0; + static processedSamples = 0; int result = 0; // store the timeInfo for later use @@ -737,7 +750,7 @@ unsigned long get_sys_reference_time() // get the system reference time #if WINDOWS return timeGetTime(); - #elif MAC + #elif MAC static const double twoRaisedTo32 = 4294967296.; UnsignedWide ys; Microseconds(&ys); @@ -773,7 +786,7 @@ inline static long Pa_TriangularDither( void ) // TO BE COMPLETED WITH ALL SUPPORTED PA SAMPLE TYPES //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Input_Int16_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Input_Int16_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -793,7 +806,7 @@ static void Input_Int16_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Input_Int32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap) + void Input_Int32_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap) { long temp; int i,j; @@ -813,17 +826,17 @@ static void Input_Int32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE TESTED -static void Input_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap) + void Input_Float32_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap) { - unsigned long temp; + long temp; int i,j; for( j=0; j>16); + *userBufPtr = temp>>16; userBufPtr += NumInputChannels; } } @@ -941,7 +954,7 @@ static void Input_Int32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, i temp = (temp >> 1) + Pa_TriangularDither(); temp = temp >> 15; temp = (short) ClipShort(temp); - *userBufPtr = (short)temp; + *userBufPtr = temp; userBufPtr += NumInputChannels; } } @@ -951,19 +964,19 @@ static void Input_Int32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, i //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE TESTED -static void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) + void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) { - unsigned long temp; + long temp; int i,j; if( flags & paDitherOff ) { for( j=0; j> 16); if (swap) temp = SwapShort(temp); - asioBufPtr[i] = (short)temp; + asioBufPtr[i] = temp; userBufPtr += NumOuputChannels; } } @@ -1406,7 +1418,7 @@ static void Output_Int32_Int16(ASIOBufferInfo* nativeBuffer, long *outBufPtr, in temp = temp >> 15; temp = (short) ClipShort(temp); if (swap) temp = SwapShort(temp); - asioBufPtr[i] = (short)temp; + asioBufPtr[i] = temp; userBufPtr += NumOuputChannels; } } @@ -1414,7 +1426,7 @@ static void Output_Int32_Int16(ASIOBufferInfo* nativeBuffer, long *outBufPtr, in } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) + void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) { long temp; int i,j; @@ -1436,7 +1448,7 @@ static void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, in //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE CHECKED -static void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) + void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) { long temp; int i,j; @@ -1456,7 +1468,7 @@ static void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,bool swap) + void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,bool swap) { long temp; int i,j; @@ -1469,14 +1481,14 @@ static void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, i { temp = *userBufPtr; if (swap) temp = SwapShort(temp); - asioBufPtr[i] = (short)temp; + asioBufPtr[i] = temp; userBufPtr += NumOuputChannels; } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1497,7 +1509,7 @@ static void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, i //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE CHECKED -static void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1515,7 +1527,7 @@ static void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, } } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1528,14 +1540,14 @@ static void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int { temp = (short)(*userBufPtr)<<8; if (swap) temp = SwapShort(temp); - asioBufPtr[i] = (short)temp; + asioBufPtr[i] = temp; userBufPtr += NumOuputChannels; } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1557,7 +1569,7 @@ static void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE CHECKED -static void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1576,7 +1588,7 @@ static void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, i } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1589,14 +1601,14 @@ static void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outB { temp = ((short)((*userBufPtr) - 0x80)) << 8; if (swap) temp = SwapShort(temp); - asioBufPtr[i] = (short)temp; + asioBufPtr[i] = temp; userBufPtr += NumOuputChannels; } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1618,7 +1630,7 @@ static void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outB //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE CHECKED -static void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) + void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; @@ -1637,7 +1649,7 @@ static void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *ou } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset) + void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, int frames, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset) { int i,j; @@ -1648,7 +1660,7 @@ static void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, long frames, } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset) + void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, int frames, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset) { int i,j; @@ -1660,7 +1672,7 @@ static void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, long frames, //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Pa_ASIO_Adaptor_Init() +void Pa_ASIO_Adaptor_Init() { if (asioDriverInfo.past->past_FramesPerUserBuffer <= asioDriverInfo.past_FramesPerHostBuffer) { asioDriverInfo.pahsc_hostOutputBufferFrameOffset = asioDriverInfo.pahsc_OutputBufferOffset; @@ -1676,7 +1688,7 @@ static void Pa_ASIO_Adaptor_Init() //------------------------------------------------------------------------------------------------------------------------------------------------------- // FIXME : optimization for Input only or output only modes (really necessary ??) -static void Pa_ASIO_Callback_Input( long index) +void Pa_ASIO_Callback_Input( long index) { internalPortAudioStream *past = asioDriverInfo.past; long framesInputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer; // number of frames available into the host input buffer @@ -1774,7 +1786,7 @@ static void Pa_ASIO_Callback_Input( long index) } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Pa_ASIO_Callback_Output(long index, long framePerBuffer) +void Pa_ASIO_Callback_Output(long index, long framePerBuffer) { internalPortAudioStream *past = asioDriverInfo.past; @@ -1801,14 +1813,14 @@ static void Pa_ASIO_Callback_Output(long index, long framePerBuffer) } } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Pa_ASIO_Callback_End() + void Pa_ASIO_Callback_End() { /* Empty ASIO ouput : write offset */ asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0; } //------------------------------------------------------------------------------------------------------------------------------------------------------- -static void Pa_ASIO_Clear_User_Buffers() +void Pa_ASIO_Clear_User_Buffers() { if( asioDriverInfo.past->past_InputBuffer != NULL ) { @@ -1821,13 +1833,13 @@ static void Pa_ASIO_Clear_User_Buffers() } //------------------------------------------------------------------------------------------------------------------------------------------------------- - static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, + void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, ASIOSampleType nativeFormat, - long NumInputChannels, - long NumOuputChannels, - long index, - long hostFrameOffset, - long frames) + short NumInputChannels, + short NumOuputChannels, + int index, + int hostFrameOffset, + int frames) { switch (nativeFormat) { @@ -1867,18 +1879,18 @@ static void Pa_ASIO_Clear_User_Buffers() //--------------------------------------------------------------------------------------- -static void Pa_ASIO_Convert_Inter_Input( +void Pa_ASIO_Convert_Inter_Input( ASIOBufferInfo* nativeBuffer, void* inputBuffer, - long NumInputChannels, - long NumOuputChannels, - long framePerBuffer, - long hostFrameOffset, - long userFrameOffset, + short NumInputChannels, + short NumOuputChannels, + short framePerBuffer, + short hostFrameOffset, + short userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, - long index) + short index) { if((NumInputChannels > 0) && (nativeBuffer != NULL)) @@ -1892,22 +1904,22 @@ static void Pa_ASIO_Convert_Inter_Input( switch (nativeFormat) { case ASIOSTInt16LSB: - Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap); + Input_Int16_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap); break; case ASIOSTInt16MSB: - Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + Input_Int16_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTInt32LSB: - Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); + Input_Int32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); break; case ASIOSTInt32MSB: - Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + Input_Int32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture - Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); + Input_Float32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); break; case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture - Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); + Input_Float32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTInt24LSB: // used for 20 bits as well @@ -2147,20 +2159,20 @@ static void Pa_ASIO_Convert_Inter_Input( //--------------------------------------------------------------------------------------- -static void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer, +void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer, void* outputBuffer, - long NumInputChannels, - long NumOuputChannels, - long framePerBuffer, - long hostFrameOffset, - long userFrameOffset, + short NumInputChannels, + short NumOuputChannels, + short framePerBuffer, + short hostFrameOffset, + short userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, - long index) + short index) { - if((NumOuputChannels > 0) && (nativeBuffer != NULL)) + if((NumOuputChannels > 0) && (nativeBuffer != NULL)) { /* Convert from PA format to native format */ @@ -2427,7 +2439,7 @@ static PaError Pa_ASIO_loadDevice (long device) { PaDeviceInfo * dev = &(sDevices[device].pad_Info); - if (!Pa_ASIO_loadAsioDriver((char *) dev->name)) return paHostError; + if (!loadAsioDriver((char *) dev->name)) return paHostError; if (ASIOInit(&asioDriverInfo.pahsc_driverInfo) != ASE_OK) return paHostError; if (ASIOGetChannels(&asioDriverInfo.pahsc_NumInputChannels, &asioDriverInfo.pahsc_NumOutputChannels) != ASE_OK) return paHostError; if (ASIOGetBufferSize(&asioDriverInfo.pahsc_minSize, &asioDriverInfo.pahsc_maxSize, &asioDriverInfo.pahsc_preferredSize, &asioDriverInfo.pahsc_granularity) != ASE_OK) return paHostError; @@ -2441,7 +2453,7 @@ static PaError Pa_ASIO_loadDevice (long device) } //--------------------------------------------------- -static int GetHighestBitPosition (unsigned long n) +static int GetHighestBitPosition( unsigned long n ) { int pos = -1; while( n != 0 ) @@ -2452,10 +2464,10 @@ static int GetHighestBitPosition (unsigned long n) return pos; } -//------------------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- static int GetFirstMultiple(long min, long val ){ return ((min + val - 1) / val) * val; } -//------------------------------------------------------------------------------------------ +//----------------------------------------------------------------------------- static int GetFirstPossibleDivisor(long max, long val ) { for (int i = 2; i < 20; i++) {if (((val%i) == 0) && ((val/i) <= max)) return (val/i); } @@ -2567,9 +2579,8 @@ error: /***********************************************************************/ PaError PaHost_Init( void ) { - /* Have we already initialized the device info? */ - PaError err = (PaError) Pa_CountDevices(); - return ( err < 0 ) ? err : paNoError; + /* Have we already initialized the device info? */ + return (Pa_CountDevices() < 0 ) ? paHostError : paNoError; } /***********************************************************************/ @@ -2578,30 +2589,26 @@ PaError PaHost_Term( void ) int i; PaDeviceInfo *dev; double *rates; - PaError result = paNoError; - - if (sNumDevices > 0) { - - /* Free allocated sample rate arrays and names*/ - for( i=0; isampleRates; - if ((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double)); - dev->sampleRates = NULL; - if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32); - dev->name = NULL; - - } - - sNumDevices = 0; - - /* Dispose : if not done by Pa_CloseStream */ - if(ASIODisposeBuffers() != ASE_OK) result = paHostError; - if(ASIOExit() != ASE_OK) result = paHostError; - - /* remove the loaded ASIO driver */ - asioDrivers->removeCurrentDriver(); - } + PaError result = paNoError; + + /* Free allocated sample rate arrays and names*/ + for( i=0; isampleRates; + if((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double)); + dev->sampleRates = NULL; + if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32); + dev->name = NULL; + } + + sNumDevices = 0; + + /* Dispose : if not done by Pa_CloseStream */ + if(ASIODisposeBuffers() != ASE_OK) result = paHostError; + if(ASIOExit() != ASE_OK) result = paHostError; + + /* remove the loaded ASIO driver */ + asioDrivers->removeCurrentDriver(); return result; } @@ -2613,8 +2620,8 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) ASIOError err; int32 device; - /* Check if a stream already runs */ - if (asioDriverInfo.past != NULL) return paHostError; + /* TO DO : Check if a stream already runs */ + //if (asioDriverInfo.past != NULL) return paHostError; (does not work) /* Check the device number */ if ((past->past_InputDeviceID != paNoDevice) diff --git a/pa_asio/readme_asio_sdk_patch.txt b/pa_asio/readme_asio_sdk_patch.txt deleted file mode 100755 index c0fdca7..0000000 --- a/pa_asio/readme_asio_sdk_patch.txt +++ /dev/null @@ -1,25 +0,0 @@ -There is a bug in the ASIO SDK that causes the Macintosh version to often fail during initialization. Here is a patch that you can apply. - -In codefragments.cpp replace getFrontProcessDirectory function with -the following one (GetFrontProcess replaced by GetCurrentProcess) - - -bool CodeFragments::getFrontProcessDirectory(void *specs) -{ - FSSpec *fss = (FSSpec *)specs; - ProcessInfoRec pif; - ProcessSerialNumber psn; - - memset(&psn,0,(long)sizeof(ProcessSerialNumber)); - // if(GetFrontProcess(&psn) == noErr) // wrong !!! - if(GetCurrentProcess(&psn) == noErr) // correct !!! - { - pif.processName = 0; - pif.processAppSpec = fss; - pif.processInfoLength = sizeof(ProcessInfoRec); - if(GetProcessInformation(&psn, &pif) == noErr) - return true; - } - return false; -} - diff --git a/pa_common/pa_convert.c b/pa_common/pa_convert.c deleted file mode 100644 index 377a955..0000000 --- a/pa_common/pa_convert.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * pa_conversions.c - * portaudio - * - * Created by Phil Burk on Mon Mar 18 2002. - * - */ -#include - -#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; ipast_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/pa_common/pa_host.h b/pa_common/pa_host.h index 94651a2..9a35261 100644 --- a/pa_common/pa_host.h +++ b/pa_common/pa_host.h @@ -36,8 +36,6 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ - -#include "portaudio.h" #ifdef __cplusplus extern "C" @@ -61,12 +59,6 @@ extern "C" 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) /************************************************************************************/ @@ -84,9 +76,7 @@ typedef struct internalPortAudioStream int past_NumOutputChannels; PaDeviceID past_InputDeviceID; PaDeviceID past_OutputDeviceID; - PaSampleFormat past_NativeInputSampleFormat; PaSampleFormat past_InputSampleFormat; - PaSampleFormat past_NativeOutputSampleFormat; PaSampleFormat past_OutputSampleFormat; void *past_DeviceData; PortAudioCallback *past_Callback; @@ -109,19 +99,11 @@ typedef struct internalPortAudioStream 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. ************/ +/****************** Prototypes ******************************************************/ /************************************************************************************/ PaError PaHost_Init( void ); @@ -138,46 +120,21 @@ 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<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_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */ past->past_Callback = callback; past->past_UserData = userData; past->past_OutputSampleFormat = outputSampleFormat; @@ -248,7 +248,7 @@ PaError Pa_OpenStream( #else past->past_SampleRate = sampleRate; #endif - /* Allocate single Input buffer for passing formatted samples to user callback. */ + /* Allocate single Input buffer. */ past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8); past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize); if( past->past_InputBuffer == NULL ) @@ -478,25 +478,13 @@ double Pa_GetCPULoad( PortAudioStream* 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<>DITHER_SHIFT) + (((long)randSeed2)>>DITHER_SHIFT); + /* Generate triangular distribution about 0. */ + current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS)); /* High pass filter to reduce audibility. */ highPass = current - previous; previous = current; @@ -529,6 +513,8 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, short *nativeOutputBuffer ) { long temp; + long bytesEmpty = 0; + long bytesFilled = 0; int userResult; unsigned int i; void *inputBuffer = NULL; @@ -590,7 +576,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, for( i=0; i> 8; /* PLB20010820 */ + temp += Pa_TriangularDither() >> 8; /* PLB20010820 */ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); inBufPtr[i] = (char)(temp >> 8); } @@ -616,7 +602,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, for( i=0; i> 8; /* PLB20010820 */ + temp += Pa_TriangularDither() >> 8; /* PLB20010820 */ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */ } @@ -683,7 +669,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, /* If you dither then you have to clip because dithering could push the signal out of range! */ for( i=0; i 0x7FFF) ? 0x7FFF : temp)); @@ -707,7 +693,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, for( i=0; i> 1) + PaConvert_TriangularDither(); + temp = (outBufPtr[i] >> 1) + Pa_TriangularDither(); temp = temp >> 15; *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); } @@ -744,6 +730,55 @@ long Pa_CallConvertInt16( internalPortAudioStream *past, return userResult; } +/************************************************************************* +** Called by host code. +** Convert input from Float32, call user code, then convert output +** to Float32 format for native use. +** Assumes host native format is Float32. +** Returns result from user callback. +** FIXME - Unimplemented for formats other than paFloat32!!!! +*/ +long Pa_CallConvertFloat32( internalPortAudioStream *past, + float *nativeInputBuffer, + float *nativeOutputBuffer ) +{ + long bytesEmpty = 0; + long bytesFilled = 0; + int userResult; + void *inputBuffer = NULL; + void *outputBuffer = NULL; + + /* Get native data from DirectSound. */ + if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) ) + { + inputBuffer = nativeInputBuffer; /* FIXME */ + } + + /* 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 == paFloat32) ? + 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. */ /* FIXME */ + return userResult; +} + /*************************************************************************/ PaError Pa_Initialize( void ) { @@ -765,11 +800,6 @@ PaError Pa_Terminate( void ) return result; } -int PaHost_IsInitialized() -{ - return gInitCount; -} - /*************************************************************************/ PaError Pa_GetSampleSize( PaSampleFormat format ) { diff --git a/pa_common/portaudio.h b/pa_common/portaudio.h index fe05829..231e804 100644 --- a/pa_common/portaudio.h +++ b/pa_common/portaudio.h @@ -63,7 +63,6 @@ typedef enum { /* Pa_Initialize() is the library initialisation function - call this before using the library. - */ PaError Pa_Initialize( void ); @@ -71,25 +70,19 @@ 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. - + Return host specific error. + This can be called after receiving a paHostError. */ - long Pa_GetHostError( void ); /* - Pa_GetErrorText() translates the supplied PortAudio error number - into a human readable message. - + Translate the error number into a human readable message. */ - const char *Pa_GetErrorText( PaError errnum ); /* @@ -99,14 +92,11 @@ const char *Pa_GetErrorText( PaError errnum ); 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. + Formats marked "always available" are supported (emulated) by all devices. + + The floating point representation uses +1.0 and -1.0 as the respective + maximum and minimum. - 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; @@ -116,23 +106,24 @@ typedef unsigned long PaSampleFormat; #define paInt24 ((PaSampleFormat) (1<<3)) #define paPackedInt24 ((PaSampleFormat) (1<<4)) #define paInt8 ((PaSampleFormat) (1<<5)) -#define paUInt8 ((PaSampleFormat) (1<<6)) +#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */ #define paCustomFormat ((PaSampleFormat) (1<<16)) /* Device enumeration mechanism. - Device ids range from 0 to Pa_CountDevices()-1. + Device ids range from 0 to Pa_CountDevices()-1. - Devices may support input, output or both. - + Devices may support input, output or both. Device 0 is always the "default" + device and should support at least stereo in and out if that is available + on the taget platform _even_ if this involves kludging an input/output + device on platforms that usually separate input from output. Other platform + specific devices are specified by positive device ids. */ typedef int PaDeviceID; #define paNoDevice -1 -int Pa_CountDevices( void ); - typedef struct { int structVersion; @@ -147,10 +138,12 @@ typedef struct } PaDeviceInfo; + +int Pa_CountDevices(); /* - Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the - default device ids for input and output respectively, or paNoDevice if - no device is available. + Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() + + Return the default device ID or paNoDevice if there is no devices. The result can be passed to Pa_OpenStream(). On the PC, the user can specify a default device by @@ -158,40 +151,34 @@ PaDeviceInfo; set PA_RECOMMENDED_OUTPUT_DEVICE=1 - The user should first determine the available device ids by using + The user should first determine the available device ID 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() - + start time useful for syncronisation. The type is used in the outTime + argument to the callback function and the result of Pa_StreamTime() */ typedef double PaTimestamp; /* - PortAudioCallback is implemented by PortAudio clients. + Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure + referring to the device specified by id. + If id is out of range the function returns NULL. + + The returned structure is owned by the PortAudio implementation and must + not be manipulated or freed. The pointer is only guaranteed to be valid + between calls to Pa_Initialize() and Pa_Terminate(). +*/ + +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID ); + +/* + PortAudioCallback is implemented by clients of the portable audio api. inputBuffer and outputBuffer are arrays of interleaved samples, the format, packing and number of channels used by the buffers are @@ -207,15 +194,15 @@ typedef double PaTimestamp; intended for storing synthesis data etc. return value: - The callback can return a non-zero value to stop the stream. This may be + The callback can return a nonzero 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. + nonzero 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)( @@ -229,11 +216,12 @@ typedef int (PortAudioCallback)( These flags may be supplied (ored together) in the streamFlags argument to the Pa_OpenStream() function. - + + [ suggestions? ] */ #define paNoFlag (0) -#define paClipOff (1<<0) /* disable default clipping of out of range samples */ +#define paClipOff (1<<0) /* disable defult clipping of out of range samples */ #define paDitherOff (1<<1) /* disable default dithering */ #define paPlatformSpecificFlags (0x00010000) typedef unsigned long PaStreamFlags; @@ -258,15 +246,15 @@ typedef void PortAudioStream; 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. + device input record for the device specified in the inputDevice parameter. If inputDevice is paNoDevice numInputChannels is ignored. - inputSampleFormat is the sample format of inputBuffer provided to the callback + inputSampleFormat is the 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. + the sound devices 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. @@ -288,24 +276,24 @@ typedef void PortAudioStream; 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 + sampleRate is the desired sampleRate for 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.) + 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. + These flags modify the behavior 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.) @@ -315,10 +303,10 @@ typedef void PortAudioStream; for processing the audio buffers. return value: - Upon success Pa_OpenStream() returns PaNoError and places a pointer to a + Apon 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. + If a call to Pa_OpenStream() fails a nonzero error code is returned (see + PAError above) and the value of stream is invalid. */ @@ -340,16 +328,15 @@ PaError Pa_OpenStream( PortAudioStream** stream, /* - 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: + Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that + opens the default input and/or ouput 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(). + is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() ) sampleFormat applies to both the input and output buffers. - */ PaError Pa_OpenDefaultStream( PortAudioStream** stream, @@ -364,17 +351,15 @@ PaError Pa_OpenDefaultStream( PortAudioStream** stream, /* 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_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. - + Pa_AbortStream() stops playing immediately without waiting for pending + buffers to complete. */ PaError Pa_StartStream( PortAudioStream *stream ); @@ -384,43 +369,37 @@ 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. + Pa_StreamActive() returns one when the stream is playing audio, + zero 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 + Pa_StreamTime() returns the current output time for the stream in samples. + This time may be used as a time reference (for example syncronising 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. + The "CPU Load" is a fraction of total CPU time consumed by the + stream's audio processing. 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. + Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for + 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: @@ -430,33 +409,23 @@ double Pa_GetCPULoad( PortAudioStream* stream ); 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.) - + Sleep for at least 'msec' milliseconds. + You may sleep longer than the requested time so don't rely + on this for accurate musical timing. */ - 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. - + Return size in bytes of a single sample in a given PaSampleFormat + or paSampleFormatNotSupported. */ - PaError Pa_GetSampleSize( PaSampleFormat format ); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/pa_mac/pa_mac.c b/pa_mac/pa_mac.c index 7a8e030..cde9a95 100644 --- a/pa_mac/pa_mac.c +++ b/pa_mac/pa_mac.c @@ -42,16 +42,7 @@ PLB20010907 - Pass unused event to WaitNextEvent to prevent Mac OSX crash. Thanks Dominic Mazzoni. PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. PLB20011009 - Use NewSndCallBackUPP() for CARBON - PLB20020417 - I used to call Pa_GetMinNumBuffers() which doesn't take into account the - variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will - give lower latency when virtual memory is turned off. - Thanks Kristoffer Jensen and Georgios Marentakis for spotting this bug. - PLB20020423 - Use new method to calculate CPU load similar to other ports. Based on num frames calculated. - Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer. - Added PA_MAX_USAGE_ALLOWED to prevent Mac form hanging when CPU load approaches 100%. - PLB20020424 - Fixed return value in Pa_StreamTime */ - /* COMPATIBILITY This Macintosh implementation is designed for use with Mac OS 7, 8 and @@ -81,7 +72,6 @@ O- Determine default devices somehow. #include #include #include - /* Mac specific includes */ #include "OSUtils.h" #include @@ -94,7 +84,6 @@ O- Determine default devices somehow. #include #include #include - #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" @@ -104,16 +93,6 @@ O- Determine default devices somehow. #define TRUE (!FALSE) #endif -/* #define TARGET_API_MAC_CARBON (1) */ - -/* - * Define maximum CPU load that will be allowed. User callback will - * be skipped if load exceeds this limit. This is to prevent the Mac - * from hanging when the CPU is hogged by the sound thread. - * On my PowerBook G3, the mac hung when I used 94% of CPU ( usage = 0.94 ). - */ -#define PA_MAX_USAGE_ALLOWED (0.92) - /* Debugging output macros. */ #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) @@ -122,7 +101,7 @@ O- Determine default devices somehow. #define MAC_PHYSICAL_FRAMES_PER_BUFFER (512) /* Minimum number of stereo frames per SoundManager double buffer. */ #define MAC_VIRTUAL_FRAMES_PER_BUFFER (4096) /* Need this many when using Virtual Memory for recording. */ -#define PA_MIN_NUM_HOST_BUFFERS (2) +#define PA_MIN_NUM_HOST_BUFFERS (2) #define PA_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */ #define PA_MAX_DEVICE_INFO (32) @@ -147,8 +126,7 @@ MultiBuffer; typedef struct PaHostSoundControl { UInt64 pahsc_EntryCount; - double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */ - + UInt64 pahsc_LastExitCount; /* Use char instead of Boolean for atomic operation. */ volatile char pahsc_IsRecording; /* Recording in progress. Set by foreground. Cleared by background. */ volatile char pahsc_StopRecording; /* Signal sent to background. */ @@ -156,23 +134,22 @@ typedef struct PaHostSoundControl /* Input */ SPB pahsc_InputParams; SICompletionUPP pahsc_InputCompletionProc; - MultiBuffer pahsc_InputMultiBuffer; - int32 pahsc_BytesPerInputHostBuffer; + MultiBuffer pahsc_InputMultiBuffer; + int32 pahsc_BytesPerInputHostBuffer; int32 pahsc_InputRefNum; /* Output */ CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS]; int32 pahsc_BytesPerOutputHostBuffer; - SndChannelPtr pahsc_Channel; + SndChannelPtr pahsc_Channel; SndCallBackUPP pahsc_OutputCompletionProc; int32 pahsc_NumOutsQueued; int32 pahsc_NumOutsPlayed; PaTimestamp pahsc_NumFramesDone; - UInt64 pahsc_WhenFramesDoneIncremented; /* Init Time -------------- */ int32 pahsc_NumHostBuffers; int32 pahsc_FramesPerHostBuffer; int32 pahsc_UserBuffersPerHostBuffer; - int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */ + int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */ } PaHostSoundControl; @@ -200,8 +177,7 @@ static int sDefaultInputDeviceID; /************************************************************************************/ static PaError PaMac_TimeSlice( internalPortAudioStream *past, int16 *macOutputBufPtr ); static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr ); -static PaError PaMac_RecordNext( internalPortAudioStream *past ); -static void PaMac_StartLoadCalculation( internalPortAudioStream *past ); +static PaError PaMac_RecordNext( internalPortAudioStream *past );static void StartLoadCalculation( internalPortAudioStream *past ); static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate ); static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h ); static PaError PaMac_ScanInputDevices( void ); @@ -720,8 +696,8 @@ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) return sDefaultOutputDeviceID; } -/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ -static void PaMac_StartLoadCalculation( internalPortAudioStream *past ) +/**************************************************************************/ +static void StartLoadCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; UnsignedWide widePad; @@ -731,36 +707,38 @@ static void PaMac_StartLoadCalculation( internalPortAudioStream *past ) pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad ); } -/****************************************************************************** -** Measure fractional CPU load based on real-time it took to calculate -** buffers worth of output. -*/ /**************************************************************************/ static void PaMac_EndLoadCalculation( internalPortAudioStream *past ) { UnsignedWide widePad; - UInt64 currentCount; - long usecsElapsed; - double newUsage; + UInt64 CurrentCount; + long InsideCount; + long TotalCount; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; - /* Measure CPU utilization during this callback. Note that this calculation ** assumes that we had the processor the whole time. */ -#define LOWPASS_COEFFICIENT_0 (0.95) +#define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) Microseconds( &widePad ); - currentCount = UnsignedWideToUInt64( widePad ); - - usecsElapsed = (long) U64Subtract(currentCount, pahsc->pahsc_EntryCount); - - /* Use inverse because it is faster than the divide. */ - newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer; - - past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + - (LOWPASS_COEFFICIENT_1 * newUsage); - + CurrentCount = UnsignedWideToUInt64( widePad ); + if( past->past_IfLastExitValid ) + { + InsideCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_EntryCount); + TotalCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_LastExitCount); + /* Low pass filter the result because sometimes we get called several times in a row. + * That can cause the TotalCount to be very low which can cause the usage to appear + * unnaturally high. So we must filter numerator and denominator separately!!! + */ + past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * InsideCount)); + past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * TotalCount)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + } + pahsc->pahsc_LastExitCount = CurrentCount; + past->past_IfLastExitValid = 1; } /*********************************************************************** @@ -851,14 +829,6 @@ static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHead sndHeader->format = kSoundNotCompressed; } -static void SetFramesDone( PaHostSoundControl *pahsc, PaTimestamp framesDone ) -{ - UnsignedWide now; - Microseconds( &now ); - pahsc->pahsc_NumFramesDone = framesDone; - pahsc->pahsc_WhenFramesDoneIncremented = UnsignedWideToUInt64( now ); -} - /***********************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { @@ -874,8 +844,7 @@ PaError PaHost_StartOutput( internalPortAudioStream *past ) past->past_IsActive = 1; pahsc->pahsc_NumOutsQueued = 0; pahsc->pahsc_NumOutsPlayed = 0; - - SetFramesDone( pahsc, 0.0 ); + pahsc->pahsc_NumFramesDone = 0.0; /* Pause channel so it does not do back ground processing while we are still filling the queue. */ pauseCommand.cmd = pauseCmd; @@ -888,7 +857,7 @@ PaError PaHost_StartOutput( internalPortAudioStream *past ) { PaMac_PlayNext( past, i ); } - + /* Resume channel now that the queue is full. */ resumeCommand.cmd = resumeCmd; resumeCommand.param1 = resumeCommand.param2 = 0; @@ -973,8 +942,8 @@ int Mac_IsVirtualMemoryOn( void ) } /******************************************************************* -* Determine number of host Buffers -* and how many User Buffers we can put into each host buffer. +* Determine number of WAVE Buffers +* and how many User Buffers we can put into each WAVE buffer. */ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) { @@ -985,23 +954,16 @@ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) int32 userBuffersPerHostBuffer; int32 framesPerHostBuffer; int32 numHostBuffers; - + /* Calculate minimum and maximum sizes based on timing and sample rate. */ minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer; minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); - /* Determine number of user buffers based on minimum latency. */ - /* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the - ** variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will - ** gove lower latency when virtual memory is turned off. */ - /* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */ - minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate ); - + minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; - - /* We cannot make the buffers too small because they may not get serviced quickly enough. */ + /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) { userBuffersPerHostBuffer = @@ -1013,17 +975,16 @@ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) userBuffersPerHostBuffer = 1; } framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; - - /* Calculate number of host buffers needed. Round up to cover minTotalFrames. */ + /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; - /* Make sure we have enough host buffers. */ + /* Make sure we have anough WAVE buffers. */ if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) { numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; } else { - /* If we have too many host buffers, try to put more user buffers in a host buffer. */ + /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) { userBuffersPerHostBuffer += 1; @@ -1067,9 +1028,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) } PaHost_CalcNumHostBuffers( past ); - - /* Setup constants for CPU load measurement. */ - pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer); /* ------------------ OUTPUT */ if( past->past_NumOutputChannels > 0 ) @@ -1261,9 +1219,6 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) /*************************************************************************/ int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) { -/* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording. -** This routine doesn't have enough information to determine the best value -** and is being depracated. */ return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate ); } /*************************************************************************/ @@ -1343,37 +1298,11 @@ void PaHost_FreeFastMemory( void *addr, long numBytes ) /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { - PaTimestamp framesDone1; - PaTimestamp framesDone2; - UInt64 whenIncremented; - UnsignedWide now; - UInt64 now64; - long microsElapsed; - long framesElapsed; - PaHostSoundControl *pahsc; internalPortAudioStream *past = (internalPortAudioStream *) stream; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; - -/* Capture information from audio thread. - * We have to be careful that we don't get interrupted in the middle. - * So we grab the pahsc_NumFramesDone twice and make sure it didn't change. - */ - do - { - framesDone1 = pahsc->pahsc_NumFramesDone; - whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented; - framesDone2 = pahsc->pahsc_NumFramesDone; - } while( framesDone1 != framesDone2 ); - - /* Calculate how many microseconds have elapsed and convert to frames. */ - Microseconds( &now ); - now64 = UnsignedWideToUInt64( now ); - microsElapsed = U64Subtract( now64, whenIncremented ); - framesElapsed = microsElapsed * past->past_SampleRate * 0.000001; - - return framesDone1 + framesElapsed; + return pahsc->pahsc_NumFramesDone; } /************************************************************************** @@ -1411,8 +1340,7 @@ pascal void PaMac_InputCompletionProc(SPBPtr recParams) */ if(past->past_NumOutputChannels == 0) { - SetFramesDone( pahsc, - pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer ); + pahsc->pahsc_NumFramesDone += pahsc->pahsc_FramesPerHostBuffer; // Advance for recording result = PaMac_CallUserLoop( past, NULL ); } @@ -1443,7 +1371,6 @@ static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPt PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; int16 *inPtr = NULL; int i; - /* Advance read index for sound input FIFO here, independantly of record/write process. */ if(past->past_NumInputChannels > 0) @@ -1458,33 +1385,22 @@ static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPt /* Call user code enough times to fill buffer. */ if( (inPtr != NULL) || (outPtr != NULL) ) { - PaMac_StartLoadCalculation( past ); /* CPU usage */ + StartLoadCalculation( past ); /* CPU usage */ + + for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) + { + result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr ); + if( result != 0) + { + /* Recording might be in another process, so tell it to stop with a flag. */ + pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording; + break; + } + /* Advance sample pointers. */ + if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels; + if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels; + } -#ifdef PA_MAX_USAGE_ALLOWED - /* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */ - if( past->past_Usage > PA_MAX_USAGE_ALLOWED ) - { - past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer; - } - else -#endif - { - - for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) - { - result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr ); - if( result != 0) - { - /* Recording might be in another process, so tell it to stop with a flag. */ - pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording; - break; - } - /* Advance sample pointers. */ - if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels; - if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels; - } - } - PaMac_EndLoadCalculation( past ); } return result; @@ -1571,10 +1487,8 @@ static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndComm pahsc = (PaHostSoundControl *) past->past_DeviceData; pahsc->pahsc_NumOutsPlayed += 1; + pahsc->pahsc_NumFramesDone += pahsc->pahsc_FramesPerHostBuffer; - SetFramesDone( pahsc, - pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer ); - PaMac_BackgroundManager( past, theCallBackCmd->param1 ); } @@ -1626,19 +1540,16 @@ static void PaMac_PlayNext ( internalPortAudioStream *past, int index ) /* If this was the last buffer, or abort requested, then just be done. */ if ( past->past_StopSoon ) goto done; - /* Load buffer with sound. */ result = PaMac_FillNextOutputBuffer ( past, index ); if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */ else if( result < 0 ) goto done; - /* Play the next buffer. */ playCmd.cmd = bufferCmd; playCmd.param1 = 0; playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ]; error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true ); if( error != noErr ) goto gotError; - /* Ask for a callback when it is done. */ callbackCmd.cmd = callBackCmd; callbackCmd.param1 = index; diff --git a/pa_mac_core/notes.txt b/pa_mac_core/notes.txt deleted file mode 100644 index c79b90e..0000000 --- a/pa_mac_core/notes.txt +++ /dev/null @@ -1,34 +0,0 @@ -Notes on Core Audio Implementation of PortAudio - -by Phil Burk and Darren Gibbs - -Document last updated March 20, 2002 - -WHAT WORKS - -Output with very low latency, <10 msec. -Half duplex input or output. -Full duplex on the same CoreAudio device. -The paFLoat32, paInt16, paInt8, paUInt8 sample formats. -Pa_GetCPULoad() -Pa_StreamTime() - -KNOWN BUGS OR LIMITATIONS - -We do not yet support simultaneous input and output on different -devices. Note that some CoreAudio devices like the Roland UH30 look -like one device but are actually two different CoreAudio devices. The -BuiltIn audio is typically one CoreAudio device. - -Mono doesn't work. - -DEVICE MAPPING - -CoreAudio devices can support both input and output. But the sample -rates supported may be different. So we have map one or two PortAudio -device to each CoreAudio device depending on whether it supports -input, output or both. - -When we query devices, we first get a list of CoreAudio devices. Then -we scan the list and add a PortAudio device for each CoreAudio device -that supports input. Then we make a scan for output devices. diff --git a/pa_mac_core/pa_mac_core.c b/pa_mac_core/pa_mac_core.c index e608402..3dc4d74 100644 --- a/pa_mac_core/pa_mac_core.c +++ b/pa_mac_core/pa_mac_core.c @@ -37,53 +37,40 @@ 3.29.2001 - Phil Burk - First pass... converted from Window MME code with help from Darren. 3.30.2001 - Darren Gibbs - Added more support for dynamically querying device info. 12.7.2001 - Gord Peters - Tweaks to compile on PA V17 and OS X 10.1 - 2.7.2002 - Darren and Phil - fixed isInput so GetProperty works better, - fixed device queries for numChannels and sampleRates, - one CoreAudio device now maps to separate input and output PaDevices, - audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices). - 2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7 - 3.19.2002 - Phil Burk - Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file. - Return error if opened in mono mode cuz not supported. - Add support for Pa_GetCPULoad(); - Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!) - Check for invalid sample rates and return an error. - Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally. - Better error checking for invalid channel counts and invalid devices. - 3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers. - 3.31.2002 - Phil Burk - Use getrusage() instead of gettimeofday() for CPU Load calculation. - -TODO: -O- how do mono output? -O- FIFO between input and output callbacks if different devices, like in pa_mac.c -*/ - + */ #include #include #include -#include #include - #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" /************************************************* Constants ********/ +#define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ +#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ + +/* Switches for debugging. */ +#define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ /* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ #define PA_TRACE_RUN (0) #define PA_TRACE_START_STOP (1) -#define PA_MIN_LATENCY_MSEC (8) -#define MIN_TIMEOUT_MSEC (1000) +#define PA_MIN_MSEC_PER_HOST_BUFFER (10) +#define PA_MAX_MSEC_PER_HOST_BUFFER (100) /* Do not exceed unless user buffer exceeds */ +#define PA_MIN_NUM_HOST_BUFFERS (3) +#define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ +#define PA_MIN_LATENCY_MSEC (200) + +#define MIN_TIMEOUT_MSEC (1000) #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) /**/ -#define DBUGX(x) /* PRINT(x) /**/ +#define DBUG(x) /* PRINT(x) */ +#define DBUGX(x) /* PRINT(x) */ -// define value of isInput passed to CoreAudio routines -#define IS_INPUT (true) -#define IS_OUTPUT (false) +/************************************************* Definitions ********/ /************************************************************** * Structure for internal host specific stream data. @@ -91,175 +78,127 @@ O- FIFO between input and output callbacks if different devices, like in pa_mac. */ typedef struct PaHostSoundControl { - AudioDeviceID pahsc_AudioDeviceID; // Must be the same for input and output for now. /* Input -------------- */ - int pahsc_BytesPerUserNativeInputBuffer; /* native buffer size in bytes per user chunk */ + int pahsc_BytesPerHostInputBuffer; + int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */ /* Output -------------- */ - int pahsc_BytesPerUserNativeOutputBuffer; /* native buffer size in bytes per user chunk */ - /* Init Time -------------- */ - int pahsc_FramesPerHostBuffer; - int pahsc_UserBuffersPerHostBuffer; + AudioDeviceID pahsc_OutputAudioDeviceID; + int pahsc_BytesPerHostOutputBuffer; + int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */ + /* Run Time -------------- */ + PaTimestamp pahsc_FramesPlayed; + long pahsc_LastPosition; /* used to track frames played. */ /* For measuring CPU utilization. */ - struct rusage pahsc_EntryRusage; - double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */ + // LARGE_INTEGER pahsc_EntryCount; + // LARGE_INTEGER pahsc_LastExitCount; + /* Init Time -------------- */ + int pahsc_NumHostBuffers; + int pahsc_FramesPerHostBuffer; + int pahsc_UserBuffersPerHostBuffer; + + // CRITICAL_SECTION pahsc_StreamLock; /* Mutext to prevent threads from colliding. */ + int pahsc_StreamLockInited; + } PaHostSoundControl; -/************************************************************** - * Structure for internal extended device info. - * There will be one or two PortAudio devices for each Core Audio device: - * one input and or one output. - */ -typedef struct PaHostDeviceInfo -{ - PaDeviceInfo paInfo; - AudioDeviceID audioDeviceID; -} -PaHostDeviceInfo; - /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ -static int sNumPaDevices = 0; /* Total number of PaDeviceInfos */ -static int sNumInputDevices = 0; /* Total number of input PaDeviceInfos */ -static int sNumOutputDevices = 0; -static PaHostDeviceInfo *sDeviceInfos = NULL; +static int sNumDevices = 0; +static PaDeviceInfo **sDevicePtrs = NULL; static int sDefaultInputDeviceID = paNoDevice; static int sDefaultOutputDeviceID = paNoDevice; static int sPaHostError = 0; - -static int sNumCoreDevices = 0; -static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs +static AudioDeviceID *sDeviceIDList; // Array of AudioDeviceIDs static const char sMapperSuffixInput[] = " - Input"; static const char sMapperSuffixOutput[] = " - Output"; -/* We index the input devices first, then the output devices. */ -#define LOWEST_INPUT_DEVID (0) -#define HIGHEST_INPUT_DEVID (sNumInputDevices - 1) -#define LOWEST_OUTPUT_DEVID (sNumInputDevices) -#define HIGHEST_OUTPUT_DEVID (sNumPaDevices - 1) - /************************************************* Macros ********/ +/* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ +#define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) + /************************************************* Prototypes **********/ static PaError Pa_QueryDevices( void ); PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); - -static int PaHost_ScanDevices( Boolean isInput ); -static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput ); - -static PaDeviceID Pa_QueryDefaultInputDevice( void ); -static PaDeviceID Pa_QueryDefaultOutputDevice( void ); -static void PaHost_CalcHostBufferSize( internalPortAudioStream *past ); - /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; - /* Query user CPU timer for usage analysis and to prevent overuse of CPU. */ - getrusage( RUSAGE_SELF, &pahsc->pahsc_EntryRusage ); + /* Query system timer for usage analysis and to prevent overuse of CPU. */ + // QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); } -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 rusage currentRusage; - long usecsElapsed; - double newUsage; - -#define LOWPASS_COEFFICIENT_0 (0.95) +#if 0 + // LARGE_INTEGER CurrentCount = { 0, 0 }; + // LONGLONG InsideCount; + // LONGLONG TotalCount; + /* + ** Measure CPU utilization during this callback. Note that this calculation + ** assumes that we had the processor the whole time. + */ +#define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; - - if( getrusage( RUSAGE_SELF, ¤tRusage ) == 0 ) - { - usecsElapsed = SubtractTime_AminusB( ¤tRusage.ru_utime, &pahsc->pahsc_EntryRusage.ru_utime ); - - /* Use inverse because it is faster than the divide. */ - newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer; - past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + - (LOWPASS_COEFFICIENT_1 * newUsage); + if( QueryPerformanceCounter( &CurrentCount ) ) + { + if( past->past_IfLastExitValid ) + { + InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; + TotalCount = CurrentCount.QuadPart - pahsc->pahsc_LastExitCount.QuadPart; + /* Low pass filter the result because sometimes we get called several times in a row. + * That can cause the TotalCount to be very low which can cause the usage to appear + * unnaturally high. So we must filter numerator and denominator separately!!! + */ + past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + + (LOWPASS_COEFFICIENT_1 * InsideCount)); + past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + + (LOWPASS_COEFFICIENT_1 * TotalCount)); + past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; + } + pahsc->pahsc_LastExitCount = CurrentCount; + past->past_IfLastExitValid = 1; } +#endif } + +static PaDeviceID Pa_QueryDefaultDevice( int deviceEnum ) +{ + OSStatus err = noErr; + UInt32 count; + int i; + AudioDeviceID tempDevice = kAudioDeviceUnknown; + PaDeviceID defaultDeviceID; + + // get the default output device for the HAL + // it is required to pass the size of the data to be returned + count = sizeof(AudioDeviceID); + err = AudioHardwareGetProperty( deviceEnum, &count, (void *) &tempDevice); + if (err != noErr) goto Bail; + // find index of default device + defaultDeviceID = paNoDevice; + for( i=0; i= sNumPaDevices ) - return NULL; +#define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */ +#define NUM_CUSTOMSAMPLINGRATES 4 /* must be the same number of elements as in the array below */ +#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES) - return &sDeviceInfos[id].paInfo; -} - -/************************************************************************* -** Scan all of the Core Audio devices to see which support input or output. -** Changes sNumDevices, and fills in sDeviceInfos. -*/ -static int PaHost_ScanDevices( Boolean isInput ) -{ - int coreDeviceIndex; - int result; - PaHostDeviceInfo *hostDeviceInfo; - int numAdded = 0; - - for( coreDeviceIndex=0; coreDeviceIndexaudioDeviceID )); - if( result > 0 ) - { - sNumPaDevices += 1; // bump global counter if we got one - numAdded += 1; - } - else if( result < 0 ) return result; - } - return numAdded; -} - -/************************************************************************* -** Try to fill in the device info for this device. -** Return 1 if a good device that PA can use. -** Return 0 if not appropriate -** or return negative error. -** -*/ -static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput ) -{ - OSErr err; + PaDeviceInfo *deviceInfo; + AudioDeviceID devID; + double *sampleRates; /* non-const ptr */ + double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0}; int index; - UInt32 outSize; AudioStreamBasicDescription formatDesc; Boolean result; - AudioDeviceID devID; - double *sampleRates = NULL; /* non-const ptr */ - PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo; - double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0}; - int maxNumSampleRates = sizeof( possibleSampleRates ) / sizeof( double ); + if( id < 0 || id >= sNumDevices ) + return NULL; + + if( sDevicePtrs[ id ] != NULL ) + { + return sDevicePtrs[ id ]; + } + + deviceInfo = PaHost_AllocateFastMemory( sizeof(PaDeviceInfo) ); + if( deviceInfo == NULL ) return NULL; deviceInfo->structVersion = 1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->numSampleRates = -1; - devID = sCoreDeviceIDs[ coreDeviceIndex ]; - hostDeviceInfo->audioDeviceID = devID; - // Figure out supported sample rates - // Make room in case device supports all rates. - sampleRates = (double*)PaHost_AllocateFastMemory( maxNumSampleRates * sizeof(double) ); - if( sampleRates == NULL ) return paInsufficientMemory; - - deviceInfo->sampleRates = sampleRates; - deviceInfo->numSampleRates = 0; - - // Loop through the possible sampling rates and check each to see if the device supports it. - for (index = 0; index < maxNumSampleRates; index ++) + // fill in format descriptor + if( id < sNumDevices ) { - memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); - formatDesc.mSampleRate = possibleSampleRates[index]; - result = deviceDoesSupportFormat( devID, &formatDesc, isInput ); + devID = sDeviceIDList[ id ]; - if (result == true) + // Get the device name + deviceInfo->name = deviceNameFromID( devID ); + + // Figure out supported sample rates + // Make room in case device supports all rates. + sampleRates = (double*)PaHost_AllocateFastMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); + deviceInfo->sampleRates = sampleRates; + deviceInfo->numSampleRates = 0; + + // Loop through the possible sampling rates and check each to see if the device supports it. + for (index = 0; index < MAX_NUMSAMPLINGRATES; index ++) { - deviceInfo->numSampleRates += 1; - *sampleRates = possibleSampleRates[index]; - sampleRates++; + memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); + formatDesc.mSampleRate = possibleSampleRates[index]; + result = deviceDoesSupportFormat( devID, &formatDesc ); + + if (result == true) + { + deviceInfo->numSampleRates += 1; + *sampleRates = possibleSampleRates[index]; + sampleRates++; + } } - } - // If no sample rates supported, then not a very good device. - if( deviceInfo->numSampleRates == 0 ) goto error; - // Get data format info from the device. - outSize = sizeof(formatDesc); - err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc); + // Get data format info from the device. + deviceDataFormatFromID(devID, &formatDesc); - // If no channels supported, then not a very good device. - if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error; - - if( isInput ) - { - deviceInfo->maxInputChannels = formatDesc.mChannelsPerFrame; - } - else - { + deviceInfo->maxInputChannels = 0; // FIXME - Input and Output are separate devices! deviceInfo->maxOutputChannels = formatDesc.mChannelsPerFrame; + + // FIXME - where to put current sample rate?: formatDesc.mSampleRate + + // Right now the Core Audio headers only define one formatID: LinearPCM + // Apparently LinearPCM must be Float32 for now. + // FIXME - + switch (formatDesc.mFormatID) + { + case kAudioFormatLinearPCM: + deviceInfo->nativeSampleFormats = paFloat32; + + // FIXME - details about the format are in these flags. + // formatDesc.mFormatFlags + + // here are the possibilities + // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer + // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little + // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer, + // only valid if kLinearPCMFormatFlagIsFloat is clear + // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible, + // clear if they are high or low aligned within the channel + // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed + + break; + default: + deviceInfo->nativeSampleFormats = paFloat32; // FIXME + break; + } + } - // FIXME - where to put current sample rate?: formatDesc.mSampleRate + sDevicePtrs[ id ] = deviceInfo; + return deviceInfo; - // Right now the Core Audio headers only define one formatID: LinearPCM - // Apparently LinearPCM must be Float32 for now. - switch (formatDesc.mFormatID) - { - case kAudioFormatLinearPCM: - deviceInfo->nativeSampleFormats = paFloat32; + /* FIXME + error: + free( sampleRates ); + free( deviceInfo ); + */ - // FIXME - details about the format are in these flags. - // formatDesc.mFormatFlags - - // here are the possibilities - // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer - // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little - // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer, - // only valid if kLinearPCMFormatFlagIsFloat is clear - // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible, - // clear if they are high or low aligned within the channel - // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed - break; - - default: - deviceInfo->nativeSampleFormats = paFloat32; // FIXME - break; - } - - // Get the device name - deviceInfo->name = PaHost_DeviceNameFromID( devID, isInput ); - return 1; - -error: - if( sampleRates != NULL ) free( sampleRates ); - return 0; + return NULL; } /************************************************************************* @@ -583,7 +491,7 @@ static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) static PaError Pa_MaybeQueryDevices( void ) { - if( sNumPaDevices == 0 ) + if( sNumDevices == 0 ) { return Pa_QueryDevices(); } @@ -625,6 +533,9 @@ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) PaError PaHost_Init( void ) { +#if PA_SIMULATE_UNDERFLOW + PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); +#endif return Pa_MaybeQueryDevices(); } @@ -636,8 +547,10 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL AudioBufferList* outOutputData ) { PaError result = 0; - char *inputNativeBufferfPtr = NULL; - char *outputNativeBufferfPtr = NULL; + char *inBufPtr; + char *outBufPtr; + int gotInput = 0; + int gotOutput = 0; int i; int buffersProcessed = 0; int done = 0; @@ -646,6 +559,13 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL past->past_NumCallbacks += 1; +#if PA_SIMULATE_UNDERFLOW + if(gUnderCallbackCounter++ == UNDER_SLEEP_AT) + { + Sleep(UNDER_SLEEP_FOR); + } +#endif + #if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks ); #endif @@ -653,15 +573,20 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL Pa_StartUsageCalculation( past ); /* If we are using output, then we need an empty output buffer. */ + gotOutput = 0; if( past->past_NumOutputChannels > 0 ) { - outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData; + outBufPtr = outOutputData->mBuffers[0].mData, + gotOutput = 1; } /* If we are using input, then we need a full input buffer. */ + gotInput = 0; + inBufPtr = NULL; if( past->past_NumInputChannels > 0 ) { - inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData; + inBufPtr = inInputData->mBuffers[0].mData, + gotInput = 1; } buffersProcessed += 1; @@ -671,21 +596,21 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL { if( done ) { - if( outputNativeBufferfPtr ) + if( gotOutput ) { /* Clear remainder of wave buffer if we are waiting for stop. */ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); - memset( outputNativeBufferfPtr, 0, pahsc->pahsc_BytesPerUserNativeOutputBuffer ); + memset( outBufPtr, 0, pahsc->pahsc_BytesPerUserOutputBuffer ); } } else { - /* Convert 32 bit native data to user data and call user routine. */ - result = PaConvert_Process( past, inputNativeBufferfPtr, outputNativeBufferfPtr ); + /* Convert 16 bit native data to user data and call user routine. */ + result = Pa_CallConvertFloat32( past, (float *) inBufPtr, (float *) outBufPtr ); if( result != 0) done = 1; } - if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer; - if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer; + if( gotInput ) inBufPtr += pahsc->pahsc_BytesPerUserInputBuffer; + if( gotOutput) outBufPtr += pahsc->pahsc_BytesPerUserOutputBuffer; } Pa_EndUsageCalculation( past ); @@ -697,10 +622,7 @@ static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferL return (result != 0) ? result : done; } -OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, - const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, - AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, - void* contextPtr) +OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* contextPtr) { PaError result = 0; @@ -709,7 +631,7 @@ OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, past = (internalPortAudioStream *) contextPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; -// printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers); + // Just Curious: printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers); /* Has someone asked us to abort by calling Pa_AbortStream()? */ if( past->past_StopNow ) @@ -726,12 +648,6 @@ OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, } else { - /* use time stamp from CoreAudio if valid */ - if( inOutputTime->mFlags & kAudioTimeStampSampleTimeValid) - { - past->past_FrameCount = inOutputTime->mSampleTime; - } - /* Process full input buffer and fill up empty output buffers. */ if( (result = Pa_TimeSlice( past, inInputData, outOutputData )) != 0) { @@ -749,7 +665,6 @@ OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, return result; } -#if 0 static int PaHost_CalcTimeOut( internalPortAudioStream *past ) { /* Calculate timeOut longer than longest time it could take to play all buffers. */ @@ -757,150 +672,59 @@ static int PaHost_CalcTimeOut( internalPortAudioStream *past ) if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; return timeOut; } -#endif - - -/*******************************************************************/ -/* Attempt to set device sample rate. */ -static PaError PaHost_SetSampleRate( AudioDeviceID devID, Boolean isInput, double sampleRate ) -{ - AudioStreamBasicDescription formatDesc; - OSStatus err; - memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); - formatDesc.mSampleRate = sampleRate; - err = AudioDeviceSetProperty( devID, 0, 0, - isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); - - if (err != kAudioHardwareNoError) return paInvalidSampleRate; - else return paNoError; -} /*******************************************************************/ PaError PaHost_OpenInputStream( internalPortAudioStream *past ) { - PaHostSoundControl *pahsc; - const PaHostDeviceInfo *hostDeviceInfo; PaError result = paNoError; - UInt32 bytesPerHostBuffer; - UInt32 dataSize; - OSStatus err = noErr; + PaHostSoundControl *pahsc; int bytesPerInputFrame; + const PaDeviceInfo *pad; pahsc = (PaHostSoundControl *) past->past_DeviceData; - + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID)); - if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) || - (past->past_InputDeviceID > HIGHEST_INPUT_DEVID) ) - { - return paInvalidDeviceId; - } - hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID]; + pad = Pa_GetDeviceInfo( past->past_InputDeviceID ); + if( pad == NULL ) return paInternalError; - /* Try to set sample rate. */ - result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_INPUT, past->past_SampleRate ); - if( result != paNoError ) return result; - - if( past->past_NumInputChannels != hostDeviceInfo->paInfo.maxInputChannels ) - { -#if 1 - return paInvalidChannelCount; // FIXME - how support mono? -#else -FIXME - should this be set on a stream basis? Is it possible to change? - /* Attempt to set number of channels. */ - AudioStreamBasicDescription formatDesc; - OSStatus err; - memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); - formatDesc.mChannelsPerFrame = past->past_NumInputChannels; - - err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, - IS_INPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); - if (err != kAudioHardwareNoError) - { - result = paInvalidChannelCount; - goto error; - } -#endif - } - - // calculate native buffer sizes in bytes - bytesPerInputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels; - pahsc->pahsc_BytesPerUserNativeInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame; - bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerInputFrame; - - // Change the bufferSize of the device! Is this per device or just for our stream? - dataSize = sizeof(UInt32); - err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT, - kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); - if( err != noErr ) - { - ERR_RPT(("Could not force buffer size!")); - result = paHostError; - goto error; - } - - // setup conversion procedure - result = PaConvert_SetupInput( past, paFloat32 ); - - return result; - -error: + bytesPerInputFrame = Pa_GetSampleSize(pad->nativeSampleFormats) * past->past_NumInputChannels; + pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame; + pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer; + // FIXME return result; } /*******************************************************************/ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) { - PaHostSoundControl *pahsc; - const PaHostDeviceInfo *hostDeviceInfo; PaError result = paNoError; + PaHostSoundControl *pahsc; + const PaDeviceInfo *pad; UInt32 bytesPerHostBuffer; - UInt32 dataSize; + UInt32 dataSize; + UInt32 hardwareLatency = -1; + Boolean writeable = false; OSStatus err = noErr; int bytesPerOutputFrame; - + pahsc = (PaHostSoundControl *) past->past_DeviceData; - + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); - if( (past->past_OutputDeviceID < LOWEST_OUTPUT_DEVID) || - (past->past_OutputDeviceID > HIGHEST_OUTPUT_DEVID) ) - { - return paInvalidDeviceId; - } - hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID]; + pad = Pa_GetDeviceInfo( past->past_OutputDeviceID ); + if( pad == NULL ) return paInternalError; - /* Try to set sample rate. */ - result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_OUTPUT, past->past_SampleRate ); - if( result != paNoError ) return result; + pahsc->pahsc_OutputAudioDeviceID = sDeviceIDList[past->past_OutputDeviceID]; - if( past->past_NumOutputChannels != hostDeviceInfo->paInfo.maxOutputChannels ) - { -#if 1 - return paInvalidChannelCount; // FIXME - how support mono? -#else - /* Attempt to set number of channels. */ - AudioStreamBasicDescription formatDesc; - OSStatus err; - memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); - formatDesc.mChannelsPerFrame = past->past_NumOutputChannels; - err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, - IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); + bytesPerOutputFrame = Pa_GetSampleSize(pad->nativeSampleFormats) * past->past_NumOutputChannels; + pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame; + pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer; - if (err != kAudioHardwareNoError) - { - result = paInvalidChannelCount; - goto error; - } -#endif - } + // FIXME - force host buffer to user size - // calculate buffer sizes in bytes - bytesPerOutputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels; - pahsc->pahsc_BytesPerUserNativeOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame; - bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerOutputFrame; - - // Change the bufferSize of the device! Is this per device or just for our stream? - dataSize = sizeof(bytesPerHostBuffer); - err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT, + // change the bufferSize of the device + bytesPerHostBuffer = past->past_OutputBufferSize; // FIXME + dataSize = sizeof(UInt32); + err = AudioDeviceSetProperty( pahsc->pahsc_OutputAudioDeviceID, 0, 0, false, kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); if( err != noErr ) { @@ -908,10 +732,25 @@ PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) result = paHostError; goto error; } - - // setup conversion procedure - result = PaConvert_SetupOutput( past, paFloat32 ); - + + // FIXME -- this isn't working for some reason. I can't figure out what the error code is. + dataSize = sizeof(UInt32); + err = AudioDeviceGetProperty(pahsc->pahsc_OutputAudioDeviceID, 0, false, kAudioDevicePropertyLatency, &dataSize, &writeable); + if( err != noErr ) + { + PRINT(("A CoreAudio error occurred: %s.\n", coreAudioErrorString( err ) )); + } + + err = AudioDeviceGetProperty(pahsc->pahsc_OutputAudioDeviceID, 0, false, kAudioDevicePropertyLatency, &dataSize, (void *)&hardwareLatency); + if ( err != noErr ) + { + PRINT(("A CoreAudio error occurred: %s.\n", coreAudioErrorString( err ) )); + } + else + { + PRINT(("Output Stream Hardware Latency = %d frames.\n", hardwareLatency )); + } + return result; error: @@ -922,38 +761,92 @@ error: PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - return pahsc->pahsc_FramesPerHostBuffer; + return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer; } /******************************************************************* -* Determine how many User Buffers we can put into our CoreAudio stream buffer. -* Uses: -* past->past_FramesPerUserBuffer, etc. -* Sets: -* past->past_NumUserBuffers -* pahsc->pahsc_UserBuffersPerHostBuffer -* pahsc->pahsc_FramesPerHostBuffer +* Determine number of WAVE Buffers +* and how many User Buffers we can put into each WAVE buffer. */ -static void PaHost_CalcHostBufferSize( internalPortAudioStream *past ) +void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) { - PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData; - unsigned int minNumUserBuffers; + PaHostSoundControl *pahsc = past->past_DeviceData; + unsigned int minNumBuffers; + int minFramesPerHostBuffer; + int maxFramesPerHostBuffer; + int minTotalFrames; + int userBuffersPerHostBuffer; + int framesPerHostBuffer; + int numHostBuffers; - // Determine number of user buffers based on minimum latency. - minNumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); - // Compare to user requested number in user wants more than the minimum. - past->past_NumUserBuffers = ( minNumUserBuffers > past->past_NumUserBuffers ) ? - minNumUserBuffers : past->past_NumUserBuffers; + /* Calculate minimum and maximum sizes based on timing and sample rate. */ + minFramesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); + minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); + + maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); + maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer )); + + /* Determine number of user buffers based on minimum latency. */ + minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); + past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); - // For CoreAudio, we only have one Host buffer, so... - pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers; - // Calculate size of CoreAudio buffer. - pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers; + minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; + + /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ + if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) + { + userBuffersPerHostBuffer = + (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / + past->past_FramesPerUserBuffer; + } + else + { + userBuffersPerHostBuffer = 1; + } + + + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + + /* Make sure we have anough WAVE buffers. */ + if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) + { + numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; + } + else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) && + ((int) past->past_FramesPerUserBuffer < (maxFramesPerHostBuffer/2) ) ) + { + /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ + while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) + { + userBuffersPerHostBuffer += 1; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + /* If we have gone too far, back up one. */ + if( (framesPerHostBuffer > maxFramesPerHostBuffer) || + (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) ) + { + userBuffersPerHostBuffer -= 1; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; + break; + } + } + } + + pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; + pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; + pahsc->pahsc_NumHostBuffers = numHostBuffers; DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); } /*******************************************************************/ @@ -972,33 +865,21 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; - // If we are using both input and out, then they must be on the same CoreAudio device, - // until we implement a FIFO between two devices. - if( (past->past_OutputDeviceID != paNoDevice) && (past->past_InputDeviceID != paNoDevice) ) - { - AudioDeviceID inputID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; - AudioDeviceID outputID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; - if( inputID != outputID ) - { - ERR_RPT(("PortAudio: input and output must use same CoreAudio device!\n")); - return paInvalidDeviceId; - } - } + /* Figure out how user buffers fit into WAVE buffers. */ + // FIXME - just force for now - PaHost_CalcHostBufferSize( past ); + pahsc->pahsc_UserBuffersPerHostBuffer = 1; + pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer; + pahsc->pahsc_NumHostBuffers = 2; // FIXME - dunno?! { int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate); - PRINT(("PortAudio on OS X - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); + PRINT(("PortAudio on OSX - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); } - - /* Setup constants for CPU load measurement. */ - pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer); /* ------------------ OUTPUT */ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) { - pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; result = PaHost_OpenOutputStream( past ); if( result < 0 ) goto error; } @@ -1006,7 +887,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) /* ------------------ INPUT */ if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) ) { - pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; result = PaHost_OpenInputStream( past ); if( result < 0 ) goto error; } @@ -1021,83 +901,118 @@ error: /*************************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { - return 0; + PaHostSoundControl *pahsc; + PaError result = paNoError; + OSStatus err = noErr; + + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + if( past->past_OutputDeviceID != paNoDevice ) + { + // Associate an IO proc with the device and pass a pointer to the audio data context + err = AudioDeviceAddIOProc(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc, past); + if (err != noErr) goto error; + + // start playing sound through the device + err = AudioDeviceStart(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto error; + } + +error: + return result; } /*************************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *past ) { - return 0; + PaError result = paNoError; + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + + if( past->past_InputDeviceID != paNoDevice ) + { + // FIXME + } + return result; } /*************************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *past ) { - OSStatus err = noErr; PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; +#if PA_USE_TIMER_CALLBACK + int resolution; + int bufsPerTimerCallback; + int msecPerBuffer; +#endif /* PA_USE_TIMER_CALLBACK */ + past->past_StopSoon = 0; past->past_StopNow = 0; past->past_IsActive = 1; - - // Associate an IO proc with the device and pass a pointer to the audio data context - err = AudioDeviceAddIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc, past); - if (err != noErr) goto error; - - // start playing sound through the device - err = AudioDeviceStart(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); - if (err != noErr) goto error; - return result; + pahsc->pahsc_FramesPlayed = 0.0; + pahsc->pahsc_LastPosition = 0; #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result ); #endif - -error: - return paHostError; // FIXME - save host error + return result; } /*************************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { - OSStatus err = noErr; + int timeOut; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; - (void) abort; /* 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; + + timeOut = PaHost_CalcTimeOut( past ); past->past_IsActive = 0; -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); -#endif - - // FIXME - we should ask proc to stop instead of stopping abruptly - err = AudioDeviceStop(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); - if (err != noErr) goto Bail; - - err = AudioDeviceRemoveIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); - if (err != noErr) goto Bail; - return paNoError; - -Bail: - return paHostError; // FIXME - save err } /*************************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; + + // FIXME return paNoError; } /*************************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; + +#if PA_TRACE_START_STOP + AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); +#endif + + // FIXME if( pahsc->pahsc_OutputAudioDeviceID != ??? ) + { + OSStatus err = noErr; + + err = AudioDeviceStop(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto Bail; + + err = AudioDeviceRemoveIOProc(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc); + if (err != noErr) goto Bail; + } +Bail: return paNoError; } @@ -1113,6 +1028,9 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); #endif + /* Free data and device for output. */ + + /* Free data and device for input. */ free( pahsc ); past->past_DeviceData = NULL; @@ -1127,52 +1045,29 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) ** ** set PA_MIN_LATENCY_MSEC=200 ** -** in the cshrc file. +** 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. */ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") -#if 1 -int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond ) +int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { - int minBuffers; - int denominator; - int minLatencyMsec = PA_MIN_LATENCY_MSEC; - char *minLatencyText = getenv(PA_LATENCY_ENV_NAME); - if( minLatencyText != NULL ) + int minLatencyMsec = 0; + double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; + int minBuffers; + + /* Let user determine minimal latency by setting environment variable. */ { - PRINT(("PA_MIN_LATENCY_MSEC = %s\n", minLatencyText )); - minLatencyMsec = atoi( minLatencyText ); - if( minLatencyMsec < 1 ) minLatencyMsec = 1; - else if( minLatencyMsec > 5000 ) minLatencyMsec = 5000; + minLatencyMsec = PA_MIN_LATENCY_MSEC; } - denominator = 1000.0 * framesPerBuffer; - minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator ); - if( minBuffers < 1 ) minBuffers = 1; + DBUG(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); + minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); + if( minBuffers < 2 ) minBuffers = 2; + return minBuffers; } -#else -/************************************************************************* -** Determine minimum number of buffers required for this host based -** on minimum latency. -*/ -int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) -{ - int minUserBuffers; - int minFramesPerHostBuffer; - - // Calculate minimum and maximum sizes based on timing and sample rate. - minFramesPerHostBuffer = (int) (PA_MIN_LATENCY_MSEC * sampleRate / 1000.0); - // round up to nearest multiple of 8 - minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; - DBUG(("Pa_GetMinNumBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); - - minUserBuffers = (minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer; - if( minUserBuffers < 1 ) minUserBuffers = 1; - - return minUserBuffers; -} -#endif /************************************************************************* ** Cleanup device info. @@ -1181,32 +1076,41 @@ PaError PaHost_Term( void ) { int i; - if( sDeviceInfos != NULL ) + if( sNumDevices > 0 ) { - for( i=0; iname ); + free( (void*)sDevicePtrs[i]->sampleRates ); + free( sDevicePtrs[i] ); + } + } + + free( sDevicePtrs ); + sDevicePtrs = NULL; + } + + sNumDevices = 0; + } return paNoError; } /*************************************************************************/ 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 + /* struct timeval timeout; + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + select( 0, NULL, NULL, NULL, &timeout ); + */ usleep( msec * 1000 ); -#endif } /************************************************************************* @@ -1245,17 +1149,11 @@ PaError PaHost_StreamActive( internalPortAudioStream *past ) /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { - AudioTimeStamp timeStamp; - PaTimestamp streamTime; PaHostSoundControl *pahsc; internalPortAudioStream *past = (internalPortAudioStream *) stream; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; - - AudioDeviceGetCurrentTime(pahsc->pahsc_AudioDeviceID, &timeStamp); - - streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ? - timeStamp.mSampleTime : past->past_FrameCount; - return streamTime; + // FIXME PaHost_UpdateStreamTime( pahsc ); + return pahsc->pahsc_FramesPlayed; } diff --git a/pa_sgi/Makefile b/pa_sgi/Makefile index 34fcee6..c631c9b 100644 --- a/pa_sgi/Makefile +++ b/pa_sgi/Makefile @@ -1,6 +1,5 @@ -# Make PortAudio for Silicon Graphics IRIX 6.2 - 6.5. -# Pieter suurmond, july 4, 2002. (for PA v18.) -# Based on SGI-specific sproc()-method to spawn children, not on POSIX-threads. +# Make PortAudio for Silicon Graphics IRIX (6.2) +# Pieter suurmond, august 17, 2001. (v15 pa_sgi sub-version #0.04) # Instead of "-lpthread", as with linux, # just the audio- and math-library for SGI: @@ -15,36 +14,36 @@ CFLAGS = -O2 PASRC = ../pa_common/pa_lib.c pa_sgi.c PAINC = ../pa_common/portaudio.h -# Tests that work (on SGI Indy with R5000 @ 180MHz running IRIX 6.2): -#TESTC = $(PASRC) ../pa_tests/patest_record.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_many.c # v18 ok (with PA_MIN_LATENCY_MSEC=250). -#TESTC = $(PASRC) ../pa_tests/patest_latency.c # v18 ok (with PA_MIN_LATENCY_MSEC=250) patest_latency.c contained // -#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # v18 ok (with PA_MIN_LATENCY_MSEC=250). - -TESTC = $(PASRC) ../pa_tests/patest_saw.c # v18 ok (with PA_MIN_LATENCY_MSEC=250). -#TESTC = $(PASRC) ../pa_tests/patest_wire.c # v18 seems ok. - -#TESTC = $(PASRC) ../pa_tests/pa_devs.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_sine.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_pink.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_clip.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_stop.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_dither.c # TODO probably ok. -#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore with v15. - -# Tests that were not yet performed: -#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # test?? -#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # test?? -#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # test?? +# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). +#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK +TESTC = $(PASRC) ../pa_tests/patest_record.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches. +#TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?). +#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK +#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK +#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. +# Tests that do not yet work. +#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default +#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default +#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-( + # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH. + # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON??? + # HMMM I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS! TESTH = $(PAINC) all: patest -# "cc" for the MIPSpro compiler, may be changed to "gcc": +#(cc may be changed to gcc) patest: $(TESTC) $(TESTH) Makefile cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest diff --git a/pa_sgi/pa_sgi.c b/pa_sgi/pa_sgi.c index 0f56237..094cb4d 100644 --- a/pa_sgi/pa_sgi.c +++ b/pa_sgi/pa_sgi.c @@ -1,10 +1,10 @@ /* * $Id$ - * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk. + * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com + * SGI IRIX implementation by Pieter Suurmond, aug 17, 2001. * - * Silicon Graphics (SGI) IRIX implementation by Pieter Suurmond. - * This implementation uses sproc()-spawning, not the POSIX-threads. + * 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 @@ -28,101 +28,98 @@ * 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. - * -MODIFICATIONS: + */ +/* +Modfication History: 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. - 8/17/2001 - v15, first unstable alpha release for IRIX, sent to Phil & Ross. - 9/23/2001 - Many fixes and changes: POLLIN for input, not POLLOUT! - 7/04/2002 - Implemented multiple user buffers per host buffer to allow clients that - request smaller buffersizes. - - [v18-0.05] Try to use CVS via the Mac now to upload instead of e-mailing to Phil & Ross. - + 8/17/2001 - (v15 pa_sgi sub-version #0.04), wow, much is working now! Send this to Phil & Ross. + ID-stuff is nicer here now than in the linux_oss-alpha-version, v15. Was able to get + rid of a number of globals (like "sNumDevices" for instance). TODO: + - Test under IRIX 6.5. + - Maybe use pthread instead of (platform-specific) poll/select/pollfd-calls. + (As Gary Scavone more or less suggested(?)... But can I get enough process-control then?) - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), and maybe also the other natively supported formats? (might increase performance) - - Implement fancy callback block adapter as described in the PDF by Stephane Letz in the ASIO dir. - - Do some more tests... (see Makefile). - + - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet, + seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?) + - Make sure that the fuzz-test doesn't let all IRIX crash (especially with higher buff-sizes). + - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4. REFERENCES: - IRIX 6.2 man pages regarding SGI AL library. - - IRIS Digital Media Programming Guide (online books and man-pages come - with IRIX 6.2 and may not be publically available on the internet). + - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and + may not be publically available on the internet). */ #include /* Standard libraries. */ #include +#include +#include +#include -#include "../pa_common/portaudio.h" /* (Makefile fails to find in subdirs, -I doesn't work?). */ -#include "../pa_common/pa_host.h" -#include "../pa_common/pa_trace.h" +#include "portaudio.h" /* Portaudio headers. */ +#include "pa_host.h" +#include "pa_trace.h" -#include +#include /* System specific (IRIX 6.2). */ #include #include -#include /* For schedctl(NDPRI, NDPHIMIN). */ -#include /* fcntl.h needed. */ -#include /* For streams, ioctl(), etc. */ +#include +#include /* fcntl.h needed. */ +#include /* For streams, ioctl(), etc. */ +#include #include #include -#include /* System specific (IRIX 6.2-6.5). */ +#include +#include -/*----------------- MACROS --------------------*/ -#define PRINT(x) { printf x; fflush(stdout); } -#define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) */ -#define DBUGX(x) /* PRINT(x) */ +/*--------------------------------------------*/ +#define PRINT(x) { printf x; fflush(stdout); } +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) PRINT(x) +#define DBUGX(x) /* PRINT(x) */ -#define MAX_CHARS_DEVNAME (16) -#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7. */ - /* Constants used in 'Pa_GetMinNumBuffers()' below: */ -#define MIN_LATENCY_MSEC (200) /* Used if 'getenv("PA_MIN_LATENCY_MSEC")' fails. */ -#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") /* Same names as in file pa_unix.h. */ +#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */ +#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */ -/*------------------------------- IRIX AL specific device info: --------------------------------------*/ -typedef struct internalPortAudioDevice +typedef struct internalPortAudioDevice /* IRIX specific device info: */ { - PaDeviceID pad_DeviceID; /* THIS "ID" IS NEW HERE. */ - long pad_ALdevice; /* SGI-number! */ - double pad_SampleRates[MAX_SAMPLE_RATES]; /* For pointing to from pad_Info */ - char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ - PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ - struct internalPortAudioDevice* pad_Next; /* Singly linked list (NULL=end). */ -} internalPortAudioDevice; - -/*----------------- Structure containing all SGI IRIX specific data: ---------------------------------------*/ -typedef struct PaHostSoundControl -{ - ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */ - pahsc_ALconfigOUT; /* stucts separate for input and output ports. */ - ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ - pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ - int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ - - unsigned int pahsc_UserBuffersPerHostBuffer, - pahsc_SamplesPerInputHostBuffer, /* Channels per frame are accounted for. */ - pahsc_SamplesPerOutputHostBuffer, - pahsc_BytesPerInputHostBuffer, /* Size per sample are accounted for. */ - pahsc_BytesPerOutputHostBuffer; - short *pahsc_InputHostBuffer, /* Allocated here, in this file, if necessary. */ - *pahsc_OutputHostBuffer; - - struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ - pahsc_LastExitTime; - long pahsc_InsideCountSum, - pahsc_TotalCountSum; -} PaHostSoundControl; - -/*-------------------------------------------------------- Shared Data -------------------------------*/ -static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ -static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ -usema_t *SendSema, /* These variables are shared between the */ - *RcvSema; /* audio handling process and main process. */ -/*--------------------------*/ -long Pa_GetHostError(void) -{ - return (long)sPaHostError; + PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ + long pad_ALdevice; /* SGI-number! */ + double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ + char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ + PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ + /* int structVersion; */ + /* const char* name; */ + /* int maxInputChannels, maxOutputChannels; */ + /* int numSampleRates; Num rates, or -1 if range supprtd. */ + /* const double* sampleRates; Array of supported sample rates, */ + /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ + struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ } +internalPortAudioDevice; + +typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */ +{ + ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ + pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ + int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ + short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ + *pahsc_NativeOutputBuffer; + unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ + pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ + unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ + pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ + struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ + pahsc_LastExitTime; + long pahsc_InsideCountSum, + pahsc_TotalCountSum; +} +PaHostSoundControl; + +/*----------------------------- Shared Data ------------------------------------------------------*/ +static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ +static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ /*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ /* (copied from source pa_linux_oss/pa_linux_oss.c) */ @@ -131,7 +128,7 @@ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) struct itimerval itimer; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; -/* Query system timer for usage analysis and to prevent overuse of CPU. */ + /* Query system timer for usage analysis and to prevent overuse of CPU. */ getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); } @@ -156,19 +153,19 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) if (pahsc == NULL) return; if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) - { + { if (past->past_IfLastExitValid) - { + { insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); pahsc->pahsc_InsideCountSum += insideCount; totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); pahsc->pahsc_TotalCountSum += totalCount; - /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ + /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ /* Low pass filter the result because sometimes we get called several times in a row. */ /* That can cause the TotalCount to be very low which can cause the usage to appear */ /* unnaturally high. So we must filter numerator and denominator separately!!! */ if (pahsc->pahsc_InsideCountSum > 0) - { + { past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + @@ -176,10 +173,10 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; pahsc->pahsc_InsideCountSum = 0; pahsc->pahsc_TotalCountSum = 0; - } } - past->past_IfLastExitValid = 1; } + past->past_IfLastExitValid = 1; + } pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); @@ -192,56 +189,56 @@ PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL- { /* call to report via ERR_RPT(), yields a PaError-num. */ const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ - { - case AL_BAD_OUT_OF_MEM: - ERR_RPT(("%sout of memory.\n", a)); - return paInsufficientMemory; /* Known PaError. */ - case AL_BAD_CONFIG: - ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_CHANNELS: - ERR_RPT(("%schannels not 1,2 or 4.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_NO_PORTS: - ERR_RPT(("%sout of audio ports.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE: - ERR_RPT(("%swrong device number.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE_ACCESS: - ERR_RPT(("%swrong device access.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DIRECTION: - ERR_RPT(("%sinvalid direction.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_SAMPFMT: - ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_FLOATMAX: - ERR_RPT(("%smax float value is zero.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_WIDTH: - ERR_RPT(("%sunsupported samplewidth.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_QSIZE: - ERR_RPT(("%sinvalid queue size.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PVBUFFER: - ERR_RPT(("%sPVbuffer null.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_NEG: - ERR_RPT(("%snegative bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_ODD: - ERR_RPT(("%sodd bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PARAM: - ERR_RPT(("%sparameter not valid for device.\n", a)); - return paHostError; /* Generic PaError. */ - default: - ERR_RPT(("%sunknown error.\n", a)); - return paHostError; /* Generic PaError. */ - } + { + case AL_BAD_OUT_OF_MEM: + ERR_RPT(("%sout of memory.\n", a)); + return paInsufficientMemory; /* Known PaError. */ + case AL_BAD_CONFIG: + ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_CHANNELS: + ERR_RPT(("%schannels not 1,2 or 4.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_NO_PORTS: + ERR_RPT(("%sout of audio ports.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DEVICE: + ERR_RPT(("%swrong device number.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DEVICE_ACCESS: + ERR_RPT(("%swrong device access.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_DIRECTION: + ERR_RPT(("%sinvalid direction.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_SAMPFMT: + ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_FLOATMAX: + ERR_RPT(("%smax float value is zero.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_WIDTH: + ERR_RPT(("%sunsupported samplewidth.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_QSIZE: + ERR_RPT(("%sinvalid queue size.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_PVBUFFER: + ERR_RPT(("%sPVbuffer null.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_BUFFERLENGTH_NEG: + ERR_RPT(("%snegative bufferlength.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_BUFFERLENGTH_ODD: + ERR_RPT(("%sodd bufferlength.\n", a)); + return paHostError; /* Generic PaError. */ + case AL_BAD_PARAM: + ERR_RPT(("%sparameter not valid for device.\n", a)); + return paHostError; /* Generic PaError. */ + default: + ERR_RPT(("%sunknown error.\n", a)); + return paHostError; /* Generic PaError. */ + } } /*------------------------------------------------------------------------------------------*/ @@ -258,15 +255,15 @@ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT pad->pad_ALdevice = ALdev; /* Set the AL device number. */ pad->pad_DeviceID = id; /* Set the PA device number. */ if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ - { + { ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); return paHostError; - } + } strcpy(pad->pad_DeviceName, name); /* Write name-string. */ pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ /*--------------------------------- natively supported sample formats: -----------------*/ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ - /* Then also choose other CallConvertXX()! */ + /* Then also choose other CallConvertXX()! */ /*--------------------------------- number of available i/o channels: ------------------*/ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) return translateSGIerror(); @@ -276,8 +273,8 @@ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT return translateSGIerror(); pad->pad_Info.maxOutputChannels = max; DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) - /*--------------------------------- supported samplerates: ----------------------*/ - pad->pad_Info.numSampleRates = 7; + /*--------------------------------- supported samplerates: ----------------------*/ + pad->pad_Info.numSampleRates = 7; pad->pad_Info.sampleRates = pad->pad_SampleRates; pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ pad->pad_SampleRates[1] = (double)AL_RATE_11025; @@ -293,18 +290,18 @@ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ return translateSGIerror(); if (max != (long)(0.5 + pad->pad_SampleRates[6])) - { + { weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); return paHostError; /* Or make it a warning and just carry on... */ - } - /*-------------------------------------------------------------------------------*/ + } + /*-------------------------------------------------------------------------------*/ return paNoError; } /*--------------------------------------------------------------------------------*/ int Pa_CountDevices() /* Name of this function suggests it only counts and */ -{ /* is NOT destructive, it however resets whole PA ! */ +{ /* is NOT destructive, it however resets whole PA ! */ int numDevices = 0; /* Let 's not do that here. */ internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ #if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ @@ -312,13 +309,15 @@ int Pa_CountDevices() /* Name of this function suggests it only counts and Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ #endif /* friendly to clients that forgot to initialize PA. */ while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ - { + { numDevices++; currentDevice = currentDevice->pad_Next; - } + } return numDevices; } + + /*-------------------------------------------------------------------------------*/ static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) { @@ -326,21 +325,22 @@ static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ while (pad) /* pad may be NULL, that's ok, return 0. */ - { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ + { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ if (pad->pad_DeviceID == id) /* This the device we were looking for? */ res = pad; /* But keep on(!) counting so we don't */ numDevices++; /* have to call Pa_CountDevices() later. */ pad = pad->pad_Next; /* Advance to the next device or NULL. */ - } /* No assumptions about order of ID's in */ + } /* No assumptions about order of ID's in */ if (!res) /* the list. */ ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); if ((id < 0) || (id >= numDevices)) - { + { ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); #if 1 /* Be strict, even when found, */ res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ #endif - } + + } return res; } @@ -359,7 +359,7 @@ const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultInputDeviceID(void) { - return 0; /* 0 is the default device ID. */ + return 0; /* 0 is the default device ID. */ } /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultOutputDeviceID(void) @@ -367,26 +367,26 @@ PaDeviceID Pa_GetDefaultOutputDeviceID(void) return 0; } -/*-------------------------------------------------------------------------------------------------*/ -/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */ -PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ +/*--------------------------------------------------------------------------------------*/ +/* Build linked list with all available audio devices on this SGI machine. */ +PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ { internalPortAudioDevice* pad; PaError r = paNoError; - int audioLibFileID; /* To test for the presence of audio. */ + int audioLibFileID; - if (sDeviceList) /* Allow re-init, only warn, no error. */ - { + if (sDeviceList) /* Allow re-init, only warn, no err. */ + { ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); return r; - } - /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/ + } + /*------------- ADD THE SGI DEFAULT DEVICES TO THE LIST: --------------------------------------*/ audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ if (audioLibFileID < 0) /* IO port. On failure, machine */ - { /* has no audio ability. */ + { /* has no audio ability. */ ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); return paHostError; - } + } close(audioLibFileID); /* Allocate fast mem to hold device info. */ pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); if (pad == NULL) @@ -397,17 +397,21 @@ PaError PaHost_Init(void) /* Called by Pa_Initializ "AL default", /* A suitable name. */ pad); /* Write args and queried info into pad. */ if (r != paNoError) - { + { ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ - } + } else - sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ - /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ - /*---------------------------------------------------------------------------------------------*/ + sDeviceList = pad; /* First element in linked list (pad->pad_Next is already NULL). */ + /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LIST: --------------*/ + /*---------------------------------------------------------------------------------*/ return r; } +/*------------------------------------------------------------------*/ +usema_t *SendSema, /* These variables are shared between the audio */ +*RcvSema; /* handling process and the main process. */ + /*--------------------------------------------------------------------------------------------*/ #define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */ #define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */ @@ -415,169 +419,114 @@ PaError PaHost_Init(void) /* Called by Pa_Initializ #define kPollIN 2 void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */ { /* as a separate thread. (Argument must be void*). */ - short evtLoop; /* Reset by parent indirectly, or at local errors. */ + short evtLoop=1; /* Reset by parent indirectly, or at local errors. */ PaError result; struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */ - internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument. */ - PaHostSoundControl *pahsc; - short n, inputEvent, outputEvent, semaEvent; /* .revents are shorts. */ - short *inBuffer, *outBuffer; /* FIX: Only 16 bit for now, may change... */ - unsigned int samplesPerInputUserBuffer, samplesPerOutputUserBuffer; - - DBUG(("Entering sproc-thread.\n")); - if (!past) - { - sPaHostError = paInternalError; /* Or paBadStreamPtr ? */ - ERR_RPT(("argument NULL!\n")); - goto skip; - } - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (!pahsc) - { + internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument.*/ + PaHostSoundControl *pahsc = (PaHostSoundControl*)past->past_DeviceData; + if (pahsc == NULL) + { sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */ - ERR_RPT(("past_DeviceData NULL!\n")); - goto skip; /* Sproc-ed threads MAY NOT RETURN paInternalError. */ - } - /*----------------------------- open AL-ports here, after sproc(): -----------------------*/ - if (past->past_NumInputChannels > 0) /* Open input port. */ - { - pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN); - if (!pahsc->pahsc_ALportIN) - { - ERR_RPT(("Failed to open AL input port.\n")); - sPaHostError = paInternalError; - goto skip; - } - DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels)); - samplesPerInputUserBuffer = pahsc->pahsc_SamplesPerInputHostBuffer / - pahsc->pahsc_UserBuffersPerHostBuffer; - } - if (past->past_NumOutputChannels > 0) /* Open output port. */ - { - pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT); - if (!pahsc->pahsc_ALportOUT) - { - ERR_RPT(("Failed to open AL output port.\n")); - sPaHostError = paInternalError; /* Assume pahsc_ALconfigs are the */ - goto skip; /* same for IN and OUT in case */ - } /* both ports are opened (bidir). */ - DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels)); - samplesPerOutputUserBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer / - pahsc->pahsc_UserBuffersPerHostBuffer; - DBUG(("samplesPerOutputUserBuffer = %d\n", samplesPerOutputUserBuffer)); - } - /*-----------------------------------------------------------------------*/ + goto skipALL; /* Sproc-ed threads MAY NOT RETURN paInternalError. */ + } past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ + DBUG(("entering thread.\n")); PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */ - PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */ + PollFD[kPollIN].events = POLLOUT; /* such as ALport not there. */ + /* .events = POLLOUT ??? ok? */ PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT); PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */ schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */ PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */ PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */ - uspsema(SendSema); /* Blocks until ... MUST be here, this uspsema(). */ - evtLoop = ((past->past_StopNow | past->past_StopSoon) == 0); - while (evtLoop) - { + uspsema(SendSema); /* Blocks until the next (first)signal is received???? */ + do + { /*---------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ----------*/ - if (pahsc->pahsc_InputHostBuffer) /* Then pahsc_ALportIN should also be there! */ + if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */ /* For input port, fill point is number of locations in the sample queue that must be */ /* filled in order to trigger a return from select(). (or poll()) */ /* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/ - if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputHostBuffer)) - { /* Multiple amount as transferred per time. */ + if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputBuffer)) + { /* Same amount as transferred per time. */ ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n")); sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ - goto skip; - } - if (pahsc->pahsc_OutputHostBuffer) /* Then pahsc_ALportOUT should also be there! */ + goto skipIO; + } + if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */ /* For output port, fill point is number of locations that must be free in order to */ /* wake up from select(). (or poll()) */ - if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputHostBuffer)) - { + if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputBuffer)) + { ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n")); sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ - goto skip; - } /* poll() with timeout=-1 makes it block until a requested */ + goto skipIO; + } /* poll() with timeout=-1 makes it block until a requested */ poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */ - /* array <0, events is ignored and revents is set to 0. */ + /* array <0, events is ignored and revents is set to 0. */ /*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/ - semaEvent = PollFD[kPollSEMA].revents & POLLIN; - if (semaEvent) - { - if (past->past_StopSoon) + if (PollFD[kPollSEMA].revents & POLLIN) + { + if (past->past_StopNow || past->past_StopSoon) evtLoop = 0; + uspsema(SendSema); /* Decrements count of previously allocated semaphore SendSema. If count */ + /* is then negative, semaphore will logically block calling process until */ + /* count is incremented due to an usvsema call made by another process. */ + usvsema(RcvSema); /* Increments the count associated with RcvSema. If there are any */ + /* processes queued waiting for the semaphore the first one is awakened. */ + /* Here usvsema sends an acknowledgement to the "SendAudioCommand()". */ if (past->past_StopNow) - goto skip; - } - /*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/ - inputEvent = PollFD[kPollIN].revents & POLLIN; - if (inputEvent) /* Don't need to check (pahsc->pahsc_InputHostBuffer): */ - { /* if buffer was not there, ALport not there, no events! */ - if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_InputHostBuffer, - pahsc->pahsc_SamplesPerInputHostBuffer)) - { /* Here again: number of samples instead of number of frames. */ + goto skipIO; /* Else go on for a little while... */ + } + /*------------------------------------- FREE-EVENT FROM INPUT BUFFER: ----------------------------*/ + if (PollFD[kPollIN].revents & POLLOUT) /* Don't need to check (pahsc->pahsc_NativeInputBuffer): */ + { /* if buffer was not there, ALport not there, no events! */ + if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer, + pahsc->pahsc_SamplesPerInputBuffer)) + { /* Here again: number of samples instead of number of frames. */ ERR_RPT(("ALreadsamps() failed.\n")); sPaHostError = paInternalError; - goto skip; - } + goto skipIO; /* (Using exit(-1) would be a bit rude.) */ } - outputEvent = PollFD[kPollOUT].revents & POLLOUT; + } /*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/ - if (inputEvent | outputEvent) /* (Bitwise is ok.) */ - { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */ - /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */ + if ((PollFD[kPollIN].revents & POLLOUT) || (PollFD[kPollOUT].revents & POLLOUT)) + { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */ + /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */ Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ - /* user data and call user routine. */ - inBuffer = pahsc->pahsc_InputHostBuffer; /* Short pointers for now, care! */ - outBuffer = pahsc->pahsc_OutputHostBuffer; - n = pahsc->pahsc_UserBuffersPerHostBuffer; /* 'n' may never start at NULL ! */ - do { - result = Pa_CallConvertInt16(past, inBuffer, outBuffer); - if (result) /* This is apparently NOT an error! Just letting the userCallBack stop us. */ - { DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); goto skip; } - inBuffer += samplesPerInputUserBuffer; /* Num channels is accounted for. */ - outBuffer += samplesPerOutputUserBuffer; - } while (--n); + result = Pa_CallConvertInt16(past, /* user data and call user routine. */ + pahsc->pahsc_NativeInputBuffer, + pahsc->pahsc_NativeOutputBuffer); Pa_EndUsageCalculation(past); - } - /*------------------------------------- FREE-EVENT FROM OUTPUT BUFFER: ---------------------------*/ - if (outputEvent) /* Don't need to check (pahsc->pahsc_OutputHostBuffer) */ - { /* because if filedescriptor not there, no event for it. */ - if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_OutputHostBuffer, - pahsc->pahsc_SamplesPerOutputHostBuffer)) - { - ERR_RPT(("ALwritesamps() failed.\n")); /* Better use SEMAS for messaging back to parent! */ - sPaHostError = paInternalError; - goto skip; - } + if (result) + { + DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); + goto skipIO; /* But it is apparently NOT an error! */ + } /* Just letting the userCallBack stop us. */ + } + /*------------------------------------- FILLED-EVENT FROM OUTPUT BUFFER: -------------------------*/ + if (PollFD[kPollOUT].revents & POLLOUT) /* Don't need to check (pahsc->pahsc_NativeOutputBuffer) */ + { /* because if filedescriptor not there, no event for it. */ + if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer, + pahsc->pahsc_SamplesPerOutputBuffer)) + { + ERR_RPT(("ALwritesamps() failed.\n")); + sPaHostError = paInternalError; /* Better use SEMAS also for messaging back to parent! */ + goto skipIO; } } -skip: - /*------------------------------- close AL-ports ----------------------------*/ - if (pahsc->pahsc_ALportIN) - { - if (ALcloseport(pahsc->pahsc_ALportIN)) - translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ - else /* But go on anyway... to release other stuff... */ - pahsc->pahsc_ALportIN = (ALport)0; - } - if (pahsc->pahsc_ALportOUT) - { - if (ALcloseport(pahsc->pahsc_ALportOUT)) - translateSGIerror(); - else - pahsc->pahsc_ALportOUT = (ALport)0; - } + /*------------------------------------------------------------------------------------------------*/ + } + while (evtLoop); /* Set at init-time, only reset indirectly via semaphore, */ +skipIO: /* or in case of error, only within this loop. */ + DBUG(("leaving thread.\n")); /* Don't we need to cleanup semaphore-stuff / thread itself? */ +skipALL: /* (make threadPID in the struct -1 again, for instance?) */ past->past_IsActive = 0; - if (semaEvent) - { - uspsema(SendSema); /* StopEngine() was still waiting for this acknowledgement. */ - usvsema(RcvSema); /* (semaEvent initialized with 0.) */ - } - DBUG(("Leaving sproc-thread.\n")); -} - + pahsc->pahsc_threadPID == -1; /* Signal back, so StopEngine() for example won't call KILL().... hmmm doesn't work yet! */ + /* SHIT: when this process ends, it also KILLS of the parent!!! because sigint = kill?? */ + exit(0); /* Unix process. SIGCLD is sent to parent (if prctl wa called with 0 by parent). */ +} /* if prctl was called with 9 by parent, then when this process ends, it also */ +/* KILLS off the parent!!! */ /*--------------------------------------------------------------------------------------*/ PaError PaHost_OpenStream(internalPortAudioStream *past) @@ -586,167 +535,190 @@ PaError PaHost_OpenStream(internalPortAudioStream *past) PaHostSoundControl *pahsc; unsigned int minNumBuffers; internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ - long pvbuf[8], sr, alq; /* To get/set hardware configs. */ - + ALconfig sgiALconfig = NULL; /* IRIX-datatype. */ + long pvbuf[8]; /* To get/set hardware configs. */ + long sr, ALqsize; DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ if (!past) - { + { ERR_RPT(("Streampointer NULL!\n")); - result = paBadStreamPtr; goto done; - } + result = paBadStreamPtr; goto done; + } pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); if (pahsc == NULL) + { + ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ + result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ + } + memset(pahsc, 0, sizeof(PaHostSoundControl)); /* Hmmm, not too elegant, besides, the */ + pahsc->pahsc_threadPID = -1; /* pahsc_threadPID must be inited to */ + past->past_DeviceData = (void*)pahsc; /* -1 instead of 0! ?? */ + /*--------------------------------------------------- Allocate native buffers: --------*/ + pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumInputChannels; /* audio-thread. */ + pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); + if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */ + { + pahsc->pahsc_NativeInputBuffer = (short *) malloc(pahsc->pahsc_BytesPerInputBuffer); + if( pahsc->pahsc_NativeInputBuffer == NULL ) { - ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ - result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ + ERR_RPT(("(normal yet) Memory allocation failed.\n")); + result = paInsufficientMemory; + goto done; } - memset(pahsc, 0, sizeof(PaHostSoundControl)); - pahsc->pahsc_threadPID = -1; /* Should pahsc_threadPID be inited to */ - past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ + } + pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ + past->past_NumOutputChannels; /* audio-thread. */ + pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); + if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */ + { + pahsc->pahsc_NativeOutputBuffer = (short *) malloc(pahsc->pahsc_BytesPerOutputBuffer); + if (pahsc->pahsc_NativeOutputBuffer == NULL) + { + ERR_RPT(("(normal yet) Memory allocation failed.\n")); + result = paInsufficientMemory; goto done; + } + } /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ pvbuf[0] = AL_INPUT_RATE; pvbuf[2] = AL_INPUT_COUNT; pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ pvbuf[6] = AL_OUTPUT_COUNT; - sr = (long)(past->past_SampleRate + 0.5); /* Common for both input and output :-) */ - /*-----------------------------------------------------------------------------*/ - /* OVERWRITE 'past_NumUserBuffers'-field in the struct supplied by the caller. */ - /* This field may be set to zero by a client application to ask for minimum */ - /* latency. It is used below, to set both input- and output-AL-queuesizes. */ - minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, - past->past_SampleRate); /* Take biggest. */ - past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ? - minNumBuffers : past->past_NumUserBuffers; - DBUG(("past->past_NumUserBuffers=%d\n", past->past_NumUserBuffers)); - /*----------------------------------------------------------------------------------*/ - pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers >> 1; - DBUG(("pahsc_UserBuffersPerHostBuffer=%d\n",pahsc->pahsc_UserBuffersPerHostBuffer)); - /* 1 is minimum because Pa_GetMinNumBuffers() returns >= 2. - Callback will be called 'pahsc_UserBuffersPerHostBuffer' times (with 'past_FramesPerUserBuffer') - per host transfer. */ - /*---------------------------------------------------- SET INPUT CONFIGURATION: ---------------------*/ - if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ - { /* sponding native AL-number(s). */ - /*--------------------------------------------------- Allocate native buffers: --------------*/ - pahsc->pahsc_SamplesPerInputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * - past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumInputChannels; /* audio-thread. */ - DBUG(("pahsc_SamplesPerInputHostBuffer=%d\n", pahsc->pahsc_SamplesPerInputHostBuffer)); - pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_SamplesPerInputHostBuffer * sizeof(short); - pahsc->pahsc_InputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer); - if (!pahsc->pahsc_InputHostBuffer) - { - ERR_RPT(("Fast memory allocation failed (in).\n")); - result = paInsufficientMemory; - goto done; - } + sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */ + if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ + { /* sponding native AL-number(s). */ padIN = Pa_GetInternalDevice(past->past_InputDeviceID); if (!padIN) - { + { ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); - result = paHostError; - goto done; - } + result = paHostError; goto done; + } if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ goto sgiError; /* the same AL-device, the AL-library might */ if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ - { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ + { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ - { + { ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ -another process is currently using input at %ld Hz.\n", sr, pvbuf[1])); - result = paHostError; - goto done; - } + another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); + result = paHostError; goto done; + } pvbuf[1] = sr; /* Then set input-rate. */ if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) - goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ - } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */ - pahsc->pahsc_ALconfigIN = ALnewconfig(); /* Released at PaHost_CloseStream(). */ - if (pahsc->pahsc_ALconfigIN == (ALconfig)0) - goto sgiError; - if (ALsetsampfmt(pahsc->pahsc_ALconfigIN, AL_SAMPFMT_TWOSCOMP))/* Choose paInt16 as native i/o-format. */ - goto sgiError; - if (ALsetwidth (pahsc->pahsc_ALconfigIN, AL_SAMPLE_16)) /* Only meaningful when sample format for */ - goto sgiError; /* config is set to two's complement format. */ - /************************ Future versions might (dynamically) switch to 32-bit floats? ******* - if (ALsetsampfmt(pahsc_ALconfigIN, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) - goto sgiError; - if (ALsetfloatmax (pahsc_ALconfigIN, 1.0)) Only meaningful when sample format for config - goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ - /*--------- Set internal AL queuesize (in samples, not in frames!) -------------------------------*/ - alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumInputChannels; - DBUG(("AL input queuesize = %ld samples.\n", alq)); - if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, alq)) - goto sgiError; - if (ALsetchannels (pahsc->pahsc_ALconfigIN, (long)(past->past_NumInputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ + goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ } - /*---------------------------------------------------- SET OUTPUT CONFIGURATION: ------------------------*/ - if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ - { /* We use padOUT/IN later on, or at least 1 of both. */ - pahsc->pahsc_SamplesPerOutputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * - past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumOutputChannels; /* audio-thread. */ - DBUG(("pahsc_SamplesPerOutputHostBuffer=%d\n", pahsc->pahsc_SamplesPerOutputHostBuffer)); - pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer * sizeof(short); - pahsc->pahsc_OutputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer); - if (!pahsc->pahsc_OutputHostBuffer) - { - ERR_RPT(("Fast memory allocation failed (out).\n")); - result = paInsufficientMemory; - goto done; - } + } + if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels<=0! */ + { /* We use padOUT/IN later on, or at least 1 of both. */ padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); if (!padOUT) - { + { ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); - result = paHostError; - goto done; - } + result = paHostError; goto done; + } if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) goto sgiError; - if (pvbuf[5] != sr) - { /* Output needed and rate different from current harware-rate. */ + if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr)) + { /* Output needed and rate different from current harware-rate. */ if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ - { + { ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ -another process is currently using output at %ld Hz.\n", sr, pvbuf[5])); - result = paHostError; - goto done; /* Will free again the inputbuffer */ - } /* that was just created above. */ + another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); + result = paHostError; goto done; /* Will free again the inputbuffer */ + } /* that was just created above. */ pvbuf[5] = sr; /* Then set output-rate. */ if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) goto sgiError; - } - pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */ - if (pahsc->pahsc_ALconfigOUT == (ALconfig)0) - goto sgiError; - if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ - goto sgiError; - if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */ - goto sgiError; /* config is set to two's complement format. */ - /** Future versions might (dynamically) switch to 32-bit floats. **/ - alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumOutputChannels; - DBUG(("AL output queuesize = %ld samples.\n", alq)); - if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, alq)) - goto sgiError; - if (ALsetchannels (pahsc->pahsc_ALconfigOUT, (long)(past->past_NumOutputChannels))) - goto sgiError; } - /*----------------------------------------------- TEST DEVICE ID's: --------------------*/ - if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */ - (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) - { - ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); - result = paHostError; - goto done; + } + /*------------------------------------------ Construct an audio-port-configuration ----------*/ + sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */ + if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */ + goto sgiError; /* See that sgiALconfig is NOT released! */ + if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ + goto sgiError; + if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */ + goto sgiError; /* config is set to two's complement format. */ + /************************ Future versions might (dynamically) switch to 32-bit floats? ******* + if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) + goto sgiError; + if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config + goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ + /*---------- ?? --------------------*/ + /* 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; + /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/ + if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer) + ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer; + else /* Take the largest of the two amounts. */ + ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer; + ALqsize *= 4; /* 4 times as large as amount per transfer! */ + if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */ + goto sgiError; /* Using 2 times may give glitches... */ + /* Have to work on ALsetqueuesize() above, fillpoints in the thread are ok now. */ + + /* Do ALsetchannels() later, apart per input and/or output. */ + /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/ + if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */ + { + if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) + { + DBUG(("PaHost_OpenStream: opening both input and output channels.\n")); + /*------------------------- open output port: ----------------------------------*/ + if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); + if (pahsc->pahsc_ALportOUT == (ALport)0) + goto sgiError; + /*------------------------- open input port: -----------------------------------*/ + if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); + if (pahsc->pahsc_ALportIN == (ALport)0) + goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */ + } /* Probably due to too small buffersizes?.... */ + else + { + ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); + result = paHostError; + goto done; } + } + else /* (OutputDeviceID != InputDeviceID) */ + { + if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */ + { + /*------------------------- open output port: ----------------------------------*/ + DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n", + past->past_NumOutputChannels, padOUT->pad_DeviceName)); + if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); + if (pahsc->pahsc_ALportOUT == (ALport)0) + goto sgiError; + } + if (past->past_NumInputChannels > 0) /* READ-ONLY: */ + { + /*------------------------- open input port: -----------------------------------*/ + DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n", + past->past_NumInputChannels, padIN->pad_DeviceName)); + if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) + goto sgiError; /* Returns 0 on success, -1 on failure. */ + pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); + if (pahsc->pahsc_ALportIN == (ALport)0) + goto sgiError; + } + } + DBUG(("PaHost_OpenStream() succeeded.\n")); goto done; /* (no errors occured) */ -sgiError: +sgiError: result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ done: + if (sgiALconfig) + ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */ if (result != paNoError) PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ return result; @@ -768,54 +740,56 @@ PaError PaHost_StartEngine(internalPortAudioStream *past) PaHostSoundControl *pahsc; usptr_t *arena; if (!past) /* Test argument. */ - { + { ERR_RPT(("PaHost_StartEngine(NULL)!\n")); return paBadStreamPtr; - } + } pahsc = (PaHostSoundControl*)past->past_DeviceData; if (!pahsc) - { + { ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n")); return paHostError; - } + } past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */ past->past_IsActive = 1; - + /* Although the pthread_create() function, as well as , may be */ /* available in IRIX, use sproc() on SGI to create audio-background-thread. */ /* (Linux/oss uses pthread_create() instead of __clone() because: */ /* - pthread_create also works for other UNIX systems like Solaris, */ /* - Java HotSpot VM crashes in pthread_setcanceltype() using __clone().) */ - + usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* (From SGI-AL-examples, file */ arena = usinit(tmpnam(0)); /* motifexample.c, function */ SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */ - RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process - will be permitted through a semaphore at a time. Values > 1 - imply that up to val resources may be simultaneously used, but requests - for more than val resources cause the calling process to block until a - resource comes free (by a process holding a resource performing a - usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */ - prctl(PR_SETEXITSIG, 0); /* No not (void*)9, but 0, which doesn't kill the parent! */ - /* PR_SETEXITSIG controls whether all members of a share group will be - signaled if any one of them leaves the share group (either via exit() - or exec()). If 2nd arg, interpreted as an int is 0, then normal IRIX - process termination rules apply, namely that the parent is sent a - SIGCLD upon death of child, but no indication of death of parent is - given. If the second argument is a valid signal number then if any - member of a share group leaves the share group, a signal is - sent to ALL surviving members of the share group. */ + RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process + will be permitted through a semaphore at a time. Values > 1 + imply that up to val resources may be simultaneously used, but requests + for more than val resources cause the calling process to block until a + resource comes free (by a process holding a resource performing a + usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */ + prctl(PR_SETEXITSIG, 0);/* No not (void*)9, but 0, which doesn't kill the parent! */ + /* PR_SETEXITSIG controls whether all members of a share group will be + signaled if any one of them leaves the share group + (either via exit() or exec()). If second + argument, interpreted as an int is 0, then normal IRIX + process termination rules apply, namely that the parent + is sent a SIGCLD upon death of child, but no indication + of death of parent is given. If the second argument is + a valid signal number then if any member + of a share group leaves the share group, a signal is + sent to ALL surviving members of the share group. */ /* SPAWN AUDIO-CHILD: */ pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */ PR_SALL, /* new process, or -1. */ - (void*)past); /* Pass past as optional */ /* IS THIS SAFE, will past never */ - if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ /* be moved around in memory???? */ - { + (void*)past); /* Pass past as optional */ + if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ + { ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); sPaHostError = oserror(); /* Pass native error-number to shared area. */ return paHostError; /* But return the generic error-number. */ - } + } return paNoError; /* Hmmm, errno may come from other threads in same group! */ } /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */ @@ -825,45 +799,34 @@ PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) int hres; long timeOut; PaError result = paNoError; - PaHostSoundControl *pahsc; - - DBUG(("PaHost_StopEngine() called.\n")); - if (!past) - return paBadStreamPtr; - pahsc = (PaHostSoundControl*)past->past_DeviceData; - /* Prevent from doing this twice!! */ - if ((!pahsc) || /* Some tests call this CLOSE twice!! */ - (!past->past_IsActive) || - past->past_StopSoon || past->past_StopNow) - return result; /* paNoError (already stopped, no err?). */ + PaHostSoundControl *pahsc = (PaHostSoundControl*)past->past_DeviceData; + + if (pahsc == NULL) + return result; /* paNoError */ past->past_StopSoon = 1; /* Tell background thread to stop generating */ if (abort) /* more and to let current data play out. If */ past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ - /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/ - usvsema(SendSema); /* Increments count associated with SendSema. */ - /* Wait for the response. */ - uspsema(RcvSema); /* Decrements count of previously allocated */ - /* semaphore specified by RcvSema. */ - while (past->past_IsActive) /* REALLY WAIT. */ - { - /* DBUG(("wait 1 ms for audio-thread to stop.\n")); */ - Pa_Sleep(1); - } -#if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */ + /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/ + usvsema(SendSema); /* Increments count associated with SendSema. */ + /* Wait for the response. */ + uspsema(RcvSema); /* Decrements count of previously allocated */ + /* semaphore specified by RcvSema. */ + /* Must be sure sub-process is really there,... otherwise above semas block?! */ if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */ - { - DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n")); + { + /* How to JOIN a "sproc"-thread to recover memory resources????? */ + /* hres = pthread_join( pahsc->pahsc_ThreadPID, NULL ); */ + DBUG(("PaHost_StopEngine() is about to KILL(SIGKILL) audio-thread.\n")); if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */ - { /* Returns -1 in case of error. */ + { /* Returns -1 in case of error. */ result = paHostError; sPaHostError = oserror(); /* Hmmm, other threads may also write here! */ ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n")); - } + } else pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */ - } -#endif + } past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */ return result; } @@ -883,106 +846,76 @@ PaError PaHost_CloseStream(internalPortAudioStream *past) { PaHostSoundControl *pahsc; PaError result = paNoError; - - DBUG(("PaHost_CloseStream() called.\n")); - if (!past) + + if (past == NULL) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ - return result; /* This test prevents from freeing NULL-pointers. */ + if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ + return result; /* This test prevents from freeing NULL-pointers. */ - if (pahsc->pahsc_ALconfigIN) - { /* Release configuration structs, only if allocated. */ - ALfreeconfig(pahsc->pahsc_ALconfigIN); - pahsc->pahsc_ALconfigIN = NULL; - } - if (pahsc->pahsc_ALconfigOUT) - { - ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */ - pahsc->pahsc_ALconfigOUT = NULL; - } - if (pahsc->pahsc_InputHostBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_InputHostBuffer, pahsc->pahsc_BytesPerInputHostBuffer); - pahsc->pahsc_InputHostBuffer = NULL; - } - if (pahsc->pahsc_OutputHostBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_OutputHostBuffer, pahsc->pahsc_BytesPerOutputHostBuffer); - pahsc->pahsc_OutputHostBuffer = NULL; - } - PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); - past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */ + if (pahsc->pahsc_ALportIN) + { + if (ALcloseport(pahsc->pahsc_ALportIN)) + result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ + else /* But go on anyway... to release other stuff... */ + pahsc->pahsc_ALportIN = (ALport)0; + } + if (pahsc->pahsc_ALportOUT) + { + if (ALcloseport(pahsc->pahsc_ALportOUT)) + result = translateSGIerror(); + else + pahsc->pahsc_ALportOUT = (ALport)0; + } + if (pahsc->pahsc_NativeInputBuffer) + { + free(pahsc->pahsc_NativeInputBuffer); + pahsc->pahsc_NativeInputBuffer = NULL; + } + if (pahsc->pahsc_NativeOutputBuffer) + { + free(pahsc->pahsc_NativeOutputBuffer); + pahsc->pahsc_NativeOutputBuffer = NULL; + } + PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); /* Not just free(pahsc) because */ + past->past_DeviceData = NULL; /* PaHost_OpenStream(); allocated FAST (thus mpinned?) MEM. */ 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 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. +*/ +#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") -/*------------------------------------------------------------------------*/ -/* Determine minimum number of buffers required for (SGI) host based on */ -/* minimum latency. Latency can be optionally set by user by setting an */ -/* environment variable. For example, to set my latency to 200 msec, I've */ -/* put this line in my '.cshrc' file: setenv PA_MIN_LATENCY_MSEC 200 */ -/* It always calls the 'PRINT' macro. */ -/* The minimum number that is returned is 2. */ -/* This number is directly proportional to the AL-queue sizes to set up. */ -/* It is one more than the number of user buffers per host buffer - in */ -/* case minimum is returned, or, twice the user buffers per host buffer. */ -/*------------------------------------------------------------------------*/ -int Pa_GetMinNumBuffers(int framesPerUserBuffer, double framesPerSecond) +int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { - int minBuffers, minLatencyMsec; - char *minLatencyText; - double actualLatency; - - minLatencyText = getenv(PA_LATENCY_ENV_NAME); /* Defined at top of file. */ - if (minLatencyText) - { - minLatencyMsec = atoi(minLatencyText); - if (minLatencyMsec < 10) - { /* 10 is the minimum. */ - minLatencyMsec = 10; - PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' below minimum of %d milliseconds.\n", - minLatencyMsec)); - } - else if (minLatencyMsec > 4000) - { /* 4000 is the maximum. */ - minLatencyMsec = 4000; - PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' above maximum of %d milliseconds.\n", - minLatencyMsec)); - } - else - PRINT (("Using environment variable 'PA_MIN_LATENCY_MSEC' (set to %d milliseconds).\n", - minLatencyMsec)); - } - else - { - minLatencyMsec = MIN_LATENCY_MSEC; /* Defined at top of this file. */ - PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' not found.\nUsing default of %d milliseconds\n", - minLatencyMsec)); - } - minBuffers = (int)((minLatencyMsec * framesPerSecond) / - (1000.0 * framesPerUserBuffer)); - if (minBuffers < 2) - minBuffers = 2; - actualLatency = 1000.0 * minBuffers * framesPerUserBuffer / framesPerSecond; - PRINT (("Actual AL latency set to %.2f milliseconds\n", actualLatency)); - return minBuffers; + return 2; } +/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */ +/* Do we HAVE to do it this way under IRIX???.... */ +/*--------------------------------------------------------------*/ + /*---------------------------------------------------------------------*/ -PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ +PaError PaHost_Term(void) /* Frees all of the linked devices. */ { /* Called by Pa_Terminate() from pa_lib.c. */ internalPortAudioDevice *pad = sDeviceList, - *nxt; + *nxt; while (pad) - { + { DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); nxt = pad->pad_Next; PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ - } + } sDeviceList = (internalPortAudioDevice*)NULL; - return 0; /* Got rid of sNumDevices=0; */ + return 0; /* Got rid of sNumDevices=0; */ } /***********************************************************************/ @@ -1007,17 +940,17 @@ void *PaHost_AllocateFastMemory(long numBytes) { void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */ if (addr) /* range and locks the pages into memory. A counter */ - { /* is incremented each time the page is locked. The */ + { /* is incremented each time the page is locked. The */ if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */ - { /* others are limited to the configurable PLOCK_MA. */ + { /* others are limited to the configurable PLOCK_MA. */ ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n")); #if 1 free(addr); /* You MAY cut out these 2 lines to be less strict, */ addr = NULL; /* you then only get the warning but PA goes on... */ #endif /* Only problem then may be corresponding munpin() */ - } /* call at PaHost_FreeFastMemory(), below. */ + } /* call at PaHost_FreeFastMemory(), below. */ memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */ - } /* a child process after a fork. Furthermore, IRIX- */ + } /* a child process after a fork. Furthermore, IRIX- */ return addr; /* man-pages warn against mixing both mpin and mlock */ } /* in 1 piece of code, so stick to mpin()/munpin() ! */ @@ -1028,11 +961,11 @@ void *PaHost_AllocateFastMemory(long numBytes) void PaHost_FreeFastMemory(void *addr, long numBytes) { if (addr) - { + { if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */ ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n")); free(addr); /* But go on, try to release it, just warn... */ - } + } } /*----------------------------------------------------------*/ @@ -1050,9 +983,9 @@ PaError PaHost_StreamActive( internalPortAudioStream *past ) /*-------------------------------------------------------------------*/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { - internalPortAudioStream *past = (internalPortAudioStream *) stream; -/* FIXME - return actual frames played, not frames generated. -** Need to query the output device somehow. -*/ + internalPortAudioStream *past = (internalPortAudioStream *) stream; + /* FIXME - return actual frames played, not frames generated. + ** Need to query the output device somehow. + */ return past->past_FrameCount; } diff --git a/pa_sgi/pthread-Makefile b/pa_sgi/pthread-Makefile deleted file mode 100644 index 527677a..0000000 --- a/pa_sgi/pthread-Makefile +++ /dev/null @@ -1,52 +0,0 @@ -# Make PortAudio for Silicon Graphics IRIX (6.2) -# Pieter suurmond, september 22, 2001. (v15 pa_sgi sub-version #0.18) - -# pthread, math (as with linux) and SGI audio library: -# SGI-books say -lpthread should be the last on the line. -LIBS = -lm -laudio -lpthread - -CDEFINES = -I../pa_common - -# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64, -# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging. -# And use for example -O2 or -O3 for better optimization: -CFLAGS = -O2 -PASRC = ../pa_common/pa_lib.c pa_sgi.c -PAINC = ../pa_common/portaudio.h - -# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). -#TESTC = $(PASRC) ../pa_tests/patest_record.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches. -TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?). -#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK -#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. - -# Tests that do not yet work. -#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default -#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default -#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS FUZZ CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-( - # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH. - # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON??? - # ANYWAY, I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS! -TESTH = $(PAINC) - -all: patest - -# "cc" for the MIPSpro compiler, may be changed to "gcc": -patest: $(TESTC) $(TESTH) Makefile - cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest - -run: patest - ./patest - diff --git a/pa_sgi/pthread-pa_sgi.c b/pa_sgi/pthread-pa_sgi.c deleted file mode 100644 index e9ab273..0000000 --- a/pa_sgi/pthread-pa_sgi.c +++ /dev/null @@ -1,908 +0,0 @@ -/* - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * SGI IRIX implementation by Pieter Suurmond, september 22, 2001 (#0.18). - * - * Copyright (c) 1999-2001 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. - */ -/* -Modfication History: - 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. - 8/17/2001 - alpha release with IRIX sproc()-method, may sometimes let IRIX6.2 crash at closing audiostream. - 9/22/2001 - #0.18 pthread starts to work a bit: - BUT UNDER IRIX6.2, I DON'T GET IT TO WORK REALLY CORRECTLY, - this POSIX-attempt, - DON'T USE THIS FILE FOR RELIABLE OPERATION, IT IS HERE JUST - FOR DOCUMENTATION/ARCHIVE... OR FOR ANYONE WHO WANTS TO FIX...... -TODO: - - Test under IRIX 6.5. - - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), - and maybe also the other natively supported formats? (might increase performance) - - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet, - seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?) - - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4. -REFERENCES: - - IRIX 6.2 man pages regarding SGI AL library. - - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and - may not be publically available on the internet). -*/ - -#include /* Standard libraries. */ -#include - -#include "../pa_common/portaudio.h" /* Portaudio headers. */ -#include "../pa_common/pa_host.h" -#include "../pa_common/pa_trace.h" - -/* -#include -#include -#include Not needed -#include -#include -#include -#include Needed? -#include -#include sched_param struct and related functions - used in setting thread priorities. -#include Some POSIX constants such as _POSIX_THREAD_THREADS_MAX -*/ - -#include /* Pthreads are supported by IRIX 6.2 after */ - /* patches 1361, 1367, and 1429 are applied. */ - -#include /* fcntl.h needed for "O_RDONLY". */ -#include /* For usleep() and constants used when calling sysconf() */ - /* to query POSIX limits (see the sysconf(3) ref. page. */ - -#include /* SGI-specific audio library. */ - - -/*--------------------------------------------*/ -#define PRINT(x) { printf x; fflush(stdout); } -#define ERR_RPT(x) PRINT(x) -#define DBUG(x) PRINT(x) -#define DBUGX(x) /* PRINT(x) */ - -#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */ -#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */ - -typedef struct internalPortAudioDevice /* IRIX specific device info: */ -{ - PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ - long pad_ALdevice; /* SGI-number! */ - double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ - char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ - PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ - /* int structVersion; */ - /* const char* name; */ - /* int maxInputChannels, maxOutputChannels; */ - /* int numSampleRates; Num rates, or -1 if range supprtd. */ - /* const double* sampleRates; Array of supported sample rates, */ - /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ - struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ -} internalPortAudioDevice; - -typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */ -{ - ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ - pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ - pthread_t pahsc_ThreadPID; - short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ - *pahsc_NativeOutputBuffer; - unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ - pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ - unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ - pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ - struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ - pahsc_LastExitTime; - long pahsc_InsideCountSum, - pahsc_TotalCountSum; -} PaHostSoundControl; - -/*----------------------------- Shared Data ------------------------------------------------------*/ -static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ -static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ - -long Pa_GetHostError(void) -{ - return (long)sPaHostError; -} - -/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ -/* (copied from source pa_linux_oss/pa_linux_oss.c) */ -static void Pa_StartUsageCalculation( internalPortAudioStream *past ) -{ - struct itimerval itimer; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; -/* Query system timer for usage analysis and to prevent overuse of CPU. */ - getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); -} - -static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) -{ - long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; - long usecs = secs * 1000000; - usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); - return usecs; -} - -static void Pa_EndUsageCalculation( internalPortAudioStream *past ) -{ - struct itimerval currentTime; - long insideCount; - long totalCount; /* Measure CPU utilization during this callback. */ - -#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 (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) - { - if (past->past_IfLastExitValid) - { - insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); - pahsc->pahsc_InsideCountSum += insideCount; - totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); - pahsc->pahsc_TotalCountSum += totalCount; - /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ - /* Low pass filter the result because sometimes we get called several times in a row. */ - /* That can cause the TotalCount to be very low which can cause the usage to appear */ - /* unnaturally high. So we must filter numerator and denominator separately!!! */ - if (pahsc->pahsc_InsideCountSum > 0) - { - past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); - past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); - past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; - pahsc->pahsc_InsideCountSum = 0; - pahsc->pahsc_TotalCountSum = 0; - } - } - past->past_IfLastExitValid = 1; - } - pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; - pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; - setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); - past->past_IfLastExitValid = 1; -} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ - - -/*--------------------------------------------------------------------------------------*/ -PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */ -{ /* call to report via ERR_RPT(), yields a PaError-num. */ - const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ - switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ - { - case AL_BAD_OUT_OF_MEM: - ERR_RPT(("%sout of memory.\n", a)); - return paInsufficientMemory; /* Known PaError. */ - case AL_BAD_CONFIG: - ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_CHANNELS: - ERR_RPT(("%schannels not 1,2 or 4.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_NO_PORTS: - ERR_RPT(("%sout of audio ports.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE: - ERR_RPT(("%swrong device number.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE_ACCESS: - ERR_RPT(("%swrong device access.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DIRECTION: - ERR_RPT(("%sinvalid direction.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_SAMPFMT: - ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_FLOATMAX: - ERR_RPT(("%smax float value is zero.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_WIDTH: - ERR_RPT(("%sunsupported samplewidth.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_QSIZE: - ERR_RPT(("%sinvalid queue size.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PVBUFFER: - ERR_RPT(("%sPVbuffer null.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_NEG: - ERR_RPT(("%snegative bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_ODD: - ERR_RPT(("%sodd bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PARAM: - ERR_RPT(("%sparameter not valid for device.\n", a)); - return paHostError; /* Generic PaError. */ - default: - ERR_RPT(("%sunknown error.\n", a)); - return paHostError; /* Generic PaError. */ - } -} - -/*------------------------------------------------------------------------------------------*/ -/* Tries to set various rates and formats and fill in the device info structure. */ -static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */ - PaDeviceID id, /* (DefaultI|ODeviceID()) */ - char* name, /* (for example "SGI AL") */ - internalPortAudioDevice* pad) /* Result written to pad. */ -{ - int format; - long min, max; /* To catch hardware characteristics. */ - ALseterrorhandler(0); /* 0 = turn off the default error handler. */ - /*--------------------------------------------------------------------------------------*/ - pad->pad_ALdevice = ALdev; /* Set the AL device number. */ - pad->pad_DeviceID = id; /* Set the PA device number. */ - if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ - { - ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); - return paHostError; - } - strcpy(pad->pad_DeviceName, name); /* Write name-string. */ - pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ - /*--------------------------------- natively supported sample formats: -----------------*/ - pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ - /* Then also choose other CallConvertXX()! */ - /*--------------------------------- number of available i/o channels: ------------------*/ - if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) - return translateSGIerror(); - pad->pad_Info.maxInputChannels = max; - DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) - if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) - return translateSGIerror(); - pad->pad_Info.maxOutputChannels = max; - DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) - /*--------------------------------- supported samplerates: ----------------------*/ - pad->pad_Info.numSampleRates = 7; - pad->pad_Info.sampleRates = pad->pad_SampleRates; - pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ - pad->pad_SampleRates[1] = (double)AL_RATE_11025; - pad->pad_SampleRates[2] = (double)AL_RATE_16000; - pad->pad_SampleRates[3] = (double)AL_RATE_22050; - pad->pad_SampleRates[4] = (double)AL_RATE_32000; - pad->pad_SampleRates[5] = (double)AL_RATE_44100; - pad->pad_SampleRates[6] = (double)AL_RATE_48000; - if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */ - return translateSGIerror(); /* double -> long. */ - if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */ - goto weird; - if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ - return translateSGIerror(); - if (max != (long)(0.5 + pad->pad_SampleRates[6])) - { -weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); - return paHostError; /* Or make it a warning and just carry on... */ - } - /*-------------------------------------------------------------------------------*/ - return paNoError; -} - - -/*--------------------------------------------------------------------------------*/ -int Pa_CountDevices() /* Name of this function suggests it only counts and */ -{ /* is NOT destructive, it however resets whole PA ! */ - int numDevices = 0; /* Let 's not do that here. */ - internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ -#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ - if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */ - Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ -#endif /* friendly to clients that forgot to initialize PA. */ - while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ - { - numDevices++; - currentDevice = currentDevice->pad_Next; - } - return numDevices; -} - -/*-------------------------------------------------------------------------------*/ -static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) -{ - int numDevices = 0; - internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; - internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ - while (pad) /* pad may be NULL, that's ok, return 0. */ - { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ - if (pad->pad_DeviceID == id) /* This the device we were looking for? */ - res = pad; /* But keep on(!) counting so we don't */ - numDevices++; /* have to call Pa_CountDevices() later. */ - pad = pad->pad_Next; /* Advance to the next device or NULL. */ - } /* No assumptions about order of ID's in */ - if (!res) /* the list. */ - ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); - if ((id < 0) || (id >= numDevices)) - { - ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); -#if 1 /* Be strict, even when found, */ - res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ -#endif - } - return res; -} - -/*----------------------------------------------------------------------*/ -const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) -{ - PaDeviceInfo* res = (PaDeviceInfo*)NULL; - internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ - if (pad) - res = &pad->pad_Info; /* Not finding the specified ID is not */ - if (!res) /* the same as &pad->pad_Info == NULL. */ - ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); - return res; /* So (maybe) a second/third ERR_RPT(). */ -} - -/*------------------------------------------------*/ -PaDeviceID Pa_GetDefaultInputDeviceID(void) -{ - return 0; /* 0 is the default device ID. */ -} -/*------------------------------------------------*/ -PaDeviceID Pa_GetDefaultOutputDeviceID(void) -{ - return 0; -} - -/*-------------------------------------------------------------------------------------------------*/ -/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */ -PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ -{ - internalPortAudioDevice* pad; - PaError r = paNoError; - int audioLibFileID; /* To test for the presence of audio. */ - - if (sDeviceList) /* Allow re-init, only warn, no error. */ - { - ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); - return r; - } - /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/ - audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ - if (audioLibFileID < 0) /* IO port. On failure, machine */ - { /* has no audio ability. */ - ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); - return paHostError; - } - close(audioLibFileID); /* Allocate fast mem to hold device info. */ - pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); - if (pad == NULL) - return paInsufficientMemory; - memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ - r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ - Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ - "AL default", /* A suitable name. */ - pad); /* Write args and queried info into pad. */ - if (r != paNoError) - { - ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ - } - else - sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ - /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ - /*---------------------------------------------------------------------------------------------*/ - return r; -} - -/*---------------------------------------------------------------------------------------------------*/ -static PaError Pa_SgiAudioProcess(internalPortAudioStream *past) /* Spawned by PaHost_StartEngine(). */ -{ - PaError result = paNoError; - PaHostSoundControl *pahsc; - - if (!past) - return paBadStreamPtr; - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (!pahsc) - return paInternalError; - past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ - DBUG(("entering thread.\n")); - - while (!past->past_StopSoon) /* OR-ing StopSoon and StopNow here gives problems! */ - { - /*---------------------------------------- INPUT: ------------------------------------*/ - if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */ - { - while (ALgetfilled(pahsc->pahsc_ALportIN) < pahsc->pahsc_SamplesPerInputBuffer) - { - /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */ - if (past->past_StopNow) /* Don't let ALreadsamps() block */ - goto done; - } - if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer, - pahsc->pahsc_SamplesPerInputBuffer)) /* Number of samples instead */ - { /* of number of frames. */ - ERR_RPT(("ALreadsamps() failed.\n")); - result = paInternalError; - goto done; - } - } - /*---------------------------------------------------- USER CALLBACK ROUTINE: ----------*/ - /* DBUG(("Calling Pa_CallConvertInt16()...\n")); */ - Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ - result = Pa_CallConvertInt16(past, /* user data and call user routine. */ - pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer); - Pa_EndUsageCalculation(past); - if (result) - { - DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); - goto done; /* This is apparently NOT an error! */ - } /* Just letting the userCallBack stop us. */ - /*---------------------------------------- OUTPUT: ------------------------------------*/ - if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */ - { - while (ALgetfillable(pahsc->pahsc_ALportOUT) < pahsc->pahsc_SamplesPerOutputBuffer) - { - /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */ - if (past->past_StopNow) /* Don't let ALwritesamps() block */ - goto done; - } - if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer, - pahsc->pahsc_SamplesPerOutputBuffer)) - { - ERR_RPT(("ALwritesamps() failed.\n")); - result = paInternalError; - goto done; - } - } - /*-------------------------------------------------------------------------------------*/ - } -done: - /* pahsc->pahsc_ThreadPID = -1; Hu? doesn't help!! (added by Pieter) */ - past->past_IsActive = 0; - DBUG(("leaving thread.\n")); - return result; -} - - -/*--------------------------------------------------------------------------------------*/ -PaError PaHost_OpenStream(internalPortAudioStream *past) -{ - PaError result = paNoError; - PaHostSoundControl *pahsc; - unsigned int minNumBuffers; - internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ - ALconfig sgiALconfig = NULL; /* IRIX-datatype. */ - long pvbuf[8]; /* To get/set hardware configs. */ - long sr, ALqsize; - DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ - if (!past) - { - ERR_RPT(("Streampointer NULL!\n")); - result = paBadStreamPtr; goto done; - } - pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); - if (pahsc == NULL) - { - ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ - result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ - } - memset(pahsc, 0, sizeof(PaHostSoundControl)); -/* pahsc->pahsc_threadPID = -1; Should pahsc_threadPID be inited to */ - past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ - /*--------------------------------------------------- Allocate native buffers: --------*/ - pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumInputChannels; /* audio-thread. */ - pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); - if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */ - { - pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer); - if( pahsc->pahsc_NativeInputBuffer == NULL ) - { - ERR_RPT(("Fast memory allocation for input-buffer failed.\n")); - result = paInsufficientMemory; goto done; - } - } - pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumOutputChannels; /* audio-thread. */ - pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); - if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */ - { - pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer); - if (pahsc->pahsc_NativeOutputBuffer == NULL) - { - ERR_RPT(("Fast memory allocation for output-buffer failed.\n")); - result = paInsufficientMemory; goto done; - } - } - /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ - ALseterrorhandler(0); /* 0 = turn off the default error handler. */ - pvbuf[0] = AL_INPUT_RATE; - pvbuf[2] = AL_INPUT_COUNT; - pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ - pvbuf[6] = AL_OUTPUT_COUNT; - sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */ - if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ - { /* sponding native AL-number(s). */ - padIN = Pa_GetInternalDevice(past->past_InputDeviceID); - if (!padIN) - { - ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); - result = paHostError; goto done; - } - if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ - goto sgiError; /* the same AL-device, the AL-library might */ - if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ - { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ - if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ - { - ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ -another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); - result = paHostError; goto done; - } - pvbuf[1] = sr; /* Then set input-rate. */ - if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) - goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ - } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */ - } - if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ - { /* We use padOUT/IN later on, or at least 1 of both. */ - padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); - if (!padOUT) - { - ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); - result = paHostError; goto done; - } - if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) - goto sgiError; - if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr)) - { /* Output needed and rate different from current harware-rate. */ - if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ - { - ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ -another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); - result = paHostError; goto done; /* Will free again the inputbuffer */ - } /* that was just created above. */ - pvbuf[5] = sr; /* Then set output-rate. */ - if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) - goto sgiError; - } - } - /*------------------------------------------ Construct an audio-port-configuration ----------*/ - sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */ - if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */ - goto sgiError; /* See that sgiALconfig is NOT released! */ - if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ - goto sgiError; - if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */ - goto sgiError; /* config is set to two's complement format. */ - /************************ Future versions might (dynamically) switch to 32-bit floats? ******* - if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) - goto sgiError; - if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config - goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ - /*---------- ?? --------------------*/ - /* 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; - /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/ - if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer) - ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer; - else /* Take the largest of the two amounts. */ - ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer; - ALqsize *= 4; /* 4 times as large as amount per transfer! */ - if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */ - goto sgiError; /* Using 2 times may give glitches... */ - /* Have to work on ALsetqueuesize() above. */ - - /* Do ALsetchannels() later, apart per input and/or output. */ - /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/ - if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */ - { - if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) - { - DBUG(("PaHost_OpenStream: opening both input and output channels.\n")); - /*------------------------- open output port: ----------------------------------*/ - if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); - if (pahsc->pahsc_ALportOUT == (ALport)0) - goto sgiError; - /*------------------------- open input port: -----------------------------------*/ - if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); - if (pahsc->pahsc_ALportIN == (ALport)0) - goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */ - } /* Probably due to too small buffersizes?.... */ - else - { - ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); - result = paHostError; - goto done; - } - } - else /* (OutputDeviceID != InputDeviceID) */ - { - if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */ - { - /*------------------------- open output port: ----------------------------------*/ - DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n", - past->past_NumOutputChannels, padOUT->pad_DeviceName)); - if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); - if (pahsc->pahsc_ALportOUT == (ALport)0) - goto sgiError; - } - if (past->past_NumInputChannels > 0) /* READ-ONLY: */ - { - /*------------------------- open input port: -----------------------------------*/ - DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n", - past->past_NumInputChannels, padIN->pad_DeviceName)); - if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); - if (pahsc->pahsc_ALportIN == (ALport)0) - goto sgiError; - } - } - DBUG(("PaHost_OpenStream() succeeded.\n")); - goto done; /* (no errors occured) */ -sgiError: - result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ -done: - if (sgiALconfig) - ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */ - if (result != paNoError) - PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ - return result; -} - -/*-----------------------------------------------------*/ -PaError PaHost_StartOutput(internalPortAudioStream *past) -{ - return paNoError; /* Hmm, not implemented yet? */ -} -PaError PaHost_StartInput(internalPortAudioStream *past) -{ - return paNoError; -} - -/*------------------------------------------------------------------------------*/ -PaError PaHost_StartEngine(internalPortAudioStream *past) -{ - PaHostSoundControl *pahsc; - int hres; - PaError result = paNoError; - - if (!past) /* Test argument. */ - { - ERR_RPT(("PaHost_StartEngine(NULL)!\n")); - return paBadStreamPtr; - } - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (!pahsc) - { - ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData == NULL!\n")); - return paHostError; - } - past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ - past->past_StopNow = 0; - past->past_IsActive = 1; - DBUG(("PaHost_StartEngine() called.\n")); - /* Use pthread_create() instead of __clone() because: */ - /* - pthread_create also works for other UNIX systems like Solaris, */ - /* - Java HotSpot VM crashes in pthread_setcanceltype() when using __clone(). */ - hres = pthread_create(&(pahsc->pahsc_ThreadPID), /* SPAWN AUDIO-CHILD. */ - NULL, /* pthread_attr_t * attr */ - (void*)Pa_SgiAudioProcess, - past); - if (hres) - { - result = paHostError; - sPaHostError = hres; - ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); - } - return result; -} - -/*------------------------------------------------------------------------------*/ -PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) -{ - int hres; - PaError result = paNoError; - PaHostSoundControl *pahsc; - - DBUG(("PaHost_StopEngine() called.\n")); - if (!past) - return paBadStreamPtr; - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (pahsc == NULL) - return result; /* paNoError (already stopped, no err?). */ - past->past_StopSoon = 1; /* Tell background thread to stop generating */ - if (abort) /* more and to let current data play out. If */ - past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ - if (pahsc->pahsc_ThreadPID != -1) /* Join thread to recover memory resources. */ - { - DBUG(("pthread_join() called.\n")); - hres = pthread_join(pahsc->pahsc_ThreadPID, NULL); - if (hres) - { - result = paHostError; - sPaHostError = hres; - ERR_RPT(("PaHost_StopEngine() failed pthread_join().\n")); - } - pahsc->pahsc_ThreadPID = -1; - } - past->past_IsActive = 0; - return result; -} - -/*---------------------------------------------------------------*/ -PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) -{ - return paNoError; /* Not implemented yet? */ -} -PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) -{ - return paNoError; -} - -/*******************************************************************/ -PaError PaHost_CloseStream(internalPortAudioStream *past) -{ - PaHostSoundControl *pahsc; - PaError result = paNoError; - - DBUG(("PaHost_CloseStream() called.\n")); - if (past == NULL) - return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ - return result; /* This test prevents from freeing NULL-pointers. */ - - if (pahsc->pahsc_ALportIN) - { - if (ALcloseport(pahsc->pahsc_ALportIN)) - result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ - else /* But go on anyway... to release other stuff... */ - pahsc->pahsc_ALportIN = (ALport)0; - } - if (pahsc->pahsc_ALportOUT) - { - if (ALcloseport(pahsc->pahsc_ALportOUT)) - result = translateSGIerror(); - else - pahsc->pahsc_ALportOUT = (ALport)0; - } - if (pahsc->pahsc_NativeInputBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer); - pahsc->pahsc_NativeInputBuffer = NULL; - } - if (pahsc->pahsc_NativeOutputBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); - pahsc->pahsc_NativeOutputBuffer = NULL; - } - PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); - past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST. */ - 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 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. -*/ -#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") - -int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) -{ - return 2; -} -/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */ -/* Do we HAVE to do it this way under IRIX???.... */ -/*--------------------------------------------------------------*/ - - -/*---------------------------------------------------------------------*/ -PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ -{ /* Called by Pa_Terminate() from pa_lib.c. */ - internalPortAudioDevice *pad = sDeviceList, - *nxt; - while (pad) - { - DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); - nxt = pad->pad_Next; - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); - pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ - } - sDeviceList = (internalPortAudioDevice*)NULL; - return 0; /* Got rid of sNumDevices=0; */ -} - -/***********************************************************************/ -void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ -{ -#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 physi- */ -/* cal 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); - if (addr) - 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) -{ - if (addr) - 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); -} - -/*-------------------------------------------------------------------*/ -PaTimestamp Pa_StreamTime( PortAudioStream *stream ) -{ - internalPortAudioStream *past = (internalPortAudioStream *) stream; -/* FIXME - return actual frames played, not frames generated. -** Need to query the output device somehow. -*/ - return past->past_FrameCount; -} diff --git a/pa_tests/debug_convert.c b/pa_tests/debug_convert.c deleted file mode 100644 index a17b556..0000000 --- a/pa_tests/debug_convert.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * $Id$ - * Convert tagged values. - * - * Author: Phil Burk - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: http://www.portaudio.com - * 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. - * - */ -#include -#include -#include "portaudio.h" -#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) -//#define OUTPUT_DEVICE (11) -#define NUM_SECONDS (8) -#define SLEEP_DUR (800) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (256) - -#define NUM_BUFFERS (0) - -typedef struct -{ - unsigned int framesToGo; -} -paTestData; -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData*)userData; - short *out = (short*)outputBuffer; - int i; - int finished = 0; - (void) outTime; /* Prevent unused variable warnings. */ - (void) inputBuffer; - - if( data->framesToGo < framesPerBuffer ) finished = 1; - - for( i=0; i -#include -#include "portaudio.h" -#include "pa_host.h" - -/*******************************************************************/ -int main(void); -int main(void) -{ - long max,min; - int i; - - for( i=0; i<10000; i++ ) - { - long dither = PaConvert_TriangularDither(); - // printf("dither = 0x%08X\n", dither ); - if( dither < min ) min = dither; - else if( dither > max ) max = dither; - } - printf("min = 0x%08X = %d, max = 0x%08X = %d\n", min, min, max, max ); -} diff --git a/pa_tests/debug_multi_out.c b/pa_tests/debug_multi_out.c index d230833..4817a11 100644 --- a/pa_tests/debug_multi_out.c +++ b/pa_tests/debug_multi_out.c @@ -1,8 +1,9 @@ /* * $Id$ - * debug_multi_out.c - * Play a different sine wave on each channels, + * debug_multi.c + * Play a sine wave on each of multiple channels, * using the Portable Audio api. + * Hacked test for debugging PA. * * Author: Phil Burk http://www.softsynth.com * @@ -37,24 +38,28 @@ #include #include #include "portaudio.h" - -#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +#define NUM_CHANNELS (8) +// #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +#define OUTPUT_DEVICE (18) +#define NUM_SECONDS (NUM_CHANNELS*4) #define SAMPLE_RATE (44100) +#define FRAMES_PER_CHANNEL (SAMPLE_RATE/2) #define FRAMES_PER_BUFFER (256) -#define FREQ_INCR (300.0 / SAMPLE_RATE) -#define MAX_CHANNELS (64) - +#define MIN_LATENCY_MSEC (400) +#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #ifndef M_PI #define M_PI (3.14159265) #endif - +#define TABLE_SIZE (800) typedef struct { - int numChannels; - double phases[MAX_CHANNELS]; + float sine[TABLE_SIZE]; + int phase; + int liveChannel; + int count; + unsigned int sampsToGo; } paTestData; - /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). @@ -65,25 +70,38 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; - int frameIndex, channelIndex; + int i, j; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; - for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) + if( data->sampsToGo < framesPerBuffer ) { - for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) - { - /* Output sine wave on every channel. */ - *out++ = (float) sin(data->phases[channelIndex]); - - /* Play each channel at a higher frequency. */ - data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); - if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); - } + finished = 1; } - - return 0; + else + { + for( i=0; i<(int)framesPerBuffer; i++ ) + { + for( j=0; jliveChannel) ? data->sine[data->phase] : 0.0f; + /* Play each channel at a higher frequency. */ + data->phase += 1 + data->liveChannel; + if( data->phase >= TABLE_SIZE ) data->phase -= TABLE_SIZE; + } + /* Switch channels every so often. */ + if( --data->count <= 0 ) + { + data->count = FRAMES_PER_CHANNEL; + data->liveChannel += 1; + if( data->liveChannel >= NUM_CHANNELS ) data->liveChannel = 0; + } + } + data->sampsToGo -= framesPerBuffer; + } + return finished; } /*******************************************************************/ int main(void); @@ -91,18 +109,21 @@ int main(void) { PortAudioStream *stream; PaError err; - const PaDeviceInfo *pdi; - paTestData data = {0}; - printf("PortAudio Test: output sine wave on each channel.\n" ); - + paTestData data; + int i; + int totalSamps; + printf("PortAudio Test: output sine wave. %d buffers\n", NUM_BUFFERS ); + /* initialise sinusoidal wavetable */ + for( i=0; imaxOutputChannels; - if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; - printf("Number of Channels = %d\n", data.numChannels ); - err = Pa_OpenStream( &stream, paNoDevice, /* default input device */ @@ -110,27 +131,27 @@ int main(void) paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, - data.numChannels, + NUM_CHANNELS, paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ - 0, /* number of buffers, if zero then use default minimum */ + NUM_BUFFERS, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; - err = Pa_StartStream( stream ); if( err != paNoError ) goto error; - - printf("Hit ENTER to stop sound.\n"); - fflush(stdout); - getchar(); - + printf("Is callback being called?\n"); + for( i=0; isamplesPerFrame, /* stereo input */ + data.samplesPerFrame, /* stereo input */ PA_SAMPLE_TYPE, NULL, paNoDevice, @@ -176,15 +195,14 @@ PaError TestRecording( paTestData *dataPtr ) PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ + REC_BUF_FRAMES, /* frames per buffer */ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ recordCallback, - dataPtr ); + &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; - printf("Now recording!\n"); fflush(stdout); for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) { @@ -193,28 +211,54 @@ PaError TestRecording( paTestData *dataPtr ) printf("Stream inactive!\n"); break; } - if( dataPtr->maxFrameIndex <= dataPtr->frameIndex ) + if( data.maxFrameIndex <= data.frameIndex ) { printf("Buffer recording complete.\n"); break; } Pa_Sleep(100); - printf("index = %d\n", dataPtr->frameIndex ); fflush(stdout); + printf("index = %d\n", data.frameIndex ); + } + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + /* Playback recorded data. */ + data.frameIndex = 0; + printf("Begin playback.\n"); fflush(stdout); + err = Pa_OpenStream( + &stream, + paNoDevice, + 0, /* NO input */ + PA_SAMPLE_TYPE, + NULL, + Pa_GetDefaultOutputDeviceID(), + data.samplesPerFrame, /* stereo output */ + PA_SAMPLE_TYPE, + NULL, + SAMPLE_RATE, + 1024, /* frames per buffer */ + 0, /* number of buffers, if zero then use default minimum */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + playCallback, + &data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Waiting for playback to finish.\n"); fflush(stdout); + for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) + { + Pa_Sleep(100); + printf("index = %d\n", data.frameIndex ); } - - printf("Finished loop. Close stream.\n"); fflush(stdout); - err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; - printf("Done.\n"); fflush(stdout); { SAMPLE max = 0; SAMPLE posVal; int i; - for( i=0; inumSamples; i++ ) + for( i=0; irecordedSamples[i]; + posVal = data.recordedSamples[i]; if( posVal < 0 ) posVal = -posVal; if( posVal > max ) max = posVal; } @@ -231,101 +275,15 @@ PaError TestRecording( paTestData *dataPtr ) } else { - fwrite( dataPtr->recordedSamples, dataPtr->samplesPerFrame * sizeof(SAMPLE), totalFrames, fid ); + fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid ); fclose( fid ); printf("Wrote data to 'recorded.raw'\n"); } } #endif - -error: - return err; -} - -/****************************************************************/ -PaError TestPlayback( paTestData *dataPtr ) -{ - PortAudioStream *stream; - PaError err; - int i; - - /* Playback recorded data. */ - dataPtr->frameIndex = 0; - printf("Begin playback.\n"); fflush(stdout); - err = Pa_OpenStream( - &stream, - paNoDevice, - 0, /* NO input */ - PA_SAMPLE_TYPE, - NULL, - Pa_GetDefaultOutputDeviceID(), - dataPtr->samplesPerFrame, /* stereo output */ - PA_SAMPLE_TYPE, - NULL, - SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - playCallback, - dataPtr ); - if( err != paNoError ) goto error; - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - printf("Waiting for playback to finish.\n"); fflush(stdout); - for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) - { - Pa_Sleep(100); - printf("index = %d\n", dataPtr->frameIndex ); - } - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error; - -error: - return err; -} -/*******************************************************************/ -int main(void); -int main(void) -{ - PaError err; - paTestData data; - long totalFrames; - long numBytes; - long i; - printf("patest_record.c\n"); fflush(stdout); - - data.frameIndex = 0; - data.samplesPerFrame = 2; - data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE; - - printf("totalFrames = %d\n", totalFrames ); fflush(stdout); - data.numSamples = totalFrames * data.samplesPerFrame; - - numBytes = data.numSamples * sizeof(SAMPLE); - data.recordedSamples = (SAMPLE *) malloc( numBytes ); - if( data.recordedSamples == NULL ) - { - printf("Could not allocate record array.\n"); - exit(1); - } - for( i=0; i -#include -#include -#include "portaudio.h" -#define SAMPLE_RATE (22050) -#define NUM_SECONDS (4) -#define SLEEP_DUR_MSEC (200) -#define FRAMES_PER_BUFFER (256) -#define NUM_REC_BUFS (0) - -#if 1 -#define PA_SAMPLE_TYPE paFloat32 -typedef float SAMPLE; -#else -#define PA_SAMPLE_TYPE paInt16 -typedef short SAMPLE; -#endif - -typedef struct -{ - long frameIndex; /* Index into sample array. */ - long maxFrameIndex; - long samplesPerFrame; - long numSamples; - PortAudioStream *outputStream; - PortAudioStream *inputStream; - SAMPLE *recordedSamples; -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may be called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int recordCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData*)userData; - SAMPLE *rptr = (SAMPLE*)inputBuffer; - SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; - long framesToCalc; - unsigned long i; - int finished; - unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; - - (void) outputBuffer; /* Prevent unused variable warnings. */ - (void) outTime; - - if( framesLeft < framesPerBuffer ) - { - framesToCalc = framesLeft; - finished = 1; - } - else - { - framesToCalc = framesPerBuffer; - finished = 0; - } - if( inputBuffer == NULL ) - { - for( i=0; iframeIndex += framesToCalc; - return finished; -} - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may be called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int playCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData*)userData; - SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; - SAMPLE *wptr = (SAMPLE*)outputBuffer; - unsigned long i; - int finished; - unsigned int framesLeft = data->maxFrameIndex - data->frameIndex; - if( outputBuffer == NULL ) return 0; - (void) inputBuffer; /* Prevent unused variable warnings. */ - (void) outTime; - - if( framesLeft < framesPerBuffer ) - { - /* final buffer... */ - for( i=0; iframeIndex += framesLeft; - finished = 1; - } - else - { - for( i=0; iframeIndex += framesPerBuffer; - finished = 0; - } - return finished; -} - -/****************************************************************/ -PaError TestRecording( paTestData *dataPtr ) -{ - PaError err; - int i; - int lastIndex = 0; - -/* Open input stream if not already open. */ - if( dataPtr->inputStream == NULL ) - { - /* Record some audio. */ - err = Pa_OpenStream( - &dataPtr->inputStream, - Pa_GetDefaultInputDeviceID(), - dataPtr->samplesPerFrame, /* stereo input */ - PA_SAMPLE_TYPE, - NULL, - paNoDevice, - 0, - PA_SAMPLE_TYPE, - NULL, - SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - recordCallback, - dataPtr ); - if( err != paNoError ) goto error; - } - - dataPtr->frameIndex = 0; - - err = Pa_StartStream( dataPtr->inputStream ); - if( err != paNoError ) goto error; - - printf("Now recording!\n"); fflush(stdout); - for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) - { - int frameIndex, delta; - Pa_Sleep(SLEEP_DUR_MSEC); - - frameIndex = dataPtr->frameIndex; - if( Pa_StreamActive( dataPtr->inputStream ) <= 0) - { - printf("Stream inactive!\n"); - break; - } - if( dataPtr->maxFrameIndex <= frameIndex ) - { - printf("Buffer recording complete.\n"); - break; - } - - delta = frameIndex - lastIndex; - lastIndex = frameIndex; - printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout); - } - - err = Pa_StopStream( dataPtr->inputStream ); - if( err != paNoError ) goto error; - - printf("Done.\n"); fflush(stdout); - -error: - return err; -} - -/****************************************************************/ -PaError TestPlayback( paTestData *dataPtr ) -{ - PaError err; - int i; - int lastIndex = 0; - - /* Playback recorded data. */ - dataPtr->frameIndex = 0; - printf("Begin playback.\n"); fflush(stdout); - -/* Open output stream if not already open. */ - if( dataPtr->outputStream == NULL ) - { - err = Pa_OpenStream( - &dataPtr->outputStream, - paNoDevice, - 0, /* NO input */ - PA_SAMPLE_TYPE, - NULL, - Pa_GetDefaultOutputDeviceID(), - dataPtr->samplesPerFrame, /* stereo output */ - PA_SAMPLE_TYPE, - NULL, - SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - playCallback, - dataPtr ); - if( err != paNoError ) goto error; - } - - err = Pa_StartStream( dataPtr->outputStream ); - if( err != paNoError ) goto error; - - printf("Waiting for playback to finish.\n"); fflush(stdout); - for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) - { - int frameIndex, delta; - Pa_Sleep(SLEEP_DUR_MSEC); - frameIndex = dataPtr->frameIndex; - delta = frameIndex - lastIndex; - lastIndex = frameIndex; - printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout); - } - - err = Pa_StopStream( dataPtr->outputStream ); - if( err != paNoError ) goto error; - -error: - return err; -} -/*******************************************************************/ -int main(void); -int main(void) -{ - PaError err; - paTestData data = { 0 }; - long totalFrames; - long numBytes; - long i; - printf("patest_record.c\n"); fflush(stdout); - -/* Set up test data structure and sample array. */ - data.frameIndex = 0; - data.samplesPerFrame = 2; - data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE; - - printf("totalFrames = %d\n", totalFrames ); fflush(stdout); - data.numSamples = totalFrames * data.samplesPerFrame; - - numBytes = data.numSamples * sizeof(SAMPLE); - data.recordedSamples = (SAMPLE *) malloc( numBytes ); - if( data.recordedSamples == NULL ) - { - printf("Could not allocate record array.\n"); - exit(1); - } - for( i=0; i -#include -#include "portaudio.h" - -#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (256) -#define FREQ_INCR (300.0 / SAMPLE_RATE) -#define MAX_CHANNELS (64) - -#ifndef M_PI -#define M_PI (3.14159265) -#endif - -typedef struct -{ - int numChannels; - double phases[MAX_CHANNELS]; - float amplitude; -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData*)userData; - float *out = (float*)outputBuffer; - int frameIndex, channelIndex; - (void) outTime; /* Prevent unused variable warnings. */ - (void) inputBuffer; - - for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) - { - for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) - { - /* Output sine wave on every channel. */ - *out++ = (float) ( data->amplitude * sin(data->phases[channelIndex]) ); - - /* Play each channel at a higher frequency. */ - data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); - if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); - } - } - - return 0; -} -/*******************************************************************/ -int main(void); -int main(void) -{ - char pad[256]; - PortAudioStream *stream; - PaError err; - const PaDeviceInfo *pdi; - paTestData data = {0}; - printf("PortAudio Test: output sine wave on each channel.\n" ); - - err = Pa_Initialize(); - if( err != paNoError ) goto error; - - pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE ); - data.numChannels = pdi->maxOutputChannels; - if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; - printf("Number of Channels = %d\n", data.numChannels ); - data.amplitude = 1.0; - - err = Pa_OpenStream( - &stream, - paNoDevice, /* default input device */ - 0, /* no input */ - paFloat32, /* 32 bit floating point input */ - NULL, - OUTPUT_DEVICE, - data.numChannels, - paFloat32, /* 32 bit floating point output */ - NULL, - SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data ); - if( err != paNoError ) goto error; - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - - do - { - printf("Current amplitude = %f\n", data.amplitude ); - printf("Enter new amplitude or 'q' to quit.\n"); - fflush(stdout); - gets( pad ); - if( pad[0] != 'q' ) - { - // I tried to use atof but it seems to be broken on Mac OS X 10.1 - float amp; - sscanf( pad, "%f", & ); - data.amplitude = amp; - } - } while( pad[0] != 'q' ); - - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - Pa_CloseStream( stream ); - Pa_Terminate(); - printf("Test finished.\n"); - return err; -error: - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return err; -} diff --git a/pa_tests/debug_sine_formats.c b/pa_tests/debug_sine_formats.c deleted file mode 100644 index a1fce56..0000000 --- a/pa_tests/debug_sine_formats.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * $Id$ - * patest_sine_formats.c - * Play a sine wave using the Portable Audio api for several seconds. - * Test various data formats. - * - * Author: Phil Burk - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: 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. - * - */ -#include -#include -#include "portaudio.h" - -#define NUM_SECONDS (10) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (256) - -#define LEFT_FREQ (SAMPLE_RATE/512.0) /* So we hit 1.0 */ -#define RIGHT_FREQ (500.0) - -#define AMPLITUDE (1.0) - -/* Select ONE format for testing. */ -#define TEST_UINT8 (1) -#define TEST_INT8 (0) -#define TEST_INT16 (0) -#define TEST_FLOAT32 (0) - -#if TEST_UINT8 -#define TEST_FORMAT paUInt8 -typedef unsigned char SAMPLE_t; -#define SAMPLE_ZERO (0x80) -#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) -#define FORMAT_NAME "Unsigned 8 Bit" - -#elif TEST_INT8 -#define TEST_FORMAT paInt8 -typedef char SAMPLE_t; -#define SAMPLE_ZERO (0) -#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) -#define FORMAT_NAME "Signed 8 Bit" - -#elif TEST_INT16 -#define TEST_FORMAT paInt16 -typedef short SAMPLE_t; -#define SAMPLE_ZERO (0) -#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x))) -#define FORMAT_NAME "Signed 16 Bit" - -#elif TEST_FLOAT32 -#define TEST_FORMAT paFloat32 -typedef float SAMPLE_t; -#define SAMPLE_ZERO (0.0) -#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x)) -#define FORMAT_NAME "Float 32 Bit" -#endif - -#ifndef M_PI -#define M_PI (3.14159265) -#endif - - -typedef struct -{ - double left_phase; - double right_phase; - unsigned int framesToGo; -} -paTestData; -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData*)userData; - SAMPLE_t *out = (SAMPLE_t *)outputBuffer; - SAMPLE_t sample; - int i; - int framesToCalc; - int finished = 0; - (void) outTime; /* Prevent unused variable warnings. */ - (void) inputBuffer; - - if( data->framesToGo < framesPerBuffer ) - { - framesToCalc = data->framesToGo; - data->framesToGo = 0; - finished = 1; - } - else - { - framesToCalc = framesPerBuffer; - data->framesToGo -= framesPerBuffer; - } - - for( i=0; ileft_phase += (LEFT_FREQ / SAMPLE_RATE); - if( data->left_phase > 1.0) data->left_phase -= 1.0; - sample = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); /**/ - *out++ = sample; -/* *out++ = sample; /**/ -/* *out++ = 0; /**/ - - data->right_phase += (RIGHT_FREQ / SAMPLE_RATE); - if( data->right_phase > 1.0) data->right_phase -= 1.0; - *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); /**/ -/* *out++ = 0; /* */ - } - /* zero remainder of final buffer */ - for( ; i<(int)framesPerBuffer; i++ ) - { - *out++ = SAMPLE_ZERO; /* left */ - *out++ = SAMPLE_ZERO; /* right */ - } - return finished; -} -/*******************************************************************/ -int main(void); -int main(void) -{ - PortAudioStream *stream; - PaError err; - paTestData data; - int totalSamps; - - printf("PortAudio Test: output " FORMAT_NAME "\n"); - - - data.left_phase = data.right_phase = 0.0; - data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */ - err = Pa_Initialize(); - if( err != paNoError ) goto error; - - err = Pa_OpenStream( - &stream, - paNoDevice,/* default input device */ - 0, /* no input */ - TEST_FORMAT, - NULL, - Pa_GetDefaultOutputDeviceID(), /* default output device */ - 2, /* stereo output */ - TEST_FORMAT, - NULL, - SAMPLE_RATE, - FRAMES_PER_BUFFER, - 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data ); - if( err != paNoError ) goto error; - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - - printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS ); - while( Pa_StreamActive( stream ) ) Pa_Sleep(10); - - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error; - Pa_Terminate(); - - printf("PortAudio Test Finished: " FORMAT_NAME "\n"); - - return err; -error: - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return err; -} diff --git a/pa_tests/patest_hang.c b/pa_tests/debug_sine_wait.c similarity index 76% rename from pa_tests/patest_hang.c rename to pa_tests/debug_sine_wait.c index 6d533da..863ae77 100644 --- a/pa_tests/patest_hang.c +++ b/pa_tests/debug_sine_wait.c @@ -1,6 +1,7 @@ /* * $Id$ - * Play a sine then hang audio callback to test watchdog. + * debug_sine_wait.c + * Play a sine wave using the Portable Audio api until we hit ENTER. * * Authors: * Ross Bencina @@ -38,18 +39,21 @@ #include #include "portaudio.h" - +#define NUM_SECONDS (20) #define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (1024) +#define FRAMES_PER_BUFFER (64) +#define NUM_BUFFERS (16) + #ifndef M_PI #define M_PI (3.14159265) #endif -#define TWOPI (M_PI * 2.0) -typedef struct paTestData +#define TABLE_SIZE (200) +typedef struct { - int sleepFor; - double phase; + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; } paTestData; @@ -65,26 +69,17 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, float *out = (float*)outputBuffer; unsigned long i; int finished = 0; - double phaseInc = 0.02; - double phase = data->phase; - (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; - for( i=0; i TWOPI ) phase -= TWOPI; - /* This is not a very efficient way to calc sines. */ - *out++ = (float) sin( phase ); /* mono */ + *out++ = data->sine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } - - if( data->sleepFor > 0 ) - { - Pa_Sleep( data->sleepFor ); - } - - data->phase = phase; return finished; } @@ -93,16 +88,18 @@ int main(void); int main(void) { PortAudioStream *stream; - PaError err; - int i; - paTestData data = {0}; - - printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", - SAMPLE_RATE, FRAMES_PER_BUFFER ); - + PaError err; + paTestData data; + int i; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; i -#include -#include -#include "portaudio.h" - -#define EWS88MT_12_REC (1) -#define EWS88MT_12_PLAY (10) -#define SBLIVE_REC (2) -#define SBLIVE_PLAY (11) - -#if 0 -#define INPUT_DEVICE_ID Pa_GetDefaultInputDeviceID() -#define OUTPUT_DEVICE_ID Pa_GetDefaultOutputDeviceID() -#else -#define INPUT_DEVICE_ID (EWS88MT_12_REC) -#define OUTPUT_DEVICE_ID (SBLIVE_PLAY) -#endif - -#define INPUT_SAMPLE_RATE (22050.0) -#define OUTPUT_SAMPLE_RATE (22050.0) -#define NUM_SECONDS (4) -#define SLEEP_DUR_MSEC (1000) -#define FRAMES_PER_BUFFER (64) -#define NUM_REC_BUFS (0) -#define SAMPLES_PER_FRAME (2) - -#define PA_SAMPLE_TYPE paInt16 -typedef short SAMPLE; - -typedef struct -{ - long frameIndex; /* Index into sample array. */ -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may be called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int recordCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData *) userData; - (void) outputBuffer; /* Prevent unused variable warnings. */ - (void) outTime; - - if( inputBuffer != NULL ) - { - data->frameIndex += framesPerBuffer; - } - return 0; -} - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may be called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int playCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData *) userData; - (void) inputBuffer; /* Prevent unused variable warnings. */ - (void) outTime; - - if( outputBuffer != NULL ) - { - data->frameIndex += framesPerBuffer; - } - return 0; -} - -/****************************************************************/ -PaError MeasureStreamRate( PortAudioStream *stream, paTestData *dataPtr, double *ratePtr ) -{ - PaError err; - int i; - int totalFrames = 0; - int totalMSec = 0; - - dataPtr->frameIndex = 0; - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - - for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) - { - int delta, endIndex; - - int startIndex = dataPtr->frameIndex; - Pa_Sleep(SLEEP_DUR_MSEC); - endIndex = dataPtr->frameIndex; - - delta = endIndex - startIndex; - totalFrames += delta; - totalMSec += SLEEP_DUR_MSEC; - - printf("index = %d, delta = %d\n", endIndex, delta ); fflush(stdout); - } - - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - *ratePtr = (totalFrames * 1000.0) / totalMSec; - -error: - return err; -} - -void ReportRate( double measuredRate, double expectedRate ) -{ - double error; - - error = (measuredRate - expectedRate) / expectedRate; - error = (error < 0 ) ? -error : error; - - printf("Measured rate = %6.1f, expected rate = %6.1f\n", - measuredRate, expectedRate ); - if( error > 0.1 ) - { - printf("ERROR: unexpected rate! --------------------- ERROR!\n"); - } - else - { - printf("SUCCESS: rate within tolerance!\n"); - } -} - -/*******************************************************************/ -int main(void); -int main(void) -{ - PaError err; - paTestData data = { 0 }; - long i; - double rate; - const PaDeviceInfo *pdi; - - PortAudioStream *outputStream; - PortAudioStream *inputStream; - - err = Pa_Initialize(); - if( err != paNoError ) goto error; - - - pdi = Pa_GetDeviceInfo( INPUT_DEVICE_ID ); - printf("Input device = %s\n", pdi->name ); - pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE_ID ); - printf("Output device = %s\n", pdi->name ); - -/* Open input stream. */ - err = Pa_OpenStream( - &inputStream, - INPUT_DEVICE_ID, - SAMPLES_PER_FRAME, /* stereo input */ - PA_SAMPLE_TYPE, - NULL, - paNoDevice, - 0, - PA_SAMPLE_TYPE, - NULL, - INPUT_SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - recordCallback, - &data ); - if( err != paNoError ) goto error; - - err = Pa_OpenStream( - &outputStream, - paNoDevice, - 0, /* NO input */ - PA_SAMPLE_TYPE, - NULL, - OUTPUT_DEVICE_ID, - SAMPLES_PER_FRAME, /* stereo output */ - PA_SAMPLE_TYPE, - NULL, - OUTPUT_SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - playCallback, - &data ); - if( err != paNoError ) goto error; - -/* Record and playback multiple times. */ - for( i=0; i<2; i++ ) - { - printf("Measuring INPUT ------------------------- \n"); - err = MeasureStreamRate( inputStream, &data, &rate ); - if( err != paNoError ) goto error; - ReportRate( rate, INPUT_SAMPLE_RATE ); - - printf("Measuring OUTPUT ------------------------- \n"); - err = MeasureStreamRate( outputStream, &data, &rate ); - if( err != paNoError ) goto error; - ReportRate( rate, OUTPUT_SAMPLE_RATE ); - } - -/* Clean up. */ - err = Pa_CloseStream( inputStream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( outputStream ); - if( err != paNoError ) goto error; - - if( err != paNoError ) goto error; - - Pa_Terminate(); - - printf("Test complete.\n"); fflush(stdout); - return 0; - -error: - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - if( err == paHostError ) - { - fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() ); - } - return -1; -} diff --git a/pa_tests/pa_minlat.c b/pa_tests/pa_minlat.c index 90b20df..356ccb9 100644 --- a/pa_tests/pa_minlat.c +++ b/pa_tests/pa_minlat.c @@ -38,21 +38,18 @@ #include #include #include "portaudio.h" - #ifndef M_PI #define M_PI (3.14159265) #endif -#define TWOPI (M_PI * 2.0) - -#define DEFAULT_BUFFER_SIZE (64) - +#define DEFAULT_BUFFER_SIZE (128) +#define TABLE_SIZE (200) typedef struct { - double left_phase; - double right_phase; + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; } paTestData; - /* Very simple synthesis routine to generate two sine waves. */ static int paminlatCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, @@ -61,25 +58,15 @@ static int paminlatCallback( void *inputBuffer, void *outputBuffer, paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned int i; - double left_phaseInc = 0.02; - double right_phaseInc = 0.06; - - double left_phase = data->left_phase; - double right_phase = data->right_phase; - for( i=0; i TWOPI ) left_phase -= TWOPI; - *out++ = (float) sin( left_phase ); - - right_phase += right_phaseInc; - if( right_phase > TWOPI ) right_phase -= TWOPI; - *out++ = (float) sin( right_phase ); + *out++ = data->sine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } - - data->left_phase = left_phase; - data->right_phase = right_phase; return 0; } void main( int argc, char **argv ); @@ -88,6 +75,7 @@ void main( int argc, char **argv ) PortAudioStream *stream; PaError err; paTestData data; + int i; int go; int numBuffers = 0; int minBuffers = 0; @@ -103,8 +91,12 @@ void main( int argc, char **argv ) /* Get bufferSize from command line. */ framesPerBuffer = ( argc > 1 ) ? atol( argv[1] ) : DEFAULT_BUFFER_SIZE; printf("Frames per buffer = %d\n", framesPerBuffer ); - - data.left_phase = data.right_phase = 0.0; + /* Initialise sinusoidal wavetable. */ + for( i=0; i, and Darren Gibbs + * Author: Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com @@ -36,18 +36,15 @@ #include #include #include "portaudio.h" - #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (64) - -#if 0 +#define FRAMES_PER_BUFFER (256) +#if 1 #define MIN_LATENCY_MSEC (2000) #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #else #define NUM_BUFFERS (0) #endif - #define MIN_FREQ (100.0f) #define CalcPhaseIncrement(freq) ((freq)/SAMPLE_RATE) #ifndef M_PI @@ -56,7 +53,7 @@ #define TABLE_SIZE (400) typedef struct { - float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */ + float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation float phase_increment; float left_phase; float right_phase; @@ -111,16 +108,15 @@ int main(void) paTestData data; int i; int done = 0; - printf("PortAudio Test: enter letter then hit ENTER. numBuffers = %d\n", NUM_BUFFERS ); + printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS ); /* initialise sinusoidal wavetable */ for( i=0; i 0 ) { - Pa_Sleep( 300 ); + printf("Countdown = %d, Toggle = %d\n", data.countDown, data.toggle ); + fflush( stdout ); + Pa_Sleep( 1000/4 ); timeout -= 1; } diff --git a/pa_tests/patest_longsine.c b/pa_tests/patest_longsine.c index 0e1e337..3d8bd4c 100644 --- a/pa_tests/patest_longsine.c +++ b/pa_tests/patest_longsine.c @@ -1,7 +1,7 @@ /* * $Id$ * patest_longsine.c - * Play a sine wave using the Portable Audio api until ENTER hit. + * Play a sine wave using the Portable Audio api forever. * * Author: Phil Burk http://www.softsynth.com * @@ -36,13 +36,10 @@ #include #include #include "portaudio.h" - #define SAMPLE_RATE (44100) - #ifndef M_PI #define M_PI (3.14159265) #endif - #define TABLE_SIZE (200) typedef struct { @@ -51,7 +48,6 @@ typedef struct int right_phase; } paTestData; - /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). @@ -76,7 +72,6 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, } return 0; } - /*******************************************************************/ int main(void); int main(void) @@ -86,17 +81,14 @@ int main(void) paTestData data; int i; printf("PortAudio Test: output sine wave.\n"); - /* initialise sinusoidal wavetable */ for( i=0; isine[index]; - float hi = data->sine[index+1]; - float val = lo + fract*(hi-lo); - return val; -} - /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). @@ -88,42 +64,34 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; - float outSample; - float scaler; - int numForScale; unsigned long i; int j; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; -/* Detemine amplitude scaling factor */ - numForScale = data->numSines; - if( numForScale < 8 ) numForScale = 8; /* prevent pops at beginning */ - scaler = 1.0f / numForScale; - for( i=0; inumSines; j++ ) { /* Advance phase of next oscillator. */ phase = data->phases[j]; phase += phaseInc; - if( phase >= 1.0 ) phase -= 1.0; + if( phase > TWOPI ) phase -= TWOPI; - output += LookupSine(data, phase); + phaseInc *= 1.02; + if( phaseInc > 0.5 ) phaseInc *= 0.5; + + /* This is not a very efficient way to calc sines. */ + output += (float) sin( phase ); data->phases[j] = phase; - - phaseInc *= 1.02f; - if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC; } - outSample = (float) (output * scaler); - *out++ = outSample; /* Left */ - *out++ = outSample; /* Right */ + + *out++ = (float) (output / data->numSines); } return finished; } @@ -132,34 +100,27 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, int main(void); int main(void) { - int i; PortAudioStream *stream; PaError err; paTestData data = {0}; double load; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); - /* initialise sinusoidal wavetable */ - for( i=0; i -#include -#include "portaudio.h" - -#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (256) -#define FREQ_INCR (300.0 / SAMPLE_RATE) -#define MAX_CHANNELS (64) - -#ifndef M_PI -#define M_PI (3.14159265) -#endif - -typedef struct -{ - int numChannels; - double phases[MAX_CHANNELS]; -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData*)userData; - float *out = (float*)outputBuffer; - int frameIndex, channelIndex; - int finished = 0; - (void) outTime; /* Prevent unused variable warnings. */ - (void) inputBuffer; - - for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) - { - for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) - { - /* Output sine wave on every channel. */ - *out++ = (float) sin(data->phases[channelIndex]); - - /* Play each channel at a higher frequency. */ - data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); - if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); - } - } - - return 0; -} - -/*******************************************************************/ -int main(void); -int main(void) -{ - PortAudioStream *stream; - PaError err; - const PaDeviceInfo *pdi; - paTestData data = {0}; - printf("PortAudio Test: output sine wave on each channel.\n" ); - - err = Pa_Initialize(); - if( err != paNoError ) goto error; - - pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE ); - data.numChannels = pdi->maxOutputChannels; - if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; - printf("Number of Channels = %d\n", data.numChannels ); - - err = Pa_OpenStream( - &stream, - paNoDevice, /* default input device */ - 0, /* no input */ - paFloat32, /* 32 bit floating point input */ - NULL, - OUTPUT_DEVICE, - data.numChannels, - paFloat32, /* 32 bit floating point output */ - NULL, - SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data ); - if( err != paNoError ) goto error; - - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - - printf("Hit ENTER to stop sound.\n"); - getchar(); - - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - Pa_CloseStream( stream ); - Pa_Terminate(); - printf("Test finished.\n"); - return err; -error: - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return err; -} diff --git a/pa_tests/patest_record.c b/pa_tests/patest_record.c index 11d8791..47ccec1 100644 --- a/pa_tests/patest_record.c +++ b/pa_tests/patest_record.c @@ -42,34 +42,24 @@ /* #define SAMPLE_RATE (17932) /* Test failure to open with this value. */ #define SAMPLE_RATE (44100) #define NUM_SECONDS (5) -#define NUM_CHANNELS (2) -/* #define DITHER_FLAG (paDitherOff) /**/ -#define DITHER_FLAG (0) /**/ /* Select sample format. */ #if 0 #define PA_SAMPLE_TYPE paFloat32 typedef float SAMPLE; -#define SAMPLE_SILENCE (0.0f) #elif 0 #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; -#define SAMPLE_SILENCE (0) -#elif 0 -#define PA_SAMPLE_TYPE paInt8 -typedef char SAMPLE; -#define SAMPLE_SILENCE (0) #else #define PA_SAMPLE_TYPE paUInt8 typedef unsigned char SAMPLE; -#define SAMPLE_SILENCE (128) - #endif typedef struct { int frameIndex; /* Index into sample array. */ int maxFrameIndex; + int samplesPerFrame; SAMPLE *recordedSamples; } paTestData; @@ -83,7 +73,7 @@ static int recordCallback( void *inputBuffer, void *outputBuffer, { paTestData *data = (paTestData*)userData; SAMPLE *rptr = (SAMPLE*)inputBuffer; - SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; + SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; long framesToCalc; long i; int finished; @@ -106,8 +96,8 @@ static int recordCallback( void *inputBuffer, void *outputBuffer, { for( i=0; iframeIndex += framesToCalc; @@ -131,7 +121,7 @@ static int playCallback( void *inputBuffer, void *outputBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; - SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; + SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; SAMPLE *wptr = (SAMPLE*)outputBuffer; unsigned int i; int finished; @@ -145,12 +135,12 @@ static int playCallback( void *inputBuffer, void *outputBuffer, for( i=0; iframeIndex += framesLeft; finished = 1; @@ -160,7 +150,7 @@ static int playCallback( void *inputBuffer, void *outputBuffer, for( i=0; iframeIndex += framesPerBuffer; finished = 0; @@ -184,7 +174,8 @@ int main(void) data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */ data.frameIndex = 0; - numSamples = totalFrames * NUM_CHANNELS; + data.samplesPerFrame = 2; + numSamples = totalFrames * data.samplesPerFrame; numBytes = numSamples * sizeof(SAMPLE); data.recordedSamples = (SAMPLE *) malloc( numBytes ); @@ -202,7 +193,7 @@ int main(void) err = Pa_OpenStream( &stream, Pa_GetDefaultInputDeviceID(), - NUM_CHANNELS, /* stereo input */ + data.samplesPerFrame, /* stereo input */ PA_SAMPLE_TYPE, NULL, paNoDevice, @@ -212,7 +203,7 @@ int main(void) SAMPLE_RATE, 1024, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ - 0, //paDitherOff, /* flags */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ recordCallback, &data ); if( err != paNoError ) goto error; @@ -243,20 +234,10 @@ int main(void) } average += val; } - + printf("sample max amplitude = %d\n", max ); average = average / numSamples; + printf("sample average = %d\n", average ); - if( PA_SAMPLE_TYPE == paFloat32 ) - { - printf("sample max amplitude = %f\n", max ); - printf("sample average = %f\n", average ); - } - else - { - printf("sample max amplitude = %d\n", max ); - printf("sample average = %d\n", average ); - } - /* Write recorded data to a file. */ #if 0 { @@ -268,7 +249,7 @@ int main(void) } else { - fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid ); + fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid ); fclose( fid ); printf("Wrote data to 'recorded.raw'\n"); } @@ -285,7 +266,7 @@ int main(void) PA_SAMPLE_TYPE, NULL, Pa_GetDefaultOutputDeviceID(), - NUM_CHANNELS, /* stereo output */ + data.samplesPerFrame, /* stereo output */ PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, diff --git a/pa_tests/patest_sine.c b/pa_tests/patest_sine.c index 1f0dcd7..f6d8f6a 100644 --- a/pa_tests/patest_sine.c +++ b/pa_tests/patest_sine.c @@ -1,4 +1,5 @@ /* + * $Id$ * $Id$ * patest_sine.c * Play a sine wave using the Portable Audio api for several seconds. diff --git a/pa_tests/patest_sine_formats.c b/pa_tests/patest_sine_formats.c index ea92603..09abb7b 100644 --- a/pa_tests/patest_sine_formats.c +++ b/pa_tests/patest_sine_formats.c @@ -40,7 +40,7 @@ #define NUM_SECONDS (20) #define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (512) +#define FRAMES_PER_BUFFER (256) #define LEFT_FREQ (SAMPLE_RATE/256.0) /* So we hit 1.0 */ #define RIGHT_FREQ (500.0) #define AMPLITUDE (1.0) @@ -57,22 +57,25 @@ typedef unsigned char SAMPLE_t; #define SAMPLE_ZERO (0x80) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) #define FORMAT_NAME "Unsigned 8 Bit" +#endif -#elif TEST_INT8 +#if TEST_INT8 #define TEST_FORMAT paInt8 typedef char SAMPLE_t; #define SAMPLE_ZERO (0) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) #define FORMAT_NAME "Signed 8 Bit" +#endif -#elif TEST_INT16 +#if TEST_INT16 #define TEST_FORMAT paInt16 typedef short SAMPLE_t; #define SAMPLE_ZERO (0) -#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x))) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767.0 * (x))) #define FORMAT_NAME "Signed 16 Bit" +#endif -#elif TEST_FLOAT32 +#if TEST_FLOAT32 #define TEST_FORMAT paFloat32 typedef float SAMPLE_t; #define SAMPLE_ZERO (0.0) diff --git a/pa_tests/patest_sine_time.c b/pa_tests/patest_sine_time.c index 9c3f0af..9b9cf3b 100644 --- a/pa_tests/patest_sine_time.c +++ b/pa_tests/patest_sine_time.c @@ -43,18 +43,16 @@ #define NUM_SECONDS (8) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (64) -#define NUM_BUFFERS (0) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { - float sine[TABLE_SIZE]; - int left_phase; - int right_phase; - int framesToGo; - volatile PaTimestamp outTime; + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + int framesToGo; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. @@ -73,8 +71,6 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; - data->outTime = outTime; - if( data->framesToGo < framesPerBuffer ) { framesToCalc = data->framesToGo; @@ -104,44 +100,23 @@ static int patestCallback( void *inputBuffer, void *outputBuffer, } return finished; } -/*******************************************************************/ -static void ReportStreamTime( PortAudioStream *stream, paTestData *data ); -static void ReportStreamTime( PortAudioStream *stream, paTestData *data ) -{ - PaTimestamp streamTime, latency, outTime; - - streamTime = Pa_StreamTime( stream ); - outTime = data->outTime; - if( outTime < 0.0 ) - { - printf("Stream time = %8.1f\n", streamTime ); - } - else - { - latency = outTime - streamTime; - printf("Stream time = %8.1f, outTime = %8.1f, latency = %8.1f\n", - streamTime, outTime, latency ); - } - fflush(stdout); -} - /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; - paTestData DATA; + paTestData data; int i; int totalSamps; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); /* initialise sinusoidal wavetable */ for( i=0; i - * Phil Burk - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: 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. - * - */ -#include -#include -#include "portaudio.h" - -#define MAX_SINES (500) -#define MAX_LOAD (1.2) -#define SAMPLE_RATE (44100) -#define FRAMES_PER_BUFFER (512) -#ifndef M_PI -#define M_PI (3.14159265) -#endif -#define TWOPI (M_PI * 2.0) - -typedef struct paTestData -{ - int numSines; - double phases[MAX_SINES]; -} -paTestData; - -/* This routine will be called by the PortAudio engine when audio is needed. -** It may called at interrupt level on some machines so don't do anything -** that could mess up the system like calling malloc() or free(). -*/ -static int patestCallback( void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ) -{ - paTestData *data = (paTestData*)userData; - float *out = (float*)outputBuffer; - unsigned long i; - int j; - int finished = 0; - (void) outTime; /* Prevent unused variable warnings. */ - (void) inputBuffer; - - for( i=0; inumSines; j++ ) - { - /* Advance phase of next oscillator. */ - phase = data->phases[j]; - phase += phaseInc; - if( phase > TWOPI ) phase -= TWOPI; - - phaseInc *= 1.02; - if( phaseInc > 0.5 ) phaseInc *= 0.5; - - /* This is not a very efficient way to calc sines. */ - output += (float) sin( phase ); - data->phases[j] = phase; - } - - - *out++ = (float) (output / data->numSines); - } - return finished; -} - -/*******************************************************************/ -int main(void); -int main(void) -{ - PortAudioStream *stream; - PaError err; - int numStress; - paTestData data = {0}; - double load; - printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d. MAX_LOAD = %f\n", - SAMPLE_RATE, FRAMES_PER_BUFFER, MAX_LOAD ); - - err = Pa_Initialize(); - if( err != paNoError ) goto error; - err = Pa_OpenStream( - &stream, - paNoDevice,/* default input device */ - 0, /* no input */ - paFloat32, /* 32 bit floating point input */ - NULL, - Pa_GetDefaultOutputDeviceID(), /* default output device */ - 1, /* mono output */ - paFloat32, /* 32 bit floating point output */ - NULL, - SAMPLE_RATE, - FRAMES_PER_BUFFER, /* frames per buffer */ - 0, /* number of buffers, if zero then use default minimum */ - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data ); - if( err != paNoError ) goto error; - err = Pa_StartStream( stream ); - if( err != paNoError ) goto error; - - /* Determine number of sines required to get to 50% */ - do - { - data.numSines++; - Pa_Sleep( 100 ); - - load = Pa_GetCPULoad( stream ); - printf("numSines = %d, CPU load = %f\n", data.numSines, load ); - } - while( load < 0.5 ); - - /* Calculate target stress value then ramp up to that level*/ - numStress = (int) (2.0 * data.numSines * MAX_LOAD ); - for( ; data.numSines < numStress; data.numSines++ ) - { - Pa_Sleep( 200 ); - load = Pa_GetCPULoad( stream ); - printf("STRESSING: numSines = %d, CPU load = %f\n", data.numSines, load ); - } - - printf("Suffer for 5 seconds.\n"); - Pa_Sleep( 5000 ); - - printf("Stop stream.\n"); - err = Pa_StopStream( stream ); - if( err != paNoError ) goto error; - - err = Pa_CloseStream( stream ); - if( err != paNoError ) goto error; - - Pa_Terminate(); - printf("Test finished.\n"); - return err; -error: - Pa_Terminate(); - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return err; -} diff --git a/pa_tests/patest_wire.c b/pa_tests/patest_wire.c index c24d225..59a33a3 100644 --- a/pa_tests/patest_wire.c +++ b/pa_tests/patest_wire.c @@ -69,6 +69,7 @@ static int wireCallback( void *inputBuffer, void *outputBuffer, SAMPLE *out = (SAMPLE*)outputBuffer; SAMPLE *in = (SAMPLE*)inputBuffer; unsigned int i; + int finished = 0; (void) outTime; /* This may get called with NULL inputBuffer during initial setup. */ @@ -97,12 +98,11 @@ int main(void) { PortAudioStream *stream; PaError err; - + int numDevices = Pa_CountDevices(); err = Pa_Initialize(); if( err != paNoError ) goto error; - - printf("PortAudio Test: input device ID = %d\n", Pa_GetDefaultInputDeviceID() ); - printf("PortAudio Test: output device ID = %d\n", Pa_GetDefaultOutputDeviceID() ); + printf("PortAudio Test: input device = %d\n", Pa_GetDefaultInputDeviceID() ); + printf("PortAudio Test: output device = %d\n", Pa_GetDefaultOutputDeviceID() ); err = Pa_OpenStream( &stream, Pa_GetDefaultInputDeviceID(), /* default output device */ @@ -120,19 +120,14 @@ int main(void) wireCallback, NULL ); /* no data */ if( err != paNoError ) goto error; - err = Pa_StartStream( stream ); if( err != paNoError ) goto error; - printf("Full duplex sound test in progress.\n"); - printf("Hit ENTER to exit test.\n"); fflush(stdout); + printf("Hit ENTER to exit test.\n"); getchar(); - - printf("Closing stream.\n"); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); - printf("Full duplex sound test complete.\n"); fflush(stdout); return 0; error: diff --git a/pa_unix_oss/Makefile b/pa_unix_oss/Makefile index f501563..9f118e1 100644 --- a/pa_unix_oss/Makefile +++ b/pa_unix_oss/Makefile @@ -3,18 +3,15 @@ LIBS = -lm -lpthread CDEFINES = -I../pa_common -CFLAGS = -g -Wall +CFLAGS = -g PASRC = ../pa_common/pa_lib.c pa_unix_oss.c PAINC = ../pa_common/portaudio.h # Tests that work. TESTC = $(PASRC) ../pa_tests/patest_sine.c -#TESTC = $(PASRC) ../pa_tests/patest_longsine.c #TESTC = $(PASRC) ../pa_tests/patest_sine_time.c #TESTC = $(PASRC) ../pa_tests/patest_maxsines.c -#TESTC = $(PASRC) ../pa_tests/patest_toomanysines.c -#TESTC = $(PASRC) ../pa_tests/patest_underflow.c -#TESTC = $(PASRC) ../pa_tests/patest_hang.c +#TESTC = $(PASRC) ../pa_tests/patest_stop.c #TESTC = $(PASRC) ../pa_tests/patest_sync.c #TESTC = $(PASRC) ../pa_tests/patest_pink.c #TESTC = $(PASRC) ../pa_tests/patest_leftright.c @@ -28,8 +25,6 @@ TESTC = $(PASRC) ../pa_tests/patest_sine.c #TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Tests that do not yet work. -# OSS doesn't let us make obscenely huge buffers so the test will seem to fail. But its OK. -#TESTC = $(PASRC) ../pa_tests/patest_stop.c TESTH = $(PAINC) diff --git a/pa_unix_oss/pa_unix_oss.c b/pa_unix_oss/pa_unix_oss.c index 97f513d..400de91 100644 --- a/pa_unix_oss/pa_unix_oss.c +++ b/pa_unix_oss/pa_unix_oss.c @@ -58,16 +58,9 @@ Modfication History 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. TODO +O- change Pa_StreamTime() to query device (patest_sync.c) O- put semaphore lock around shared data? O- handle native formats better O- handle stereo-only device better ??? @@ -98,14 +91,17 @@ PaDriverInfo; #include #include #include +#include "portaudio.h" +#include "pa_host.h" +#include "pa_trace.h" + #include #include #include #include #include -#include -#include -#include +#include +#include #ifdef __linux__ #include @@ -113,9 +109,13 @@ PaDriverInfo; #include /* JH20010905 */ #endif -#include "portaudio.h" -#include "pa_host.h" -#include "pa_trace.h" +#include +#include + +/* Some versions of OSS do not define AFMT_S16_NE. Assume little endian. FIXME - check CPU*/ +#ifndef AFMT_S16_NE + #define AFMT_S16_NE AFMT_S16_LE +#endif #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) @@ -135,9 +135,6 @@ PaDriverInfo; #define DEVICE_NAME_BASE "/dev/audio" #endif -/* What is a pthread_t anyway? Here is a guess at a value that will never happen in real life. */ -#define INVALID_THREAD (-1) - #define MAX_CHARS_DEVNAME (32) #define MAX_SAMPLE_RATES (10) typedef struct internalPortAudioDevice @@ -154,14 +151,7 @@ typedef struct PaHostSoundControl { int pahsc_OutputHandle; int pahsc_InputHandle; - int pahsc_AudioPriority; /* priority of background audio thread */ - pthread_t pahsc_AudioThread; /* background audio thread */ - pid_t pahsc_AudioThreadPID; /* background audio thread */ - pthread_t pahsc_WatchDogThread; /* highest priority thread that protects system */ - int pahsc_WatchDogRun; /* Ask WatchDog to stop. */ - pthread_t pahsc_CanaryThread; /* low priority thread that detects abuse by audio */ - struct timeval pahsc_CanaryTime; - int pahsc_CanaryRun; /* Ask Canary to stop. */ + pthread_t pahsc_ThreadPID; short *pahsc_NativeInputBuffer; short *pahsc_NativeOutputBuffer; unsigned int pahsc_BytesPerInputBuffer; /* native buffer size in bytes */ @@ -169,30 +159,29 @@ typedef struct PaHostSoundControl /* 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; /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ +static int sDeviceIndex = 0; static internalPortAudioDevice *sDeviceList = NULL; static int sDefaultInputDeviceID = paNoDevice; static int sDefaultOutputDeviceID = paNoDevice; +static int sEnumerationError; static int sPaHostError = 0; /************************************************* Prototypes **********/ static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ); -static PaError Pa_QueryDevices( void ); +static Pa_QueryDevices( void ); static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ); static PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate ); /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { + struct itimerval itimer; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ @@ -235,21 +224,6 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) } /****************************************** END CPU UTILIZATION *******/ -#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. - */ -static 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 - /********************************************************************* * Try to open the named device. * If it opens, try to set various rates and formats and fill in @@ -258,6 +232,7 @@ static int Get_AFMT_S16_NE( void ) static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ) { int result = paHostError; + int numBytes; int tempDevHandle; int numChannels, maxNumChannels; int format; @@ -274,7 +249,7 @@ static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice * the correct order for OSS is: format, channels, sample rate */ - if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 ) + if ( (tempDevHandle = open(deviceName,O_WRONLY)) == -1 ) { DBUG(("Pa_QueryDevice: could not open %s\n", deviceName )); return paHostError; @@ -400,6 +375,7 @@ error: static PaError Pa_QueryDevices( void ) { internalPortAudioDevice *pad, *lastPad; + int numBytes; int go = 1; int numDevices = 0; PaError testResult; @@ -529,273 +505,55 @@ 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 && ((result = usleep( WATCHDOG_INTERVAL_USEC )) == 0) ) - { - 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 ) -{ - PaError result = 0; - 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 && ((result = usleep( WATCHDOG_INTERVAL_USEC )) == 0) ) - { - int delta; - struct timeval currentTime; - - gettimeofday( ¤tTime, NULL ); - - /* If audio thread is not advancing, then lower its priority. */ - 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 kill audio and 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_CanaryThread = INVALID_THREAD; - -#ifdef GNUSTEP - GSUnregisterCurrentThread(); /* SB20010904 */ -#endif - return 0; -} - -/*******************************************************************************************/ -static void PaHost_StopWatchDog( PaHostSoundControl *pahsc ) -{ -/* Cancel WatchDog thread if there is one. */ - if( pahsc->pahsc_WatchDogThread != INVALID_THREAD ) - { - pahsc->pahsc_WatchDogRun = 0; - DBUG(("PaHost_StopWatchDog: cancel WatchDog\n")); - pthread_cancel( pahsc->pahsc_WatchDogThread ); - pthread_join( pahsc->pahsc_WatchDogThread, NULL ); - pahsc->pahsc_WatchDogThread = INVALID_THREAD; - } -/* Cancel Canary thread if there is one. */ - if( pahsc->pahsc_CanaryThread != INVALID_THREAD ) - { - 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_CanaryThread = INVALID_THREAD; - } -} - -/*******************************************************************************************/ -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*/, - (void*)PaHost_CanaryProc, pahsc); - if( hres != 0 ) - { - pahsc->pahsc_CanaryThread = INVALID_THREAD; - result = paHostError; - sPaHostError = hres; - goto error; - } - - /* Launch a watchdog thread to prevent runaway audio thread. */ - pahsc->pahsc_WatchDogRun = 1; - hres = pthread_create(&(pahsc->pahsc_WatchDogThread), - NULL /*pthread_attr_t * attr*/, - (void*)PaHost_WatchDogProc, pahsc); - if( hres != 0 ) - { - pahsc->pahsc_WatchDogThread = INVALID_THREAD; - result = paHostError; - sPaHostError = hres; - goto error; - } - 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) - { - PRINT(("PortAudio: only superuser can use real-time priority.\n")); - } - else - { - PRINT(("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; + PaError result = 0; PaHostSoundControl *pahsc; - ssize_t bytes_read, bytes_written; - count_info info; - int delta; + short bytes_read = 0; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paInternalError; - #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif - result = PaHost_BoostPriority( past ); - if( result < 0 ) goto error; +#if 1 + { +#define SCHEDULER_POLICY SCHED_RR + + struct sched_param schp; + memset(&schp, 0, sizeof(schp)); + schp.sched_priority = sched_get_priority_max(SCHEDULER_POLICY); + + if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) + { + perror("sched_setscheduler"); + printf("PortAudio: only superuser can use real-time priority.\n"); + } + else + { + printf("PortAudio: callback priority set to level %d!\n", schp.sched_priority); + } + } +#endif + + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paInternalError; past->past_IsActive = 1; DBUG(("entering thread.\n")); while( (past->past_StopNow == 0) && (past->past_StopSoon == 0) ) { + + DBUG(("go!\n")); /* Read data from device */ if(pahsc->pahsc_NativeInputBuffer) { - DBUG(("Pa_AudioThreadProc: attempt to read %d bytes\n", pahsc->pahsc_BytesPerInputBuffer)); bytes_read = read(pahsc->pahsc_InputHandle, (void *)pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer); - DBUG(("Pa_AudioThreadProc: bytes_read = %d\n", bytes_read)); - if( bytes_read < pahsc->pahsc_BytesPerInputBuffer ) - { - ERR_RPT(("PortAudio: read interrupted! Only got %d bytes.\n", bytes_read )); - break; - } + + DBUG(("bytes_read: %d\n", bytes_read)); } /* Convert 16 bit native data to user data and call user routine. */ @@ -816,37 +574,19 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) if( pahsc->pahsc_NativeOutputBuffer ) { - bytes_written = write(pahsc->pahsc_OutputHandle, + write(pahsc->pahsc_OutputHandle, (void *)pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); - if( bytes_written < pahsc->pahsc_BytesPerOutputBuffer ) - { - ERR_RPT(("PortAudio: write interrupted! Only got %d bytes.\n", bytes_written )); - break; - } } - - /* 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; } - DBUG(("Pa_AudioThreadProc: left audio loop.\n")); - + past->past_IsActive = 0; - PaHost_StopWatchDog( pahsc ); - -error: - DBUG(("leaving audio thread.\n")); + DBUG(("leaving thread.\n")); + #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif - return result; + return 0; } /*******************************************************************************************/ @@ -863,7 +603,7 @@ static PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleR ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_SETFMT\n" )); return paHostError; } - if( tmp != AFMT_S16_NE ) + if( tmp != AFMT_S16_NE) { ERR_RPT(("Pa_SetupDeviceFormat: HW does not support AFMT_S16_NE\n" )); return paHostError; @@ -912,7 +652,7 @@ static int CalcHigherLogTwo( int n ) static void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, int channelsPerFrame ) { int tmp; - int bufferSize, powerOfTwo; + int numFrames , bufferSize, powerOfTwo; /* Increase size of buffers and reduce number of buffers to reduce latency inside driver. */ while( numBuffers > 8 ) @@ -922,7 +662,7 @@ static void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, i } /* calculate size of buffers in bytes */ - bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME - other sizes? */ + bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME */ /* Calculate next largest power of two */ powerOfTwo = CalcHigherLogTwo( bufferSize ); @@ -975,6 +715,9 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { PaError result = paNoError; PaHostSoundControl *pahsc; + int tmp; + int flags; + int numBytes, maxChannels; unsigned int minNumBuffers; internalPortAudioDevice *pad; DBUG(("PaHost_OpenStream() called.\n" )); @@ -991,8 +734,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; /* No device currently opened. */ pahsc->pahsc_InputHandle = BAD_DEVICE_ID; - pahsc->pahsc_AudioThread = INVALID_THREAD; - pahsc->pahsc_WatchDogThread = INVALID_THREAD; /* Allocate native buffers. */ pahsc->pahsc_BytesPerInputBuffer = past->past_FramesPerUserBuffer * @@ -1035,18 +776,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { 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) @@ -1068,17 +797,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { 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) { @@ -1097,17 +815,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past ) { 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) { @@ -1162,14 +869,13 @@ PaError PaHost_StartEngine( internalPortAudioStream *past ) * - 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), + hres = pthread_create(&(pahsc->pahsc_ThreadPID), NULL /*pthread_attr_t * attr*/, (void*)Pa_AudioThreadProc, past); if( hres != 0 ) { result = paHostError; sPaHostError = hres; - pahsc->pahsc_AudioThread = INVALID_THREAD; goto error; } @@ -1181,6 +887,7 @@ error: PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { int hres; + long timeOut; PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; @@ -1192,12 +899,12 @@ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) if( abort ) past->past_StopNow = 1; /* Join thread to recover memory resources. */ - if( pahsc->pahsc_AudioThread != INVALID_THREAD ) + if( pahsc->pahsc_ThreadPID != -1 ) { /* This check is needed for GNUSTEP - SB20010904 */ - if ( !pthread_equal( pahsc->pahsc_AudioThread, pthread_self() ) ) + if ( !pthread_equal( pahsc->pahsc_ThreadPID, pthread_self() ) ) { - hres = pthread_join( pahsc->pahsc_AudioThread, NULL ); + hres = pthread_join( pahsc->pahsc_ThreadPID, NULL ); } else { @@ -1210,7 +917,7 @@ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) result = paHostError; sPaHostError = hres; } - pahsc->pahsc_AudioThread = INVALID_THREAD; + pahsc->pahsc_ThreadPID = -1; } past->past_IsActive = 0; @@ -1322,7 +1029,7 @@ void Pa_Sleep( long msec ) */ void *PaHost_AllocateFastMemory( long numBytes ) { - void *addr = malloc( numBytes ); /* FIXME - do we need physical, wired, non-virtual memory? */ + void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */ if( addr != NULL ) memset( addr, 0, numBytes ); return addr; } @@ -1351,23 +1058,11 @@ PaError PaHost_StreamActive( internalPortAudioStream *past ) PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *past = (internalPortAudioStream *) stream; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - count_info info; - int delta; - + /* FIXME - return actual frames played, not frames generated. + ** Need to query the output device somehow. + */ if( past == NULL ) return paBadStreamPtr; - - 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)); - - } + return past->past_FrameCount; } /***********************************************************************/ diff --git a/pa_win_ds/pa_dsound.c b/pa_win_ds/pa_dsound.c index 877c01d..96f4753 100644 --- a/pa_win_ds/pa_dsound.c +++ b/pa_win_ds/pa_dsound.c @@ -33,7 +33,6 @@ /* Modifications * 7/19/01 Mike Berry - casts for compiling with __MWERKS__ CodeWarrior * 9/27/01 Phil Burk - use number of frames instead of real-time for CPULoad calculation. - * 4/19/02 Phil Burk - Check for Win XP for system latency calculation. */ /* Compiler flags: SUPPORT_AUDIO_CAPTURE - define this flag if you want to SUPPORT_AUDIO_CAPTURE @@ -50,12 +49,10 @@ #include "pa_host.h" #include "pa_trace.h" #include "dsound_wrapper.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 PA_USE_HIGH_LATENCY (0) #if PA_USE_HIGH_LATENCY #define PA_WIN_9X_LATENCY (500) @@ -64,9 +61,6 @@ #define PA_WIN_9X_LATENCY (140) #define PA_WIN_NT_LATENCY (280) #endif - -#define PA_WIN_WDM_LATENCY (120) - /* Trigger an underflow for testing purposes. Should normally be (0). */ #define PA_SIMULATE_UNDERFLOW (0) #if PA_SIMULATE_UNDERFLOW @@ -74,7 +68,6 @@ static gUnderCallbackCounter = 0; #define UNDER_START_GAP (10) #define UNDER_STOP_GAP (UNDER_START_GAP + 4) #endif - /************************************************* Definitions ********/ typedef struct internalPortAudioStream internalPortAudioStream; typedef struct internalPortAudioDevice @@ -85,7 +78,6 @@ typedef struct internalPortAudioDevice PaDeviceInfo pad_Info; } internalPortAudioDevice; - /* Define structure to contain all DirectSound and Windows specific data. */ typedef struct PaHostSoundControl { @@ -101,7 +93,6 @@ typedef struct PaHostSoundControl double pahsc_InverseTicksPerUserBuffer; } PaHostSoundControl; - /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ static int sNumDevices = 0; @@ -124,7 +115,6 @@ static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID, static Pa_QueryDevices( void ); static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); - /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { @@ -133,7 +123,6 @@ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) /* Query system timer for usage analysis and to prevent overuse of CPU. */ QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); } - static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { LARGE_INTEGER CurrentCount = { 0, 0 }; @@ -153,7 +142,6 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) (LOWPASS_COEFFICIENT_1 * newUsage); } } - /****************************************** END CPU UTILIZATION *******/ static PaError Pa_QueryDevices( void ) { @@ -885,38 +873,6 @@ PaError PaHost_CloseStream( internalPortAudioStream *past ) past->past_DeviceData = NULL; return paNoError; } - -/* Set minimal latency based on whether NT or Win95. - * NT has higher latency. - */ -static int PaHost_GetMinSystemLatency( void ) -{ - int minLatencyMsec; - /* Set minimal latency based on whether NT or other OS. - * NT has higher latency. - */ - OSVERSIONINFO osvi; - osvi.dwOSVersionInfoSize = sizeof( osvi ); - GetVersionEx( &osvi ); - DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); - DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); - DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); - /* Check for NT */ - if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) - { - minLatencyMsec = PA_WIN_NT_LATENCY; - } - else if(osvi.dwMajorVersion >= 5) - { - minLatencyMsec = PA_WIN_WDM_LATENCY; - } - else - { - minLatencyMsec = PA_WIN_9X_LATENCY; - } - return minLatencyMsec; -} - /************************************************************************* ** Determine minimum number of buffers required for this host based ** on minimum latency. Latency can be optionally set by user by setting @@ -932,6 +888,7 @@ static int PaHost_GetMinSystemLatency( void ) int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { char envbuf[PA_ENV_BUF_SIZE]; + DWORD hostVersion; DWORD hresult; int minLatencyMsec = 0; double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; @@ -944,7 +901,12 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) } else { - minLatencyMsec = PaHost_GetMinSystemLatency(); + /* Set minimal latency based on whether NT or Win95. + * NT has higher latency. + */ + hostVersion = GetVersion(); + /* High bit clear if NT */ + minLatencyMsec = ( (hostVersion & 0x80000000) == 0 ) ? PA_WIN_NT_LATENCY : PA_WIN_9X_LATENCY ; #if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); #endif diff --git a/pa_win_wmme/pa_win_wmme.c b/pa_win_wmme/pa_win_wmme.c index ba7ca62..2b3dea2 100644 --- a/pa_win_wmme/pa_win_wmme.c +++ b/pa_win_wmme/pa_win_wmme.c @@ -40,20 +40,15 @@ /* Modification History: PLB = Phil Burk JM = Julien Maillard - RDB = Ross Bencina PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer) PLB20010413 - check for excessive numbers of channels PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC including condition including of memory.h, - and explicit typecasting on memory allocation + and explicit typecasting on memory allocation PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory PLB20010816 - pass process instead of thread to SetPriorityClass() PLB20010927 - use number of frames instead of real-time for CPULoad calculation. JM20020118 - prevent hung thread when buffers underflow. - PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount - RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init - RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices - refactoring, renaming and fixed a few edge case bugs */ #include @@ -72,18 +67,13 @@ #include "pa_trace.h" /************************************************* Constants ********/ -#define PA_TRACK_MEMORY (0) - #define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ +#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ /* Switches for debugging. */ #define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ - /* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ #define PA_TRACE_RUN (0) #define PA_TRACE_START_STOP (1) - -#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ - #if PA_USE_HIGH_LATENCY #define PA_MIN_MSEC_PER_HOST_BUFFER (100) #define PA_MAX_MSEC_PER_HOST_BUFFER (300) /* Do not exceed unless user buffer exceeds */ @@ -98,13 +88,11 @@ #define PA_WIN_9X_LATENCY (200) #endif #define MIN_TIMEOUT_MSEC (1000) - /* ** Use higher latency for NT because it is even worse at real-time ** operation than Win9x. */ #define PA_WIN_NT_LATENCY (PA_WIN_9X_LATENCY * 2) -#define PA_WIN_WDM_LATENCY (PA_WIN_9X_LATENCY) #if PA_SIMULATE_UNDERFLOW static gUnderCallbackCounter = 0; @@ -114,52 +102,52 @@ static gUnderCallbackCounter = 0; #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) /**/ +#define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ /************************************************* Definitions ********/ /************************************************************** * Structure for internal host specific stream data. * This is allocated on a per stream basis. */ -typedef struct PaWMMEStreamData +typedef struct PaHostSoundControl { /* Input -------------- */ - HWAVEIN hWaveIn; - WAVEHDR *inputBuffers; - int currentInputBuffer; - int bytesPerHostInputBuffer; - int bytesPerUserInputBuffer; /* native buffer size in bytes */ + HWAVEIN pahsc_HWaveIn; + WAVEHDR *pahsc_InputBuffers; + int pahsc_CurrentInputBuffer; + int pahsc_BytesPerHostInputBuffer; + int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */ /* Output -------------- */ - HWAVEOUT hWaveOut; - WAVEHDR *outputBuffers; - int currentOutputBuffer; - int bytesPerHostOutputBuffer; - int bytesPerUserOutputBuffer; /* native buffer size in bytes */ + HWAVEOUT pahsc_HWaveOut; + WAVEHDR *pahsc_OutputBuffers; + int pahsc_CurrentOutputBuffer; + int pahsc_BytesPerHostOutputBuffer; + int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */ /* Run Time -------------- */ - PaTimestamp framesPlayed; - long lastPosition; /* used to track frames played. */ + PaTimestamp pahsc_FramesPlayed; + long pahsc_LastPosition; /* used to track frames played. */ /* For measuring CPU utilization. */ - LARGE_INTEGER entryCount; - double inverseTicksPerHostBuffer; + LARGE_INTEGER pahsc_EntryCount; + double pahsc_InverseTicksPerHostBuffer; /* Init Time -------------- */ - int numHostBuffers; - int framesPerHostBuffer; - int userBuffersPerHostBuffer; - CRITICAL_SECTION streamLock; /* Mutext to prevent threads from colliding. */ - INT streamLockInited; + int pahsc_NumHostBuffers; + int pahsc_FramesPerHostBuffer; + int pahsc_UserBuffersPerHostBuffer; + CRITICAL_SECTION pahsc_StreamLock; /* Mutext to prevent threads from colliding. */ + INT pahsc_StreamLockInited; #if PA_USE_TIMER_CALLBACK - BOOL ifInsideCallback; /* Test for reentrancy. */ - MMRESULT timerID; + BOOL pahsc_IfInsideCallback; /* Test for reentrancy. */ + MMRESULT pahsc_TimerID; #else - HANDLE abortEvent; - int abortEventInited; - HANDLE bufferEvent; - int bufferEventInited; - HANDLE engineThread; - DWORD engineThreadID; + HANDLE pahsc_AbortEvent; + int pahsc_AbortEventInited; + HANDLE pahsc_BufferEvent; + int pahsc_BufferEventInited; + HANDLE pahsc_EngineThread; + DWORD pahsc_EngineThreadID; #endif } -PaWMMEStreamData; +PaHostSoundControl; /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ static int sNumInputDevices = 0; @@ -171,169 +159,64 @@ static int sDefaultOutputDeviceID = paNoDevice; static int sPaHostError = 0; static const char sMapperSuffixInput[] = " - Input"; static const char sMapperSuffixOutput[] = " - Output"; - -#if PA_TRACK_MEMORY -static int sNumAllocations = 0; -#endif - /************************************************* Macros ********/ /* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ #define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) /************************************************* Prototypes **********/ - -void Pa_InitializeNumDevices( void ); -PaError Pa_AllocateDevicePtrs( void ); - +static Pa_QueryDevices( void ); static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); -static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ); +static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc ); static PaError PaHost_BackgroundManager( internalPortAudioStream *past ); -static void *PaHost_AllocateTrackedMemory( long numBytes ); -static void PaHost_FreeTrackedMemory( void *addr ); - -/*******************************************************************/ -static PaError PaHost_AllocateWMMEStreamData( internalPortAudioStream *stream ) -{ - PaError result = paNoError; - PaWMMEStreamData *wmmeStreamData; - - wmmeStreamData = (PaWMMEStreamData *) PaHost_AllocateFastMemory(sizeof(PaWMMEStreamData)); /* MEM */ - if( wmmeStreamData == NULL ) - { - result = paInsufficientMemory; - goto error; - } - memset( wmmeStreamData, 0, sizeof(PaWMMEStreamData) ); - stream->past_DeviceData = (void *) wmmeStreamData; - - return result; - -error: - return result; -} - -/*******************************************************************/ -static void PaHost_FreeWMMEStreamData( internalPortAudioStream *internalStream ) -{ - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) internalStream->past_DeviceData; - - PaHost_FreeFastMemory( wmmeStreamData, sizeof(PaWMMEStreamData) ); /* MEM */ - internalStream->past_DeviceData = NULL; -} -/*************************************************************************/ -static PaWMMEStreamData* PaHost_GetWMMEStreamData( internalPortAudioStream* internalStream ) -{ - PaWMMEStreamData *result = NULL; - - if( internalStream != NULL ) - { - result = (PaWMMEStreamData *) internalStream->past_DeviceData; - } - return result; -} /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ -/* FIXME: the cpu usage code should be factored out into a common module */ -static void Pa_InitializeCpuUsageScalar( internalPortAudioStream *stream ) +static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - - LARGE_INTEGER frequency; - if( QueryPerformanceFrequency( &frequency ) == 0 ) - { - wmmeStreamData->inverseTicksPerHostBuffer = 0.0; - } - else - { - wmmeStreamData->inverseTicksPerHostBuffer = stream->past_SampleRate / - ( (double)frequency.QuadPart * stream->past_FramesPerUserBuffer * wmmeStreamData->userBuffersPerHostBuffer ); - DBUG(("inverseTicksPerHostBuffer = %g\n", wmmeStreamData->inverseTicksPerHostBuffer )); - } -} -static void Pa_StartUsageCalculation( internalPortAudioStream *stream ) -{ - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - - if( wmmeStreamData == NULL ) return; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ - QueryPerformanceCounter( &wmmeStreamData->entryCount ); + QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); } -static void Pa_EndUsageCalculation( internalPortAudioStream *stream ) +static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { - LARGE_INTEGER CurrentCount; - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - - if( wmmeStreamData == NULL ) return; + LARGE_INTEGER CurrentCount = { 0, 0 }; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; /* - * Measure CPU utilization during this callback. Note that this calculation - * assumes that we had the processor the whole time. - */ + ** Measure CPU utilization during this callback. Note that this calculation + ** assumes that we had the processor the whole time. + */ #define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) if( QueryPerformanceCounter( &CurrentCount ) ) { - LONGLONG InsideCount = CurrentCount.QuadPart - wmmeStreamData->entryCount.QuadPart; - double newUsage = InsideCount * wmmeStreamData->inverseTicksPerHostBuffer; - stream->past_Usage = (LOWPASS_COEFFICIENT_0 * stream->past_Usage) + - (LOWPASS_COEFFICIENT_1 * newUsage); + LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; + double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerHostBuffer; + past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + + (LOWPASS_COEFFICIENT_1 * newUsage); } } /****************************************** END CPU UTILIZATION *******/ -static void Pa_InitializeNumDevices( void ) -{ - sNumInputDevices = waveInGetNumDevs(); - if( sNumInputDevices > 0 ) - { - sNumInputDevices += 1; /* add one extra for the WAVE_MAPPER */ - sDefaultInputDeviceID = 0; - } - else - { - sDefaultInputDeviceID = paNoDevice; - } - - sNumOutputDevices = waveOutGetNumDevs(); - if( sNumOutputDevices > 0 ) - { - sNumOutputDevices += 1; /* add one extra for the WAVE_MAPPER */ - sDefaultOutputDeviceID = sNumInputDevices; - } - else - { - sDefaultOutputDeviceID = paNoDevice; - } - - sNumDevices = sNumInputDevices + sNumOutputDevices; -} - -static PaError Pa_AllocateDevicePtrs( void ) +static PaError Pa_QueryDevices( void ) { int numBytes; - int i; - + /* Count the devices and add one extra for the WAVE_MAPPER */ + sNumInputDevices = waveInGetNumDevs() + 1; + sDefaultInputDeviceID = 0; + sNumOutputDevices = waveOutGetNumDevs() + 1; + sDefaultOutputDeviceID = sNumInputDevices; + sNumDevices = sNumInputDevices + sNumOutputDevices; /* Allocate structures to hold device info. */ /* PLB20010402 - was allocating too much memory. */ /* numBytes = sNumDevices * sizeof(PaDeviceInfo); // PLB20010402 */ - - if( sNumDevices > 0 ) - { - numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */ - sDevicePtrs = (PaDeviceInfo **) PaHost_AllocateTrackedMemory( numBytes ); /* MEM */ - if( sDevicePtrs == NULL ) return paInsufficientMemory; - - for( i = 0; i < sNumDevices; i++ ) - sDevicePtrs[i] = NULL; /* RDB20020417 explicitly set each ptr to NULL */ - } - else - { - sDevicePtrs = NULL; - } - + numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */ + sDevicePtrs = (PaDeviceInfo **) GlobalAlloc( GPTR, numBytes ); /* MEM */ + if( sDevicePtrs == NULL ) return paInsufficientMemory; return paNoError; } -/*************************************************************************/ +/************************************************************************************/ long Pa_GetHostError() { return sPaHostError; @@ -341,18 +224,16 @@ long Pa_GetHostError() /*************************************************************************/ int Pa_CountDevices() { - if( PaHost_IsInitialized() ) - return sNumDevices; - else - return 0; + if( sNumDevices <= 0 ) Pa_Initialize(); + return sNumDevices; } /************************************************************************* - * If a PaDeviceInfo structure has not already been created, - * then allocate one and fill it in for the selected device. - * - * We create one extra input and one extra output device for the WAVE_MAPPER. - * [Does anyone know how to query the default device and get its name?] - */ +** If a PaDeviceInfo structure has not already been created, +** then allocate one and fill it in for the selected device. +** +** We create one extra input and one extra output device for the WAVE_MAPPER. +** [Does anyone know how to query the default device and get its name?] +*/ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { #define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */ @@ -370,19 +251,19 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { return sDevicePtrs[ id ]; } - deviceInfo = (PaDeviceInfo *)PaHost_AllocateTrackedMemory( sizeof(PaDeviceInfo) ); /* MEM */ + deviceInfo = (PaDeviceInfo *)GlobalAlloc( GPTR, sizeof(PaDeviceInfo) ); /* MEM */ if( deviceInfo == NULL ) return NULL; deviceInfo->structVersion = 1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->numSampleRates = 0; - sampleRates = (double*)PaHost_AllocateTrackedMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */ + sampleRates = (double*)GlobalAlloc( GPTR, MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */ deviceInfo->sampleRates = sampleRates; deviceInfo->nativeSampleFormats = paInt16; /* should query for higher bit depths below */ if( id < sNumInputDevices ) { /* input device */ - int inputMmID = PaDeviceIdToWinId(id); + int inputMmID = id - 1; /* WAVE_MAPPER is -1 so we start with WAVE_MAPPER */ WAVEINCAPS wic; if( waveInGetDevCaps( inputMmID, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR ) goto error; @@ -390,21 +271,21 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) /* Append I/O suffix to WAVE_MAPPER device. */ if( inputMmID == WAVE_MAPPER ) { - s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */ + s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */ strcpy( s, wic.szPname ); strcat( s, sMapperSuffixInput ); } else { - s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 ); /* MEM */ + s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 ); /* MEM */ strcpy( s, wic.szPname ); } deviceInfo->name = s; deviceInfo->maxInputChannels = wic.wChannels; /* Sometimes a device can return a rediculously large number of channels. - * This happened with an SBLive card on a Windows ME box. - * If that happens, then force it to 2 channels. PLB20010413 - */ + ** This happened with an SBLive card on a Windows ME box. + ** If that happens, then force it to 2 channels. PLB20010413 + */ if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) ) { ERR_RPT(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels )); @@ -440,62 +321,33 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) else if( id - sNumInputDevices < sNumOutputDevices ) { /* output device */ - int outputMmID = PaDeviceIdToWinId(id); + int outputMmID = id - sNumInputDevices - 1; WAVEOUTCAPS woc; if( waveOutGetDevCaps( outputMmID, &woc, sizeof( WAVEOUTCAPS ) ) != MMSYSERR_NOERROR ) goto error; /* Append I/O suffix to WAVE_MAPPER device. */ if( outputMmID == WAVE_MAPPER ) { - s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */ + s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */ strcpy( s, woc.szPname ); strcat( s, sMapperSuffixOutput ); } else { - s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 ); /* MEM */ + s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 ); /* MEM */ strcpy( s, woc.szPname ); } deviceInfo->name = s; deviceInfo->maxOutputChannels = woc.wChannels; /* Sometimes a device can return a rediculously large number of channels. - * This happened with an SBLive card on a Windows ME box. - * It also happens on Win XP! - */ + ** This happened with an SBLive card on a Windows ME box. + ** If that happens, then force it to 2 channels. PLB20010413 + */ if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) ) { -#if 1 + ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels )); deviceInfo->maxOutputChannels = 2; -#else - /* If channel max is goofy, then query for max channels. PLB20020228 - * This doesn't seem to help. Disable code for now. Remove it later. - */ - ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d!", deviceInfo->maxOutputChannels )); - deviceInfo->maxOutputChannels = 0; - /* Attempt to find the correct maximum by querying the device. */ - for( i=2; i<16; i += 2 ) - { - WAVEFORMATEX wfx; - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nSamplesPerSec = 44100; - wfx.wBitsPerSample = 16; - wfx.cbSize = 0; /* ignored */ - wfx.nChannels = (WORD) i; - wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); - wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); - if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) - { - deviceInfo->maxOutputChannels = i; - } - else - { - break; - } - } -#endif - ERR_RPT((" Changed to %d.\n", deviceInfo->maxOutputChannels )); } - /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on the format flags. */ if( woc.dwFormats & WAVE_FORMAT_1M16 ||woc.dwFormats & WAVE_FORMAT_1S16 ) @@ -504,7 +356,6 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) sampleRates[ deviceInfo->numSampleRates++ ] = 22050.; if( woc.dwFormats & WAVE_FORMAT_4M16 ||woc.dwFormats & WAVE_FORMAT_4S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 44100.; - /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on opening the device successfully. */ for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ) @@ -525,23 +376,22 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) } sDevicePtrs[ id ] = deviceInfo; return deviceInfo; - error: - PaHost_FreeTrackedMemory( sampleRates ); /* MEM */ - PaHost_FreeTrackedMemory( deviceInfo ); /* MEM */ + GlobalFree( sampleRates ); /* MEM */ + GlobalFree( deviceInfo ); /* MEM */ return NULL; } /************************************************************************* - * Returns recommended device ID. - * On the PC, the recommended device can be specified by the user 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 ID by using - * the supplied application "pa_devs". - */ +** Returns recommended device ID. +** On the PC, the recommended device can be specified by the user 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 ID by using +** the supplied application "pa_devs". +*/ #define PA_ENV_BUF_SIZE (32) #define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE") #define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE") @@ -550,7 +400,6 @@ static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) DWORD hresult; char envbuf[PA_ENV_BUF_SIZE]; PaDeviceID recommendedID = paNoDevice; - /* Let user determine default device by setting environment variable. */ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) @@ -559,69 +408,73 @@ static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) } return recommendedID; } +static PaError Pa_MaybeQueryDevices( void ) +{ + if( sNumDevices == 0 ) + { + return Pa_QueryDevices(); + } + return 0; +} /********************************************************************** - * Check for environment variable, else query devices and use result. - */ +** Check for environment variable, else query devices and use result. +*/ PaDeviceID Pa_GetDefaultInputDeviceID( void ) { - PaDeviceID result; - + PaError result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); - if( result == paNoDevice || result < 0 || result >= sNumInputDevices ) + if( result < 0 ) { + result = Pa_MaybeQueryDevices(); + if( result < 0 ) return result; result = sDefaultInputDeviceID; } return result; } PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { - PaDeviceID result; - + PaError result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); - if( result == paNoDevice || result < sNumInputDevices || result >= sNumDevices ) + if( result < 0 ) { + result = Pa_MaybeQueryDevices(); + if( result < 0 ) return result; result = sDefaultOutputDeviceID; } return result; } /********************************************************************** - * Initialize Host dependant part of API. - */ +** Initialize Host dependant part of API. +*/ PaError PaHost_Init( void ) { - -#if PA_TRACK_MEMORY - PRINT(("PaHost_Init: sNumAllocations = %d\n", sNumAllocations )); -#endif - #if PA_SIMULATE_UNDERFLOW PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); #endif - - - Pa_InitializeNumDevices(); - - return Pa_AllocateDevicePtrs(); + return Pa_MaybeQueryDevices(); } /********************************************************************** - * Check WAVE buffers to see if they are done. - * Fill any available output buffers and use any available - * input buffers by calling user callback. - * - * This routine will loop until: - * user callback returns !=0 OR - * all output buffers are filled OR - * past->past_StopSoon is set OR - * an error occurs when calling WMME. - * - * Returns >0 when user requests a stop, <0 on error. - * - */ -static PaError Pa_TimeSlice( internalPortAudioStream *stream ) +** Check WAVE buffers to see if they are done. +** Fill any available output buffers and use any available +** input buffers by calling user callback. +** +** This routine will loop until: +** user callback returns !=0 OR +** all output buffers are filled OR +** past->past_StopSoon is set OR +** an error occurs when calling WMME. +** +** Returns >0 when user requests a stop, <0 on error. +** +*/ +static PaError Pa_TimeSlice( internalPortAudioStream *past ) { - PaError result = paNoError; - MMRESULT mmresult; + PaError result = 0; + long bytesEmpty = 0; + long bytesFilled = 0; + long buffersEmpty = 0; + MMRESULT mresult; char *inBufPtr; char *outBufPtr; int gotInput = 0; @@ -629,18 +482,17 @@ static PaError Pa_TimeSlice( internalPortAudioStream *stream ) int i; int buffersProcessed = 0; int done = 0; - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paInternalError; - if( wmmeStreamData == NULL ) return paInternalError; - - stream->past_NumCallbacks += 1; + past->past_NumCallbacks += 1; #if PA_TRACE_RUN - AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", stream->past_NumCallbacks ); + AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks ); #endif /* JM20020118 - prevent hung thread when buffers underflow. */ /* while( !done ) /* BAD */ - while( !done && !stream->past_StopSoon ) /* GOOD */ + while( !done && !past->past_StopSoon ) /* GOOD */ { #if PA_SIMULATE_UNDERFLOW if(gUnderCallbackCounter++ == UNDER_SLEEP_AT) @@ -652,29 +504,29 @@ static PaError Pa_TimeSlice( internalPortAudioStream *stream ) /* If we are using output, then we need an empty output buffer. */ gotOutput = 0; outBufPtr = NULL; - if( stream->past_NumOutputChannels > 0 ) + if( past->past_NumOutputChannels > 0 ) { - if((wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].dwFlags & WHDR_DONE) == 0) + if((pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ].dwFlags & WHDR_DONE) == 0) { break; /* If none empty then bail and try again later. */ } else { - outBufPtr = wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].lpData; + outBufPtr = pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ].lpData; gotOutput = 1; } } /* Use an input buffer if one is available. */ gotInput = 0; inBufPtr = NULL; - if( ( stream->past_NumInputChannels > 0 ) && - (wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].dwFlags & WHDR_DONE) ) + if( ( past->past_NumInputChannels > 0 ) && + (pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ].dwFlags & WHDR_DONE) ) { - inBufPtr = wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].lpData; + inBufPtr = pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ].lpData; gotInput = 1; #if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: got input buffer at ", (int)inBufPtr ); - AddTraceMessage("Pa_TimeSlice: got input buffer # ", wmmeStreamData->currentInputBuffer ); + AddTraceMessage("Pa_TimeSlice: got input buffer # ", pahsc->pahsc_CurrentInputBuffer ); #endif } @@ -683,8 +535,8 @@ static PaError Pa_TimeSlice( internalPortAudioStream *stream ) buffersProcessed += 1; /* Each Wave buffer contains multiple user buffers so do them all now. */ /* Base Usage on time it took to process one host buffer. */ - Pa_StartUsageCalculation( stream ); - for( i=0; iuserBuffersPerHostBuffer; i++ ) + Pa_StartUsageCalculation( past ); + for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) { if( done ) { @@ -692,51 +544,51 @@ static PaError Pa_TimeSlice( internalPortAudioStream *stream ) { /* Clear remainder of wave buffer if we are waiting for stop. */ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); - memset( outBufPtr, 0, wmmeStreamData->bytesPerUserOutputBuffer ); + memset( outBufPtr, 0, pahsc->pahsc_BytesPerUserOutputBuffer ); } } else { /* Convert 16 bit native data to user data and call user routine. */ - result = Pa_CallConvertInt16( stream, (short *) inBufPtr, (short *) outBufPtr ); + result = Pa_CallConvertInt16( past, (short *) inBufPtr, (short *) outBufPtr ); if( result != 0) done = 1; } - if( gotInput ) inBufPtr += wmmeStreamData->bytesPerUserInputBuffer; - if( gotOutput) outBufPtr += wmmeStreamData->bytesPerUserOutputBuffer; + if( gotInput ) inBufPtr += pahsc->pahsc_BytesPerUserInputBuffer; + if( gotOutput) outBufPtr += pahsc->pahsc_BytesPerUserOutputBuffer; } - Pa_EndUsageCalculation( stream ); + Pa_EndUsageCalculation( past ); /* Send WAVE buffer to Wave Device to be refilled. */ if( gotInput ) { - mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, - &wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ], + mresult = waveInAddBuffer( pahsc->pahsc_HWaveIn, + &pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ], sizeof(WAVEHDR) ); - if( mmresult != MMSYSERR_NOERROR ) + if( mresult != MMSYSERR_NOERROR ) { - sPaHostError = mmresult; + sPaHostError = mresult; result = paHostError; break; } - wmmeStreamData->currentInputBuffer = (wmmeStreamData->currentInputBuffer+1 >= wmmeStreamData->numHostBuffers) ? - 0 : wmmeStreamData->currentInputBuffer+1; + pahsc->pahsc_CurrentInputBuffer = (pahsc->pahsc_CurrentInputBuffer+1 >= pahsc->pahsc_NumHostBuffers) ? + 0 : pahsc->pahsc_CurrentInputBuffer+1; } /* Write WAVE buffer to Wave Device. */ if( gotOutput ) { #if PA_TRACE_START_STOP - AddTraceMessage( "Pa_TimeSlice: writing buffer ", wmmeStreamData->currentOutputBuffer ); + AddTraceMessage( "Pa_TimeSlice: writing buffer ", pahsc->pahsc_CurrentOutputBuffer ); #endif - mmresult = waveOutWrite( wmmeStreamData->hWaveOut, - &wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ], + mresult = waveOutWrite( pahsc->pahsc_HWaveOut, + &pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ], sizeof(WAVEHDR) ); - if( mmresult != MMSYSERR_NOERROR ) + if( mresult != MMSYSERR_NOERROR ) { - sPaHostError = mmresult; + sPaHostError = mresult; result = paHostError; break; } - wmmeStreamData->currentOutputBuffer = (wmmeStreamData->currentOutputBuffer+1 >= wmmeStreamData->numHostBuffers) ? - 0 : wmmeStreamData->currentOutputBuffer+1; + pahsc->pahsc_CurrentOutputBuffer = (pahsc->pahsc_CurrentOutputBuffer+1 >= pahsc->pahsc_NumHostBuffers) ? + 0 : pahsc->pahsc_CurrentOutputBuffer+1; } } @@ -748,62 +600,62 @@ static PaError Pa_TimeSlice( internalPortAudioStream *stream ) } /*******************************************************************/ -static PaError PaHost_BackgroundManager( internalPortAudioStream *stream ) +static PaError PaHost_BackgroundManager( internalPortAudioStream *past ) { - PaError result = paNoError; + PaError result = 0; int i; - int numQueuedoutputBuffers = 0; - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + int numQueuedOutputBuffers = 0; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; /* Has someone asked us to abort by calling Pa_AbortStream()? */ - if( stream->past_StopNow ) + if( past->past_StopNow ) { - stream->past_IsActive = 0; /* Will cause thread to return. */ + past->past_IsActive = 0; /* Will cause thread to return. */ } /* Has someone asked us to stop by calling Pa_StopStream() * OR has a user callback returned '1' to indicate finished. */ - else if( stream->past_StopSoon ) + else if( past->past_StopSoon ) { /* Poll buffer and when all have played then exit thread. */ /* Count how many output buffers are queued. */ - numQueuedoutputBuffers = 0; - if( stream->past_NumOutputChannels > 0 ) + numQueuedOutputBuffers = 0; + if( past->past_NumOutputChannels > 0 ) { - for( i=0; inumHostBuffers; i++ ) + for( i=0; ipahsc_NumHostBuffers; i++ ) { - if( !( wmmeStreamData->outputBuffers[ i ].dwFlags & WHDR_DONE) ) + if( !( pahsc->pahsc_OutputBuffers[ i ].dwFlags & WHDR_DONE) ) { #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_BackgroundManager: waiting for buffer ", i ); + AddTraceMessage( "WinMMPa_OutputThreadProc: waiting for buffer ", i ); #endif - numQueuedoutputBuffers++; + numQueuedOutputBuffers++; } } } #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_BackgroundManager: numQueuedoutputBuffers ", numQueuedoutputBuffers ); + AddTraceMessage( "WinMMPa_OutputThreadProc: numQueuedOutputBuffers ", numQueuedOutputBuffers ); #endif - if( numQueuedoutputBuffers == 0 ) + if( numQueuedOutputBuffers == 0 ) { - stream->past_IsActive = 0; /* Will cause thread to return. */ + past->past_IsActive = 0; /* Will cause thread to return. */ } } else { /* Process full input buffer and fill up empty output buffers. */ - if( (result = Pa_TimeSlice( stream )) != 0) + if( (result = Pa_TimeSlice( past )) != 0) { /* User callback has asked us to stop. */ #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_BackgroundManager: TimeSlice() returned ", result ); + AddTraceMessage( "WinMMPa_OutputThreadProc: TimeSlice() returned ", result ); #endif - stream->past_StopSoon = 1; /* Request that audio play out then stop. */ + past->past_StopSoon = 1; /* Request that audio play out then stop. */ result = paNoError; } } - PaHost_UpdateStreamTime( wmmeStreamData ); + PaHost_UpdateStreamTime( pahsc ); return result; } @@ -811,57 +663,57 @@ static PaError PaHost_BackgroundManager( internalPortAudioStream *stream ) /*******************************************************************/ static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { - internalPortAudioStream *stream; - PaWMMEStreamData *wmmeStreamData; + internalPortAudioStream *past; + PaHostSoundControl *pahsc; PaError result; - - stream = (internalPortAudioStream *) dwUser; - if( stream == NULL ) return; - wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - if( wmmeStreamData == NULL ) return; - if( wmmeStreamData->ifInsideCallback ) + past = (internalPortAudioStream *) dwUser; + if( past == NULL ) return; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return; + if( pahsc->pahsc_IfInsideCallback ) { - if( wmmeStreamData->timerID != 0 ) + if( pahsc->pahsc_TimerID != 0 ) { - timeKillEvent(wmmeStreamData->timerID); /* Stop callback timer. */ - wmmeStreamData->timerID = 0; + timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */ + pahsc->pahsc_TimerID = 0; } return; } - wmmeStreamData->ifInsideCallback = 1; + pahsc->pahsc_IfInsideCallback = 1; /* Manage flags and audio processing. */ - result = PaHost_BackgroundManager( stream ); + result = PaHost_BackgroundManager( past ); if( result != paNoError ) { - stream->past_IsActive = 0; + past->past_IsActive = 0; } - wmmeStreamData->ifInsideCallback = 0; + pahsc->pahsc_IfInsideCallback = 0; } #else /* PA_USE_TIMER_CALLBACK */ /*******************************************************************/ static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) { - internalPortAudioStream *stream; - PaWMMEStreamData *wmmeStreamData; + internalPortAudioStream *past; + PaHostSoundControl *pahsc; + void *inputBuffer=NULL; HANDLE events[2]; int numEvents = 0; DWORD result = 0; DWORD waitResult; DWORD numTimeouts = 0; DWORD timeOut; - stream = (internalPortAudioStream *) pArg; - wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + past = (internalPortAudioStream *) pArg; + pahsc = (PaHostSoundControl *) past->past_DeviceData; #if PA_TRACE_START_STOP AddTraceMessage( "WinMMPa_OutputThreadProc: timeoutPeriod", timeoutPeriod ); - AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", stream->past_NumUserBuffers ); + AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", past->past_NumUserBuffers ); #endif /* Calculate timeOut as half the time it would take to play all buffers. */ - timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( stream ) / stream->past_SampleRate); + timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate); /* Get event(s) ready for wait. */ - events[numEvents++] = wmmeStreamData->bufferEvent; - if( wmmeStreamData->abortEventInited ) events[numEvents++] = wmmeStreamData->abortEvent; + events[numEvents++] = pahsc->pahsc_BufferEvent; + if( pahsc->pahsc_AbortEventInited ) events[numEvents++] = pahsc->pahsc_AbortEvent; /* Stay in this thread as long as we are "active". */ - while( stream->past_IsActive ) + while( past->past_IsActive ) { /*******************************************************************/ /******** WAIT here for an event from WMME or PA *******************/ @@ -872,21 +724,21 @@ static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) { sPaHostError = GetLastError(); result = paHostError; - stream->past_IsActive = 0; + past->past_IsActive = 0; } /* Timeout? Don't stop. Just keep polling for DONE.*/ else if( waitResult == WAIT_TIMEOUT ) { #if PA_TRACE_START_STOP - AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedoutputBuffers ); + AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedOutputBuffers ); #endif numTimeouts += 1; } /* Manage flags and audio processing. */ - result = PaHost_BackgroundManager( stream ); + result = PaHost_BackgroundManager( past ); if( result != paNoError ) { - stream->past_IsActive = 0; + past->past_IsActive = 0; } } return result; @@ -894,218 +746,210 @@ static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) #endif /*******************************************************************/ -PaError PaHost_OpenInputStream( internalPortAudioStream *stream ) +PaError PaHost_OpenInputStream( internalPortAudioStream *past ) { + MMRESULT mr; PaError result = paNoError; - MMRESULT mmresult; - PaWMMEStreamData *wmmeStreamData; + PaHostSoundControl *pahsc; int i; int inputMmId; int bytesPerInputFrame; WAVEFORMATEX wfx; - const PaDeviceInfo *deviceInfo; - - wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_InputDeviceID)); - deviceInfo = Pa_GetDeviceInfo( stream->past_InputDeviceID ); - if( deviceInfo == NULL ) return paInternalError; - - switch( deviceInfo->nativeSampleFormats ) + const PaDeviceInfo *pad; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID)); + pad = Pa_GetDeviceInfo( past->past_InputDeviceID ); + if( pad == NULL ) return paInternalError; + switch( pad->nativeSampleFormats ) { case paInt32: case paFloat32: - bytesPerInputFrame = sizeof(float) * stream->past_NumInputChannels; + bytesPerInputFrame = sizeof(float) * past->past_NumInputChannels; break; default: - bytesPerInputFrame = sizeof(short) * stream->past_NumInputChannels; + bytesPerInputFrame = sizeof(short) * past->past_NumInputChannels; break; } wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = (WORD) stream->past_NumInputChannels; - wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate; - wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * stream->past_SampleRate); + wfx.nChannels = (WORD) past->past_NumInputChannels; + wfx.nSamplesPerSec = (DWORD) past->past_SampleRate; + wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * past->past_SampleRate); wfx.nBlockAlign = (WORD)bytesPerInputFrame; - wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/stream->past_NumInputChannels) * 8); + wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/past->past_NumInputChannels) * 8); wfx.cbSize = 0; - inputMmId = PaDeviceIdToWinId( stream->past_InputDeviceID ); + inputMmId = PaDeviceIdToWinId( past->past_InputDeviceID ); #if PA_USE_TIMER_CALLBACK - mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, + mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx, 0, 0, CALLBACK_NULL ); #else - mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, - (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); + mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx, + (DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT ); #endif - if( mmresult != MMSYSERR_NOERROR ) + if( mr != MMSYSERR_NOERROR ) { ERR_RPT(("PortAudio: PaHost_OpenInputStream() failed!\n")); result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } /* Allocate an array to hold the buffer pointers. */ - wmmeStreamData->inputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */ - if( wmmeStreamData->inputBuffers == NULL ) + pahsc->pahsc_InputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ + if( pahsc->pahsc_InputBuffers == NULL ) { result = paInsufficientMemory; goto error; } /* Allocate each buffer. */ - for( i=0; inumHostBuffers; i++ ) + for( i=0; ipahsc_NumHostBuffers; i++ ) { - wmmeStreamData->inputBuffers[i].lpData = (char *)PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostInputBuffer ); /* MEM */ - if( wmmeStreamData->inputBuffers[i].lpData == NULL ) + pahsc->pahsc_InputBuffers[i].lpData = (char *)GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostInputBuffer ); /* MEM */ + if( pahsc->pahsc_InputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; goto error; } - wmmeStreamData->inputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostInputBuffer; - wmmeStreamData->inputBuffers[i].dwUser = i; - if( ( mmresult = waveInPrepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) + pahsc->pahsc_InputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostInputBuffer; + pahsc->pahsc_InputBuffers[i].dwUser = i; + if( ( mr = waveInPrepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } } return result; - error: return result; } /*******************************************************************/ -PaError PaHost_OpenOutputStream( internalPortAudioStream *stream ) +PaError PaHost_OpenOutputStream( internalPortAudioStream *past ) { + MMRESULT mr; PaError result = paNoError; - MMRESULT mmresult; - PaWMMEStreamData *wmmeStreamData; + PaHostSoundControl *pahsc; int i; int outputMmID; int bytesPerOutputFrame; WAVEFORMATEX wfx; - const PaDeviceInfo *deviceInfo; - - wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_OutputDeviceID)); - - deviceInfo = Pa_GetDeviceInfo( stream->past_OutputDeviceID ); - if( deviceInfo == NULL ) return paInternalError; - - switch( deviceInfo->nativeSampleFormats ) + const PaDeviceInfo *pad; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); + pad = Pa_GetDeviceInfo( past->past_OutputDeviceID ); + if( pad == NULL ) return paInternalError; + switch( pad->nativeSampleFormats ) { case paInt32: case paFloat32: - bytesPerOutputFrame = sizeof(float) * stream->past_NumOutputChannels; + bytesPerOutputFrame = sizeof(float) * past->past_NumOutputChannels; break; default: - bytesPerOutputFrame = sizeof(short) * stream->past_NumOutputChannels; + bytesPerOutputFrame = sizeof(short) * past->past_NumOutputChannels; break; } wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = (WORD) stream->past_NumOutputChannels; - wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate; - wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * stream->past_SampleRate); + wfx.nChannels = (WORD) past->past_NumOutputChannels; + wfx.nSamplesPerSec = (DWORD) past->past_SampleRate; + wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * past->past_SampleRate); wfx.nBlockAlign = (WORD)bytesPerOutputFrame; - wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/stream->past_NumOutputChannels) * 8); + wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/past->past_NumOutputChannels) * 8); wfx.cbSize = 0; - outputMmID = PaDeviceIdToWinId( stream->past_OutputDeviceID ); + outputMmID = PaDeviceIdToWinId( past->past_OutputDeviceID ); #if PA_USE_TIMER_CALLBACK - mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, + mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx, 0, 0, CALLBACK_NULL ); #else - wmmeStreamData->abortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); - if( wmmeStreamData->abortEvent == NULL ) + pahsc->pahsc_AbortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if( pahsc->pahsc_AbortEvent == NULL ) { result = paHostError; sPaHostError = GetLastError(); goto error; } - wmmeStreamData->abortEventInited = 1; - mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, - (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); + pahsc->pahsc_AbortEventInited = 1; + mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx, + (DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT ); #endif - if( mmresult != MMSYSERR_NOERROR ) + if( mr != MMSYSERR_NOERROR ) { ERR_RPT(("PortAudio: PaHost_OpenOutputStream() failed!\n")); result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } /* Allocate an array to hold the buffer pointers. */ - wmmeStreamData->outputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */ - if( wmmeStreamData->outputBuffers == NULL ) + pahsc->pahsc_OutputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */ + if( pahsc->pahsc_OutputBuffers == NULL ) { result = paInsufficientMemory; goto error; } /* Allocate each buffer. */ - for( i=0; inumHostBuffers; i++ ) + for( i=0; ipahsc_NumHostBuffers; i++ ) { - wmmeStreamData->outputBuffers[i].lpData = (char *) PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostOutputBuffer ); /* MEM */ - if( wmmeStreamData->outputBuffers[i].lpData == NULL ) + pahsc->pahsc_OutputBuffers[i].lpData = (char *) GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostOutputBuffer ); /* MEM */ + if( pahsc->pahsc_OutputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; goto error; } - wmmeStreamData->outputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostOutputBuffer; - wmmeStreamData->outputBuffers[i].dwUser = i; - if( (mmresult = waveOutPrepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) + pahsc->pahsc_OutputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostOutputBuffer; + pahsc->pahsc_OutputBuffers[i].dwUser = i; + if( (mr = waveOutPrepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } } return result; - error: return result; } /*******************************************************************/ -PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *stream ) +PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) { - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; - return wmmeStreamData->numHostBuffers * wmmeStreamData->framesPerHostBuffer; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer; } /******************************************************************* - * Determine number of WAVE Buffers - * and how many User Buffers we can put into each WAVE buffer. - */ -static void PaHost_CalcNumHostBuffers( internalPortAudioStream *stream ) +* Determine number of WAVE Buffers +* and how many User Buffers we can put into each WAVE buffer. +*/ +static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) { - PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; unsigned int minNumBuffers; - int minframesPerHostBuffer; - int maxframesPerHostBuffer; + int minFramesPerHostBuffer; + int maxFramesPerHostBuffer; int minTotalFrames; int userBuffersPerHostBuffer; int framesPerHostBuffer; int numHostBuffers; - /* Calculate minimum and maximum sizes based on timing and sample rate. */ - minframesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001); - minframesPerHostBuffer = (minframesPerHostBuffer + 7) & ~7; - DBUG(("PaHost_CalcNumHostBuffers: minframesPerHostBuffer = %d\n", minframesPerHostBuffer )); - maxframesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001); - maxframesPerHostBuffer = (maxframesPerHostBuffer + 7) & ~7; - DBUG(("PaHost_CalcNumHostBuffers: maxframesPerHostBuffer = %d\n", maxframesPerHostBuffer )); + minFramesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); + minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); + maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0); + maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7; + DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer )); /* Determine number of user buffers based on minimum latency. */ - minNumBuffers = Pa_GetMinNumBuffers( stream->past_FramesPerUserBuffer, stream->past_SampleRate ); - stream->past_NumUserBuffers = ( minNumBuffers > stream->past_NumUserBuffers ) ? minNumBuffers : stream->past_NumUserBuffers; - DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", stream->past_NumUserBuffers )); - minTotalFrames = stream->past_NumUserBuffers * stream->past_FramesPerUserBuffer; + minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); + past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; + DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); + minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ - if( (int) stream->past_FramesPerUserBuffer < minframesPerHostBuffer ) + if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) { userBuffersPerHostBuffer = - (minframesPerHostBuffer + stream->past_FramesPerUserBuffer - 1) / - stream->past_FramesPerUserBuffer; + (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / + past->past_FramesPerUserBuffer; } else { userBuffersPerHostBuffer = 1; } - framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* Make sure we have anough WAVE buffers. */ @@ -1114,446 +958,429 @@ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *stream ) numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; } else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) && - ((int) stream->past_FramesPerUserBuffer < (maxframesPerHostBuffer/2) ) ) + ((int) past->past_FramesPerUserBuffer < (maxFramesPerHostBuffer/2) ) ) { /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) { userBuffersPerHostBuffer += 1; - framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* If we have gone too far, back up one. */ - if( (framesPerHostBuffer > maxframesPerHostBuffer) || + if( (framesPerHostBuffer > maxFramesPerHostBuffer) || (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) ) { userBuffersPerHostBuffer -= 1; - framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; + framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; break; } } } - wmmeStreamData->userBuffersPerHostBuffer = userBuffersPerHostBuffer; - wmmeStreamData->framesPerHostBuffer = framesPerHostBuffer; - wmmeStreamData->numHostBuffers = numHostBuffers; - DBUG(("PaHost_CalcNumHostBuffers: userBuffersPerHostBuffer = %d\n", wmmeStreamData->userBuffersPerHostBuffer )); - DBUG(("PaHost_CalcNumHostBuffers: numHostBuffers = %d\n", wmmeStreamData->numHostBuffers )); - DBUG(("PaHost_CalcNumHostBuffers: framesPerHostBuffer = %d\n", wmmeStreamData->framesPerHostBuffer )); - DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", stream->past_NumUserBuffers )); + pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; + pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; + pahsc->pahsc_NumHostBuffers = numHostBuffers; + DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); + DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); + DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); } /*******************************************************************/ -PaError PaHost_OpenStream( internalPortAudioStream *stream ) +PaError PaHost_OpenStream( internalPortAudioStream *past ) { PaError result = paNoError; - PaWMMEStreamData *wmmeStreamData; - - result = PaHost_AllocateWMMEStreamData( stream ); - if( result != paNoError ) return result; - - wmmeStreamData = PaHost_GetWMMEStreamData( stream ); - - /* Figure out how user buffers fit into WAVE buffers. */ - PaHost_CalcNumHostBuffers( stream ); + PaHostSoundControl *pahsc; + /* Allocate and initialize host data. */ + pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */ + if( pahsc == NULL ) { - int msecLatency = (int) ((PaHost_GetTotalBufferFrames(stream) * 1000) / stream->past_SampleRate); - DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(stream), msecLatency )); + result = paInsufficientMemory; + goto error; } - InitializeCriticalSection( &wmmeStreamData->streamLock ); - wmmeStreamData->streamLockInited = 1; + memset( pahsc, 0, sizeof(PaHostSoundControl) ); + past->past_DeviceData = (void *) pahsc; + /* Figure out how user buffers fit into WAVE buffers. */ + PaHost_CalcNumHostBuffers( past ); + { + int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate); + DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); + } + InitializeCriticalSection( &pahsc->pahsc_StreamLock ); + pahsc->pahsc_StreamLockInited = 1; #if (PA_USE_TIMER_CALLBACK == 0) - wmmeStreamData->bufferEventInited = 0; - wmmeStreamData->bufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); - if( wmmeStreamData->bufferEvent == NULL ) + pahsc->pahsc_BufferEventInited = 0; + pahsc->pahsc_BufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( pahsc->pahsc_BufferEvent == NULL ) { result = paHostError; sPaHostError = GetLastError(); goto error; } - wmmeStreamData->bufferEventInited = 1; + pahsc->pahsc_BufferEventInited = 1; #endif /* (PA_USE_TIMER_CALLBACK == 0) */ /* ------------------ OUTPUT */ - wmmeStreamData->bytesPerUserOutputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumOutputChannels * sizeof(short); - wmmeStreamData->bytesPerHostOutputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserOutputBuffer; - if( (stream->past_OutputDeviceID != paNoDevice) && (stream->past_NumOutputChannels > 0) ) + pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels * sizeof(short); + pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer; + if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) { - result = PaHost_OpenOutputStream( stream ); + result = PaHost_OpenOutputStream( past ); if( result < 0 ) goto error; } /* ------------------ INPUT */ - wmmeStreamData->bytesPerUserInputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumInputChannels * sizeof(short); - wmmeStreamData->bytesPerHostInputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserInputBuffer; - if( (stream->past_InputDeviceID != paNoDevice) && (stream->past_NumInputChannels > 0) ) + pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels * sizeof(short); + pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer; + if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) ) { - result = PaHost_OpenInputStream( stream ); + result = PaHost_OpenInputStream( past ); if( result < 0 ) goto error; } - - Pa_InitializeCpuUsageScalar( stream ); - + /* Calculate scalar used in CPULoad calculation. */ + { + LARGE_INTEGER frequency; + if( QueryPerformanceFrequency( &frequency ) == 0 ) + { + pahsc->pahsc_InverseTicksPerHostBuffer = 0.0; + } + else + { + pahsc->pahsc_InverseTicksPerHostBuffer = past->past_SampleRate / + ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer * pahsc->pahsc_UserBuffersPerHostBuffer ); + DBUG(("pahsc_InverseTicksPerHostBuffer = %g\n", pahsc->pahsc_InverseTicksPerHostBuffer )); + } + } return result; - error: - PaHost_CloseStream( stream ); + PaHost_CloseStream( past ); return result; } /*************************************************************************/ -PaError PaHost_StartOutput( internalPortAudioStream *stream ) +PaError PaHost_StartOutput( internalPortAudioStream *past ) { + MMRESULT mr; + PaHostSoundControl *pahsc; PaError result = paNoError; - MMRESULT mmresult; int i; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); - - if( wmmeStreamData == NULL ) return paInternalError; - - if( stream->past_OutputDeviceID != paNoDevice ) + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( past->past_OutputDeviceID != paNoDevice ) { - if( (mmresult = waveOutPause( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) + if( (mr = waveOutPause( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } - for( i=0; inumHostBuffers; i++ ) + for( i=0; ipahsc_NumHostBuffers; i++ ) { - ZeroMemory( wmmeStreamData->outputBuffers[i].lpData, wmmeStreamData->outputBuffers[i].dwBufferLength ); - mmresult = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); - if( mmresult != MMSYSERR_NOERROR ) + ZeroMemory( pahsc->pahsc_OutputBuffers[i].lpData, pahsc->pahsc_OutputBuffers[i].dwBufferLength ); + mr = waveOutWrite( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) ); + if( mr != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } - stream->past_FrameCount += wmmeStreamData->framesPerHostBuffer; + past->past_FrameCount += pahsc->pahsc_FramesPerHostBuffer; } - wmmeStreamData->currentOutputBuffer = 0; - if( (mmresult = waveOutRestart( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) + pahsc->pahsc_CurrentOutputBuffer = 0; + if( (mr = waveOutRestart( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } } - + DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr)); error: - DBUG(("PaHost_StartOutput: wave returned mmresult = 0x%X.\n", mmresult)); return result; } /*************************************************************************/ -PaError PaHost_StartInput( internalPortAudioStream *internalStream ) +PaError PaHost_StartInput( internalPortAudioStream *past ) { PaError result = paNoError; - MMRESULT mmresult; + MMRESULT mr; int i; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); - - if( wmmeStreamData == NULL ) return paInternalError; - - if( internalStream->past_InputDeviceID != paNoDevice ) + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( past->past_InputDeviceID != paNoDevice ) { - for( i=0; inumHostBuffers; i++ ) + for( i=0; ipahsc_NumHostBuffers; i++ ) { - mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); - if( mmresult != MMSYSERR_NOERROR ) + mr = waveInAddBuffer( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) ); + if( mr != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } } - wmmeStreamData->currentInputBuffer = 0; - mmresult = waveInStart( wmmeStreamData->hWaveIn ); - DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult)); - if( mmresult != MMSYSERR_NOERROR ) + pahsc->pahsc_CurrentInputBuffer = 0; + mr = waveInStart( pahsc->pahsc_HWaveIn ); + DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", hr)); + if( mr != MMSYSERR_NOERROR ) { result = paHostError; - sPaHostError = mmresult; + sPaHostError = mr; goto error; } } - error: return result; } /*************************************************************************/ -PaError PaHost_StartEngine( internalPortAudioStream *stream ) +PaError PaHost_StartEngine( internalPortAudioStream *past ) { PaError result = paNoError; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; #if PA_USE_TIMER_CALLBACK int resolution; int bufsPerTimerCallback; int msecPerBuffer; #endif /* PA_USE_TIMER_CALLBACK */ - if( wmmeStreamData == NULL ) return paInternalError; - - stream->past_StopSoon = 0; - stream->past_StopNow = 0; - stream->past_IsActive = 1; - wmmeStreamData->framesPlayed = 0.0; - wmmeStreamData->lastPosition = 0; + past->past_StopSoon = 0; + past->past_StopNow = 0; + past->past_IsActive = 1; + pahsc->pahsc_FramesPlayed = 0.0; + pahsc->pahsc_LastPosition = 0; #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result ); #endif #if PA_USE_TIMER_CALLBACK /* Create timer that will wake us up so we can fill the DSound buffer. */ - bufsPerTimerCallback = wmmeStreamData->numHostBuffers/4; + bufsPerTimerCallback = pahsc->pahsc_NumHostBuffers/4; if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; msecPerBuffer = (1000 * bufsPerTimerCallback * - wmmeStreamData->userBuffersPerHostBuffer * - internalStream->past_FramesPerUserBuffer ) / (int) internalStream->past_SampleRate; + pahsc->pahsc_UserBuffersPerHostBuffer * + past->past_FramesPerUserBuffer ) / (int) past->past_SampleRate; if( msecPerBuffer < 10 ) msecPerBuffer = 10; else if( msecPerBuffer > 100 ) msecPerBuffer = 100; resolution = msecPerBuffer/4; - wmmeStreamData->timerID = timeSetEvent( msecPerBuffer, resolution, + pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback, - (DWORD) stream, TIME_PERIODIC ); - if( wmmeStreamData->timerID == 0 ) + (DWORD) past, TIME_PERIODIC ); + if( pahsc->pahsc_TimerID == 0 ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #else /* PA_USE_TIMER_CALLBACK */ - ResetEvent( wmmeStreamData->abortEvent ); + ResetEvent( pahsc->pahsc_AbortEvent ); /* Create thread that waits for audio buffers to be ready for processing. */ - wmmeStreamData->engineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, stream, 0, &wmmeStreamData->engineThreadID ); - if( wmmeStreamData->engineThread == NULL ) + pahsc->pahsc_EngineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, past, 0, &pahsc->pahsc_EngineThreadID ); + if( pahsc->pahsc_EngineThread == NULL ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StartEngine: thread ", (int) wmmeStreamData->engineThread ); + AddTraceMessage( "PaHost_StartEngine: thread ", (int) pahsc->pahsc_EngineThread ); #endif /* I used to pass the thread which was failing. I now pass GetCurrentProcess(). - * This fix could improve latency for some applications. It could also result in CPU - * starvation if the callback did too much processing. - * I also added result checks, so we might see more failures at initialization. - * Thanks to Alberto di Bene for spotting this. - */ + ** This fix could improve latency for some applications. It could also result in CPU + ** starvation if the callback did too much processing. + ** I also added result checks, so we might see more failures at initialization. + ** Thanks to Alberto di Bene for spotting this. + */ if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */ { result = paHostError; sPaHostError = GetLastError();; goto error; } - if( !SetThreadPriority( wmmeStreamData->engineThread, THREAD_PRIORITY_HIGHEST ) ) + if( !SetThreadPriority( pahsc->pahsc_EngineThread, THREAD_PRIORITY_HIGHEST ) ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #endif - error: return result; } + /*************************************************************************/ -PaError PaHost_StopEngine( internalPortAudioStream *internalStream, int abort ) +PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { int timeOut; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); - - if( wmmeStreamData == NULL ) return 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. */ - internalStream->past_StopSoon = 1; + past->past_StopSoon = 1; /* If aborting, tell background thread to stop NOW! */ - if( abort ) internalStream->past_StopNow = 1; + if( abort ) past->past_StopNow = 1; /* Calculate timeOut longer than longest time it could take to play all buffers. */ - timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( internalStream ) / internalStream->past_SampleRate); + timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate); if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; #if PA_USE_TIMER_CALLBACK - if( (internalStream->past_OutputDeviceID != paNoDevice) && - internalStream->past_IsActive && - (wmmeStreamData->timerID != 0) ) + if( (past->past_OutputDeviceID != paNoDevice) && + past->past_IsActive && + (pahsc->pahsc_TimerID != 0) ) { /* Wait for IsActive to drop. */ - while( (internalStream->past_IsActive) && (timeOut > 0) ) + while( (past->past_IsActive) && (timeOut > 0) ) { Sleep(10); timeOut -= 10; } - timeKillEvent( wmmeStreamData->timerID ); /* Stop callback timer. */ - wmmeStreamData->timerID = 0; + timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */ + pahsc->pahsc_TimerID = 0; } #else /* PA_USE_TIMER_CALLBACK */ #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StopEngine: thread ", (int) wmmeStreamData->engineThread ); + AddTraceMessage( "PaHost_StopEngine: thread ", (int) pahsc->pahsc_EngineThread ); #endif - if( (internalStream->past_OutputDeviceID != paNoDevice) && - (internalStream->past_IsActive) && - (wmmeStreamData->engineThread != NULL) ) + if( (past->past_OutputDeviceID != paNoDevice) && + (past->past_IsActive) && + (pahsc->pahsc_EngineThread != NULL) ) { DWORD got; /* Tell background thread to stop generating more data and to let current data play out. */ DBUG(("PaHost_StopEngine: waiting for background thread.\n")); - got = WaitForSingleObject( wmmeStreamData->engineThread, timeOut ); + got = WaitForSingleObject( pahsc->pahsc_EngineThread, timeOut ); if( got == WAIT_TIMEOUT ) { ERR_RPT(("PaHost_StopEngine: timed out while waiting for background thread to finish.\n")); return paTimedOut; } - CloseHandle( wmmeStreamData->engineThread ); - wmmeStreamData->engineThread = NULL; + CloseHandle( pahsc->pahsc_EngineThread ); + pahsc->pahsc_EngineThread = NULL; } #endif /* PA_USE_TIMER_CALLBACK */ - internalStream->past_IsActive = 0; + past->past_IsActive = 0; return paNoError; } /*************************************************************************/ -PaError PaHost_StopInput( internalPortAudioStream *stream, int abort ) +PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { - MMRESULT mmresult; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); - - if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ - (void) abort; /* unused parameter */ - - if( wmmeStreamData->hWaveIn != NULL ) + MMRESULT mr; + PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; + if( pahsc->pahsc_HWaveIn != NULL ) { - mmresult = waveInReset( wmmeStreamData->hWaveIn ); - if( mmresult != MMSYSERR_NOERROR ) + mr = waveInReset( pahsc->pahsc_HWaveIn ); + if( mr != MMSYSERR_NOERROR ) { - sPaHostError = mmresult; + sPaHostError = mr; return paHostError; } } return paNoError; } /*************************************************************************/ -PaError PaHost_StopOutput( internalPortAudioStream *internalStream, int abort ) +PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { - MMRESULT mmresult; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); - - if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ - (void) abort; /* unused parameter */ - + MMRESULT mr; + PaHostSoundControl *pahsc; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; + (void) abort; #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_StopOutput: hWaveOut ", (int) wmmeStreamData->hWaveOut ); + AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); #endif - if( wmmeStreamData->hWaveOut != NULL ) + if( pahsc->pahsc_HWaveOut != NULL ) { - mmresult = waveOutReset( wmmeStreamData->hWaveOut ); - if( mmresult != MMSYSERR_NOERROR ) + mr = waveOutReset( pahsc->pahsc_HWaveOut ); + if( mr != MMSYSERR_NOERROR ) { - sPaHostError = mmresult; + sPaHostError = mr; return paHostError; } } return paNoError; } /*******************************************************************/ -PaError PaHost_CloseStream( internalPortAudioStream *stream ) +PaError PaHost_CloseStream( internalPortAudioStream *past ) { - int i; - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); - - if( stream == NULL ) return paBadStreamPtr; - if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return no error? */ - + int i; + PaHostSoundControl *pahsc; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paNoError; #if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_CloseStream: hWaveOut ", (int) wmmeStreamData->hWaveOut ); + AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); #endif /* Free data and device for output. */ - if( wmmeStreamData->hWaveOut ) + if( pahsc->pahsc_HWaveOut ) { - if( wmmeStreamData->outputBuffers ) + if( pahsc->pahsc_OutputBuffers ) { - for( i=0; inumHostBuffers; i++ ) + for( i=0; ipahsc_NumHostBuffers; i++ ) { - waveOutUnprepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); - PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers[i].lpData ); /* MEM */ + waveOutUnprepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) ); + GlobalFree( pahsc->pahsc_OutputBuffers[i].lpData ); /* MEM */ } - PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers ); /* MEM */ + GlobalFree( pahsc->pahsc_OutputBuffers ); /* MEM */ } - waveOutClose( wmmeStreamData->hWaveOut ); + waveOutClose( pahsc->pahsc_HWaveOut ); } /* Free data and device for input. */ - if( wmmeStreamData->hWaveIn ) + if( pahsc->pahsc_HWaveIn ) { - if( wmmeStreamData->inputBuffers ) + if( pahsc->pahsc_InputBuffers ) { - for( i=0; inumHostBuffers; i++ ) + for( i=0; ipahsc_NumHostBuffers; i++ ) { - waveInUnprepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); - PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers[i].lpData ); /* MEM */ + waveInUnprepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) ); + GlobalFree( pahsc->pahsc_InputBuffers[i].lpData ); /* MEM */ } - PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers ); /* MEM */ + GlobalFree( pahsc->pahsc_InputBuffers ); /* MEM */ } - waveInClose( wmmeStreamData->hWaveIn ); + waveInClose( pahsc->pahsc_HWaveIn ); } #if (PA_USE_TIMER_CALLBACK == 0) - if( wmmeStreamData->abortEventInited ) CloseHandle( wmmeStreamData->abortEvent ); - if( wmmeStreamData->bufferEventInited ) CloseHandle( wmmeStreamData->bufferEvent ); + if( pahsc->pahsc_AbortEventInited ) CloseHandle( pahsc->pahsc_AbortEvent ); + if( pahsc->pahsc_BufferEventInited ) CloseHandle( pahsc->pahsc_BufferEvent ); #endif - if( wmmeStreamData->streamLockInited ) - DeleteCriticalSection( &wmmeStreamData->streamLock ); - - PaHost_FreeWMMEStreamData( stream ); - + if( pahsc->pahsc_StreamLockInited ) + DeleteCriticalSection( &pahsc->pahsc_StreamLock ); + PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */ + past->past_DeviceData = NULL; return paNoError; } /************************************************************************* - * 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 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. - */ +** 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 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. +*/ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { char envbuf[PA_ENV_BUF_SIZE]; + DWORD hostVersion; DWORD hresult; int minLatencyMsec = 0; double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; int minBuffers; - /* Let user determine minimal latency by setting environment variable. */ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { - minLatencyMsec = atoi( envbuf ); /* REVIEW: will we crash if the environment variable contains some nasty value? */ + minLatencyMsec = atoi( envbuf ); } else { - /* Set minimal latency based on whether NT or other OS. + /* Set minimal latency based on whether NT or Win95. * NT has higher latency. */ - OSVERSIONINFO osvi; - osvi.dwOSVersionInfoSize = sizeof( osvi ); - GetVersionEx( &osvi ); - DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); - DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); - DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); - /* Check for NT */ - if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) - { - minLatencyMsec = PA_WIN_NT_LATENCY; - } - else if(osvi.dwMajorVersion >= 5) - { - minLatencyMsec = PA_WIN_WDM_LATENCY; - } - else - { - minLatencyMsec = PA_WIN_9X_LATENCY; - } + hostVersion = GetVersion(); + /* High bit clear if NT */ + minLatencyMsec = ( (hostVersion & 0x80000000) == 0 ) ? PA_WIN_NT_LATENCY : PA_WIN_9X_LATENCY ; #if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); #endif @@ -1565,12 +1392,11 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) return minBuffers; } /************************************************************************* - * Cleanup device info. - */ +** Cleanup device info. +*/ PaError PaHost_Term( void ) { int i; - if( sNumDevices > 0 ) { if( sDevicePtrs != NULL ) @@ -1579,21 +1405,16 @@ PaError PaHost_Term( void ) { if( sDevicePtrs[i] != NULL ) { - PaHost_FreeTrackedMemory( (char*)sDevicePtrs[i]->name ); /* MEM */ - PaHost_FreeTrackedMemory( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */ - PaHost_FreeTrackedMemory( sDevicePtrs[i] ); /* MEM */ + GlobalFree( (char*)sDevicePtrs[i]->name ); /* MEM */ + GlobalFree( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */ + GlobalFree( sDevicePtrs[i] ); /* MEM */ } } - PaHost_FreeTrackedMemory( sDevicePtrs ); /* MEM */ + GlobalFree( sDevicePtrs ); /* MEM */ sDevicePtrs = NULL; } sNumDevices = 0; } - -#if PA_TRACK_MEMORY - PRINT(("PaHost_Term: sNumAllocations = %d\n", sNumAllocations )); -#endif - return paNoError; } /*************************************************************************/ @@ -1602,7 +1423,6 @@ void Pa_Sleep( long msec ) Sleep( msec ); } /************************************************************************* -FIXME: the following memory allocation routines should not be declared here * 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. @@ -1611,7 +1431,8 @@ FIXME: the following memory allocation routines should not be declared here */ void *PaHost_AllocateFastMemory( long numBytes ) { - return PaHost_AllocateTrackedMemory( numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */ + void *addr = GlobalAlloc( GPTR, numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */ + return addr; } /************************************************************************* * Free memory that could be accessed in real-time. @@ -1619,89 +1440,54 @@ void *PaHost_AllocateFastMemory( long numBytes ) */ void PaHost_FreeFastMemory( void *addr, long numBytes ) { - (void) numBytes; /* unused parameter */ - - PaHost_FreeTrackedMemory( addr ); /* MEM */ + if( addr != NULL ) GlobalFree( addr ); /* MEM */ } - -/************************************************************************* - * Track memory allocations to avoid leaks. - */ -static void *PaHost_AllocateTrackedMemory( long numBytes ) -{ - void *result = GlobalAlloc( GPTR, numBytes ); /* MEM */ - -#if PA_TRACK_MEMORY - if( result != NULL ) sNumAllocations += 1; -#endif - return result; -} - -static void PaHost_FreeTrackedMemory( void *addr ) -{ - if( addr != NULL ) - { - GlobalFree( addr ); /* MEM */ -#if PA_TRACK_MEMORY - sNumAllocations -= 1; -#endif - } -} - /***********************************************************************/ -PaError PaHost_StreamActive( internalPortAudioStream *internalStream ) +PaError PaHost_StreamActive( internalPortAudioStream *past ) { - if( internalStream == NULL ) return paBadStreamPtr; - - return (PaError) internalStream->past_IsActive; + PaHostSoundControl *pahsc; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + if( pahsc == NULL ) return paInternalError; + return (PaError) past->past_IsActive; } /************************************************************************* * This must be called periodically because mmtime.u.sample * is a DWORD and can wrap and lose sync after a few hours. */ -static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ) +static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc ) { - MMRESULT mmresult; + MMRESULT mr; MMTIME mmtime; mmtime.wType = TIME_SAMPLES; - - if( wmmeStreamData->hWaveOut != NULL ) + if( pahsc->pahsc_HWaveOut != NULL ) { - mmresult = waveOutGetPosition( wmmeStreamData->hWaveOut, &mmtime, sizeof(mmtime) ); + mr = waveOutGetPosition( pahsc->pahsc_HWaveOut, &mmtime, sizeof(mmtime) ); } else { - mmresult = waveInGetPosition( wmmeStreamData->hWaveIn, &mmtime, sizeof(mmtime) ); + mr = waveInGetPosition( pahsc->pahsc_HWaveIn, &mmtime, sizeof(mmtime) ); } - - if( mmresult != MMSYSERR_NOERROR ) + if( mr != MMSYSERR_NOERROR ) { - sPaHostError = mmresult; + sPaHostError = mr; return paHostError; } - - /* This data has two variables and is shared by foreground and background. - * So we need to make it thread safe. */ - EnterCriticalSection( &wmmeStreamData->streamLock ); - wmmeStreamData->framesPlayed += ((long)mmtime.u.sample) - wmmeStreamData->lastPosition; - wmmeStreamData->lastPosition = (long)mmtime.u.sample; - LeaveCriticalSection( &wmmeStreamData->streamLock ); - + /* This data has two variables and is shared by foreground and background. */ + /* So we need to make it thread safe. */ + EnterCriticalSection( &pahsc->pahsc_StreamLock ); + pahsc->pahsc_FramesPlayed += ((long)mmtime.u.sample) - pahsc->pahsc_LastPosition; + pahsc->pahsc_LastPosition = (long)mmtime.u.sample; + LeaveCriticalSection( &pahsc->pahsc_StreamLock ); return paNoError; } /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { - internalPortAudioStream *internalStream = PaHost_GetStreamRepresentation( stream ); - PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); - - if( internalStream == NULL ) return paBadStreamPtr; - if( wmmeStreamData == NULL ) return paInternalError; - - PaHost_UpdateStreamTime( wmmeStreamData ); - return wmmeStreamData->framesPlayed; + PaHostSoundControl *pahsc; + internalPortAudioStream *past = (internalPortAudioStream *) stream; + if( past == NULL ) return paBadStreamPtr; + pahsc = (PaHostSoundControl *) past->past_DeviceData; + PaHost_UpdateStreamTime( pahsc ); + return pahsc->pahsc_FramesPlayed; } -/*************************************************************************/ - - - diff --git a/pablio/test_rw.c b/pablio/test_rw.c index 7f7e886..245e19c 100644 --- a/pablio/test_rw.c +++ b/pablio/test_rw.c @@ -44,10 +44,9 @@ ** full duplex audio (simultaneous record and playback). ** And some only support full duplex at lower sample rates. */ -#define SAMPLE_RATE (44100) -#define NUM_SECONDS (5) -#define SAMPLES_PER_FRAME (2) -#define FRAMES_PER_BLOCK (64) +#define SAMPLE_RATE (22050) +#define NUM_SECONDS (15) +#define SAMPLES_PER_FRAME (2) /* Select whether we will use floats or shorts. */ #if 1 @@ -63,7 +62,7 @@ int main(void); int main(void) { int i; - SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK]; + SAMPLE samples[SAMPLES_PER_FRAME]; PaError err; PABLIO_Stream *aStream; @@ -76,12 +75,13 @@ int main(void) if( err != paNoError ) goto error; /* Process samples in the foreground. */ - for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ ) { - /* Read one block of data into sample array from audio input. */ - ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK ); - /* Write that same block of data to output. */ - WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK ); + /* Read one frame of data into sample array from audio input. */ + ReadAudioStream( aStream, samples, 1 ); + /* Write that same frame of data to output. */ + /* samples[1] = (i&256) * (1.0f/256.0f); /* sawtooth */ + WriteAudioStream( aStream, samples, 1 ); } CloseAudioStream( aStream ); diff --git a/testcvs/changeme.txt b/testcvs/changeme.txt deleted file mode 100644 index 3a69b98..0000000 --- a/testcvs/changeme.txt +++ /dev/null @@ -1,9 +0,0 @@ -This is just a dopy little file used to test the CVS repository. -Feel free to trash this file. -Minor change. -Another tweak. -philburk tweak -stephane test -Phil changed this again on 2/21/02. Yawn... -pieter test (MacCVS Pro 2.5b2) -phil says hi diff --git a/testcvs/stuff/info.txt b/testcvs/stuff/info.txt deleted file mode 100644 index d557202..0000000 --- a/testcvs/stuff/info.txt +++ /dev/null @@ -1 +0,0 @@ -interesting info From c1e1d067d2f6b0fe184eae7ebf1fcb7b2d5ff5c7 Mon Sep 17 00:00:00 2001 From: bjornroche Date: Thu, 20 Mar 2008 14:24:39 +0000 Subject: [PATCH 105/814] moved trunk into place --- COMPILING.DARWIN | 1 + Doxyfile | 239 + LICENSE.txt | 81 + Makefile.in | 214 + README.txt | 98 + SConstruct | 197 + aclocal.m4 | 6627 +++++++++++++++ bindings/cpp/AUTHORS | 0 bindings/cpp/COPYING | 31 + bindings/cpp/ChangeLog | 178 + bindings/cpp/INSTALL | 236 + bindings/cpp/Makefile.am | 7 + bindings/cpp/Makefile.in | 642 ++ bindings/cpp/NEWS | 0 bindings/cpp/README | 0 bindings/cpp/SConscript | 65 + bindings/cpp/aclocal.m4 | 7336 +++++++++++++++++ bindings/cpp/bin/Makefile.am | 9 + bindings/cpp/bin/Makefile.in | 470 ++ bindings/cpp/build/gnu/Makefile.in | 106 + bindings/cpp/build/gnu/OUT_OF_DATE | 0 bindings/cpp/build/gnu/aclocal.m4 | 57 + bindings/cpp/build/gnu/config.guess | Bin 0 -> 38293 bytes bindings/cpp/build/gnu/config.sub | Bin 0 -> 30339 bytes bindings/cpp/build/gnu/configure | Bin 0 -> 126971 bytes bindings/cpp/build/gnu/configure.ac | 214 + bindings/cpp/build/gnu/install-sh | Bin 0 -> 5598 bytes bindings/cpp/build/vc6/devs_example.dsp | 248 + bindings/cpp/build/vc6/devs_example.dsw | 44 + bindings/cpp/build/vc6/sine_example.dsp | 252 + bindings/cpp/build/vc6/sine_example.dsw | 44 + bindings/cpp/build/vc6/static_library.dsp | 395 + bindings/cpp/build/vc6/static_library.dsw | 29 + bindings/cpp/build/vc7/OUT_OF_DATE | 0 bindings/cpp/build/vc7_1/devs_example.sln | 30 + bindings/cpp/build/vc7_1/devs_example.vcproj | 195 + bindings/cpp/build/vc7_1/sine_example.sln | 30 + bindings/cpp/build/vc7_1/sine_example.vcproj | 327 + bindings/cpp/build/vc7_1/static_library.sln | 21 + .../cpp/build/vc7_1/static_library.vcproj | 218 + bindings/cpp/configure | Bin 0 -> 702299 bytes bindings/cpp/configure.ac | 54 + bindings/cpp/doc/Makefile.am | 5 + bindings/cpp/doc/Makefile.in | 326 + bindings/cpp/doc/README | 34 + bindings/cpp/doc/config.doxy | 211 + bindings/cpp/doc/config.doxy.linux | 210 + bindings/cpp/example/devs.cxx | 177 + bindings/cpp/example/sine.cxx | 137 + bindings/cpp/include/Makefile.am | 22 + bindings/cpp/include/Makefile.in | 423 + .../portaudiocpp/AsioDeviceAdapter.hxx | 44 + .../cpp/include/portaudiocpp/AutoSystem.hxx | 62 + .../include/portaudiocpp/BlockingStream.hxx | 45 + .../portaudiocpp/CFunCallbackStream.hxx | 49 + .../portaudiocpp/CallbackInterface.hxx | 45 + .../include/portaudiocpp/CallbackStream.hxx | 40 + .../portaudiocpp/CppFunCallbackStream.hxx | 86 + bindings/cpp/include/portaudiocpp/Device.hxx | 91 + .../DirectionSpecificStreamParameters.hxx | 77 + .../cpp/include/portaudiocpp/Exception.hxx | 108 + bindings/cpp/include/portaudiocpp/HostApi.hxx | 76 + .../portaudiocpp/InterfaceCallbackStream.hxx | 49 + .../portaudiocpp/MemFunCallbackStream.hxx | 107 + .../cpp/include/portaudiocpp/PortAudioCpp.hxx | 109 + .../include/portaudiocpp/SampleDataFormat.hxx | 35 + bindings/cpp/include/portaudiocpp/Stream.hxx | 82 + .../include/portaudiocpp/StreamParameters.hxx | 77 + bindings/cpp/include/portaudiocpp/System.hxx | 107 + .../portaudiocpp/SystemDeviceIterator.hxx | 66 + .../portaudiocpp/SystemHostApiIterator.hxx | 61 + bindings/cpp/lib/Makefile.am | 26 + bindings/cpp/lib/Makefile.in | 615 ++ bindings/cpp/portaudiocpp.pc.in | 12 + .../source/portaudiocpp/AsioDeviceAdapter.cxx | 83 + .../source/portaudiocpp/BlockingStream.cxx | 100 + .../portaudiocpp/CFunCallbackStream.cxx | 41 + .../source/portaudiocpp/CallbackInterface.cxx | 25 + .../source/portaudiocpp/CallbackStream.cxx | 20 + .../portaudiocpp/CppFunCallbackStream.cxx | 81 + bindings/cpp/source/portaudiocpp/Device.cxx | 168 + .../DirectionSpecificStreamParameters.cxx | 163 + .../cpp/source/portaudiocpp/Exception.cxx | 123 + bindings/cpp/source/portaudiocpp/HostApi.cxx | 121 + .../portaudiocpp/InterfaceCallbackStream.cxx | 45 + .../portaudiocpp/MemFunCallbackStream.cxx | 4 + bindings/cpp/source/portaudiocpp/Stream.cxx | 195 + .../source/portaudiocpp/StreamParameters.cxx | 165 + bindings/cpp/source/portaudiocpp/System.cxx | 308 + .../portaudiocpp/SystemDeviceIterator.cxx | 60 + .../portaudiocpp/SystemHostApiIterator.cxx | 59 + build/dev-cpp/Makefile-dll | 78 + build/dev-cpp/Makefile-static | 75 + build/dev-cpp/portaudio-dll.dev | 209 + build/dev-cpp/portaudio-static.dev | 209 + build/dev-cpp/readme.txt | 23 + build/msvc/portaudio.def | 43 + build/msvc/portaudio.dsp | 269 + build/msvc/portaudio.dsw | 29 + build/msvc/portaudio.sln | 26 + build/msvc/portaudio.vcproj | 1512 ++++ build/msvc/readme.txt | 80 + build/scons/SConscript_common | 30 + build/scons/SConscript_opts | 91 + config.guess | Bin 0 -> 41362 bytes config.sub | Bin 0 -> 29973 bytes configure | Bin 0 -> 739337 bytes configure.in | 362 + depcomp | Bin 0 -> 15936 bytes doc/src/license.dox | 38 + doc/src/mainpage.dox | 44 + doc/src/srcguide.dox | 43 + doc/utils/checkfiledocs.py | 77 + fixdir.bat | 19 + fixfile.bat | 7 + include/pa_asio.h | 130 + include/pa_jack.h | 76 + include/pa_linux_alsa.h | 94 + include/pa_mac_core.h | 176 + include/pa_win_ds.h | 101 + include/pa_win_waveformat.h | 181 + include/pa_win_wmme.h | 177 + include/portaudio.h | 1134 +++ index.html | 105 + install-sh | Bin 0 -> 5598 bytes ltmain.sh | 6971 ++++++++++++++++ missing | Bin 0 -> 11014 bytes pablio/README.txt | 45 + pablio/pablio.c | 314 + pablio/pablio.def | 35 + pablio/pablio.h | 116 + pablio/test_rw.c | 105 + pablio/test_rw_echo.c | 129 + pablio/test_w_saw.c | 114 + pablio/test_w_saw8.c | 112 + portaudio-2.0.pc.in | 12 + src/SConscript | 219 + src/common/pa_allocation.c | 243 + src/common/pa_allocation.h | 104 + src/common/pa_converters.c | 1935 +++++ src/common/pa_converters.h | 263 + src/common/pa_cpuload.c | 105 + src/common/pa_cpuload.h | 72 + src/common/pa_debugprint.c | 107 + src/common/pa_debugprint.h | 149 + src/common/pa_dither.c | 213 + src/common/pa_dither.h | 100 + src/common/pa_endianness.h | 145 + src/common/pa_front.c | 1765 ++++ src/common/pa_hostapi.h | 259 + src/common/pa_memorybarrier.h | 123 + src/common/pa_process.c | 1772 ++++ src/common/pa_process.h | 750 ++ src/common/pa_ringbuffer.c | 227 + src/common/pa_ringbuffer.h | 218 + src/common/pa_skeleton.c | 818 ++ src/common/pa_stream.c | 150 + src/common/pa_stream.h | 205 + src/common/pa_trace.c | 97 + src/common/pa_trace.h | 101 + src/common/pa_types.h | 107 + src/common/pa_util.h | 162 + src/hostapi/alsa/pa_linux_alsa.c | 3586 ++++++++ src/hostapi/asihpi/pa_linux_asihpi.c | 2942 +++++++ src/hostapi/asio/ASIO-README.txt | 140 + src/hostapi/asio/Callback_adaptation_.pdf | Bin 0 -> 50527 bytes src/hostapi/asio/Pa_ASIO.pdf | Bin 0 -> 50778 bytes src/hostapi/asio/iasiothiscallresolver.cpp | 563 ++ src/hostapi/asio/iasiothiscallresolver.h | 197 + src/hostapi/asio/pa_asio.cpp | 3965 +++++++++ src/hostapi/coreaudio/notes.txt | 196 + src/hostapi/coreaudio/pa_mac_core.c | 2343 ++++++ src/hostapi/coreaudio/pa_mac_core_blocking.c | 592 ++ src/hostapi/coreaudio/pa_mac_core_blocking.h | 136 + src/hostapi/coreaudio/pa_mac_core_internal.h | 164 + src/hostapi/coreaudio/pa_mac_core_old.c | 913 ++ src/hostapi/coreaudio/pa_mac_core_utilities.c | 738 ++ src/hostapi/coreaudio/pa_mac_core_utilities.h | 230 + src/hostapi/dsound/pa_win_ds.c | 2525 ++++++ src/hostapi/dsound/pa_win_ds_dynlink.c | 180 + src/hostapi/dsound/pa_win_ds_dynlink.h | 95 + src/hostapi/jack/pa_jack.c | 1761 ++++ src/hostapi/oss/low_latency_tip.txt | Bin 0 -> 3111 bytes src/hostapi/oss/pa_unix_oss.c | 1985 +++++ src/hostapi/oss/recplay.c | 114 + src/hostapi/wasapi/pa_win_wasapi.cpp | 1911 +++++ src/hostapi/wdmks/pa_win_wdmks.c | 3283 ++++++++ src/hostapi/wdmks/readme.txt | 82 + src/hostapi/wmme/pa_win_wmme.c | 3902 +++++++++ src/os/unix/pa_unix_hostapis.c | 92 + src/os/unix/pa_unix_util.c | 666 ++ src/os/unix/pa_unix_util.h | 224 + src/os/win/pa_win_hostapis.c | 100 + src/os/win/pa_win_util.c | 147 + src/os/win/pa_win_waveformat.c | 159 + src/os/win/pa_win_wdmks_utils.c | 260 + src/os/win/pa_win_wdmks_utils.h | 65 + src/os/win/pa_x86_plain_converters.c | 1219 +++ src/os/win/pa_x86_plain_converters.h | 60 + test/README.txt | 60 + test/debug_convert.c | 138 + test/debug_dither_calc.c | 62 + test/debug_dual.c | 190 + test/debug_multi_in.c | 186 + test/debug_multi_out.c | 151 + test/debug_record.c | 346 + test/debug_record_reuse.c | 358 + test/debug_sine.c | 199 + test/debug_sine_amp.c | 164 + test/debug_sine_formats.c | 209 + test/debug_srate.c | 272 + test/debug_test1.c | 114 + test/pa_devs.c | 238 + test/pa_fuzz.c | 183 + test/pa_minlat.c | 194 + test/paqa_devs.c | 355 + test/paqa_errs.c | 400 + test/patest1.c | 208 + test/patest_buffer.c | 206 + test/patest_callbackstop.c | 252 + test/patest_clip.c | 190 + test/patest_converters.c | 392 + test/patest_dither.c | 190 + test/patest_dsound_surround.c | 205 + test/patest_hang.c | 164 + test/patest_in_overflow.c | 236 + test/patest_latency.c | 193 + test/patest_leftright.c | 185 + test/patest_longsine.c | 151 + test/patest_many.c | 210 + test/patest_maxsines.c | 216 + test/patest_mono.c | 155 + test/patest_mono_asio_channel_select.c | 166 + test/patest_multi_sine.c | 205 + test/patest_out_underflow.c | 229 + test/patest_pink.c | 280 + test/patest_prime.c | 234 + test/patest_read_record.c | 244 + test/patest_read_write_wire.c | 215 + test/patest_record.c | 352 + test/patest_ringmix.c | 86 + test/patest_saw.c | 133 + test/patest_sine.c | 176 + test/patest_sine8.c | 225 + test/patest_sine_channelmaps.c | 190 + test/patest_sine_formats.c | 203 + test/patest_sine_time.c | 219 + test/patest_start_stop.c | 172 + test/patest_stop.c | 324 + test/patest_stop_playout.c | 439 + test/patest_sync.c | 271 + test/patest_timing.c | 173 + test/patest_toomanysines.c | 185 + test/patest_two_rates.c | 178 + test/patest_underflow.c | 162 + test/patest_wire.c | 300 + test/patest_wmme_surround.c | 206 + test/patest_write_sine.c | 159 + test/patest_write_stop.c | 165 + testcvs/changeme.txt | 8 + 260 files changed, 96276 insertions(+) create mode 100644 COMPILING.DARWIN create mode 100644 Doxyfile create mode 100644 LICENSE.txt create mode 100644 Makefile.in create mode 100644 README.txt create mode 100644 SConstruct create mode 100644 aclocal.m4 create mode 100644 bindings/cpp/AUTHORS create mode 100644 bindings/cpp/COPYING create mode 100644 bindings/cpp/ChangeLog create mode 100644 bindings/cpp/INSTALL create mode 100644 bindings/cpp/Makefile.am create mode 100644 bindings/cpp/Makefile.in create mode 100644 bindings/cpp/NEWS create mode 100644 bindings/cpp/README create mode 100644 bindings/cpp/SConscript create mode 100644 bindings/cpp/aclocal.m4 create mode 100644 bindings/cpp/bin/Makefile.am create mode 100644 bindings/cpp/bin/Makefile.in create mode 100644 bindings/cpp/build/gnu/Makefile.in create mode 100644 bindings/cpp/build/gnu/OUT_OF_DATE create mode 100644 bindings/cpp/build/gnu/aclocal.m4 create mode 100644 bindings/cpp/build/gnu/config.guess create mode 100644 bindings/cpp/build/gnu/config.sub create mode 100644 bindings/cpp/build/gnu/configure create mode 100644 bindings/cpp/build/gnu/configure.ac create mode 100644 bindings/cpp/build/gnu/install-sh create mode 100644 bindings/cpp/build/vc6/devs_example.dsp create mode 100644 bindings/cpp/build/vc6/devs_example.dsw create mode 100644 bindings/cpp/build/vc6/sine_example.dsp create mode 100644 bindings/cpp/build/vc6/sine_example.dsw create mode 100644 bindings/cpp/build/vc6/static_library.dsp create mode 100644 bindings/cpp/build/vc6/static_library.dsw create mode 100644 bindings/cpp/build/vc7/OUT_OF_DATE create mode 100644 bindings/cpp/build/vc7_1/devs_example.sln create mode 100644 bindings/cpp/build/vc7_1/devs_example.vcproj create mode 100644 bindings/cpp/build/vc7_1/sine_example.sln create mode 100644 bindings/cpp/build/vc7_1/sine_example.vcproj create mode 100644 bindings/cpp/build/vc7_1/static_library.sln create mode 100644 bindings/cpp/build/vc7_1/static_library.vcproj create mode 100755 bindings/cpp/configure create mode 100644 bindings/cpp/configure.ac create mode 100644 bindings/cpp/doc/Makefile.am create mode 100644 bindings/cpp/doc/Makefile.in create mode 100644 bindings/cpp/doc/README create mode 100644 bindings/cpp/doc/config.doxy create mode 100644 bindings/cpp/doc/config.doxy.linux create mode 100644 bindings/cpp/example/devs.cxx create mode 100644 bindings/cpp/example/sine.cxx create mode 100644 bindings/cpp/include/Makefile.am create mode 100644 bindings/cpp/include/Makefile.in create mode 100644 bindings/cpp/include/portaudiocpp/AsioDeviceAdapter.hxx create mode 100644 bindings/cpp/include/portaudiocpp/AutoSystem.hxx create mode 100644 bindings/cpp/include/portaudiocpp/BlockingStream.hxx create mode 100644 bindings/cpp/include/portaudiocpp/CFunCallbackStream.hxx create mode 100644 bindings/cpp/include/portaudiocpp/CallbackInterface.hxx create mode 100644 bindings/cpp/include/portaudiocpp/CallbackStream.hxx create mode 100644 bindings/cpp/include/portaudiocpp/CppFunCallbackStream.hxx create mode 100644 bindings/cpp/include/portaudiocpp/Device.hxx create mode 100644 bindings/cpp/include/portaudiocpp/DirectionSpecificStreamParameters.hxx create mode 100644 bindings/cpp/include/portaudiocpp/Exception.hxx create mode 100644 bindings/cpp/include/portaudiocpp/HostApi.hxx create mode 100644 bindings/cpp/include/portaudiocpp/InterfaceCallbackStream.hxx create mode 100644 bindings/cpp/include/portaudiocpp/MemFunCallbackStream.hxx create mode 100644 bindings/cpp/include/portaudiocpp/PortAudioCpp.hxx create mode 100644 bindings/cpp/include/portaudiocpp/SampleDataFormat.hxx create mode 100644 bindings/cpp/include/portaudiocpp/Stream.hxx create mode 100644 bindings/cpp/include/portaudiocpp/StreamParameters.hxx create mode 100644 bindings/cpp/include/portaudiocpp/System.hxx create mode 100644 bindings/cpp/include/portaudiocpp/SystemDeviceIterator.hxx create mode 100644 bindings/cpp/include/portaudiocpp/SystemHostApiIterator.hxx create mode 100644 bindings/cpp/lib/Makefile.am create mode 100644 bindings/cpp/lib/Makefile.in create mode 100644 bindings/cpp/portaudiocpp.pc.in create mode 100644 bindings/cpp/source/portaudiocpp/AsioDeviceAdapter.cxx create mode 100644 bindings/cpp/source/portaudiocpp/BlockingStream.cxx create mode 100644 bindings/cpp/source/portaudiocpp/CFunCallbackStream.cxx create mode 100644 bindings/cpp/source/portaudiocpp/CallbackInterface.cxx create mode 100644 bindings/cpp/source/portaudiocpp/CallbackStream.cxx create mode 100644 bindings/cpp/source/portaudiocpp/CppFunCallbackStream.cxx create mode 100644 bindings/cpp/source/portaudiocpp/Device.cxx create mode 100644 bindings/cpp/source/portaudiocpp/DirectionSpecificStreamParameters.cxx create mode 100644 bindings/cpp/source/portaudiocpp/Exception.cxx create mode 100644 bindings/cpp/source/portaudiocpp/HostApi.cxx create mode 100644 bindings/cpp/source/portaudiocpp/InterfaceCallbackStream.cxx create mode 100644 bindings/cpp/source/portaudiocpp/MemFunCallbackStream.cxx create mode 100644 bindings/cpp/source/portaudiocpp/Stream.cxx create mode 100644 bindings/cpp/source/portaudiocpp/StreamParameters.cxx create mode 100644 bindings/cpp/source/portaudiocpp/System.cxx create mode 100644 bindings/cpp/source/portaudiocpp/SystemDeviceIterator.cxx create mode 100644 bindings/cpp/source/portaudiocpp/SystemHostApiIterator.cxx create mode 100644 build/dev-cpp/Makefile-dll create mode 100644 build/dev-cpp/Makefile-static create mode 100644 build/dev-cpp/portaudio-dll.dev create mode 100644 build/dev-cpp/portaudio-static.dev create mode 100644 build/dev-cpp/readme.txt create mode 100644 build/msvc/portaudio.def create mode 100644 build/msvc/portaudio.dsp create mode 100644 build/msvc/portaudio.dsw create mode 100644 build/msvc/portaudio.sln create mode 100644 build/msvc/portaudio.vcproj create mode 100644 build/msvc/readme.txt create mode 100644 build/scons/SConscript_common create mode 100644 build/scons/SConscript_opts create mode 100755 config.guess create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100755 depcomp create mode 100644 doc/src/license.dox create mode 100644 doc/src/mainpage.dox create mode 100644 doc/src/srcguide.dox create mode 100644 doc/utils/checkfiledocs.py create mode 100755 fixdir.bat create mode 100755 fixfile.bat create mode 100644 include/pa_asio.h create mode 100644 include/pa_jack.h create mode 100644 include/pa_linux_alsa.h create mode 100644 include/pa_mac_core.h create mode 100644 include/pa_win_ds.h create mode 100644 include/pa_win_waveformat.h create mode 100644 include/pa_win_wmme.h create mode 100644 include/portaudio.h create mode 100644 index.html create mode 100755 install-sh create mode 100644 ltmain.sh create mode 100755 missing create mode 100644 pablio/README.txt create mode 100644 pablio/pablio.c create mode 100644 pablio/pablio.def create mode 100644 pablio/pablio.h create mode 100644 pablio/test_rw.c create mode 100644 pablio/test_rw_echo.c create mode 100644 pablio/test_w_saw.c create mode 100644 pablio/test_w_saw8.c create mode 100644 portaudio-2.0.pc.in create mode 100644 src/SConscript create mode 100644 src/common/pa_allocation.c create mode 100644 src/common/pa_allocation.h create mode 100644 src/common/pa_converters.c create mode 100644 src/common/pa_converters.h create mode 100644 src/common/pa_cpuload.c create mode 100644 src/common/pa_cpuload.h create mode 100644 src/common/pa_debugprint.c create mode 100644 src/common/pa_debugprint.h create mode 100644 src/common/pa_dither.c create mode 100644 src/common/pa_dither.h create mode 100644 src/common/pa_endianness.h create mode 100644 src/common/pa_front.c create mode 100644 src/common/pa_hostapi.h create mode 100644 src/common/pa_memorybarrier.h create mode 100644 src/common/pa_process.c create mode 100644 src/common/pa_process.h create mode 100644 src/common/pa_ringbuffer.c create mode 100644 src/common/pa_ringbuffer.h create mode 100644 src/common/pa_skeleton.c create mode 100644 src/common/pa_stream.c create mode 100644 src/common/pa_stream.h create mode 100644 src/common/pa_trace.c create mode 100644 src/common/pa_trace.h create mode 100644 src/common/pa_types.h create mode 100644 src/common/pa_util.h create mode 100644 src/hostapi/alsa/pa_linux_alsa.c create mode 100644 src/hostapi/asihpi/pa_linux_asihpi.c create mode 100644 src/hostapi/asio/ASIO-README.txt create mode 100644 src/hostapi/asio/Callback_adaptation_.pdf create mode 100644 src/hostapi/asio/Pa_ASIO.pdf create mode 100644 src/hostapi/asio/iasiothiscallresolver.cpp create mode 100644 src/hostapi/asio/iasiothiscallresolver.h create mode 100644 src/hostapi/asio/pa_asio.cpp create mode 100644 src/hostapi/coreaudio/notes.txt create mode 100644 src/hostapi/coreaudio/pa_mac_core.c create mode 100644 src/hostapi/coreaudio/pa_mac_core_blocking.c create mode 100644 src/hostapi/coreaudio/pa_mac_core_blocking.h create mode 100644 src/hostapi/coreaudio/pa_mac_core_internal.h create mode 100644 src/hostapi/coreaudio/pa_mac_core_old.c create mode 100644 src/hostapi/coreaudio/pa_mac_core_utilities.c create mode 100644 src/hostapi/coreaudio/pa_mac_core_utilities.h create mode 100644 src/hostapi/dsound/pa_win_ds.c create mode 100644 src/hostapi/dsound/pa_win_ds_dynlink.c create mode 100644 src/hostapi/dsound/pa_win_ds_dynlink.h create mode 100644 src/hostapi/jack/pa_jack.c create mode 100644 src/hostapi/oss/low_latency_tip.txt create mode 100644 src/hostapi/oss/pa_unix_oss.c create mode 100644 src/hostapi/oss/recplay.c create mode 100644 src/hostapi/wasapi/pa_win_wasapi.cpp create mode 100644 src/hostapi/wdmks/pa_win_wdmks.c create mode 100644 src/hostapi/wdmks/readme.txt create mode 100644 src/hostapi/wmme/pa_win_wmme.c create mode 100644 src/os/unix/pa_unix_hostapis.c create mode 100644 src/os/unix/pa_unix_util.c create mode 100644 src/os/unix/pa_unix_util.h create mode 100644 src/os/win/pa_win_hostapis.c create mode 100644 src/os/win/pa_win_util.c create mode 100644 src/os/win/pa_win_waveformat.c create mode 100644 src/os/win/pa_win_wdmks_utils.c create mode 100644 src/os/win/pa_win_wdmks_utils.h create mode 100644 src/os/win/pa_x86_plain_converters.c create mode 100644 src/os/win/pa_x86_plain_converters.h create mode 100644 test/README.txt create mode 100644 test/debug_convert.c create mode 100644 test/debug_dither_calc.c create mode 100644 test/debug_dual.c create mode 100644 test/debug_multi_in.c create mode 100644 test/debug_multi_out.c create mode 100644 test/debug_record.c create mode 100644 test/debug_record_reuse.c create mode 100644 test/debug_sine.c create mode 100644 test/debug_sine_amp.c create mode 100644 test/debug_sine_formats.c create mode 100644 test/debug_srate.c create mode 100644 test/debug_test1.c create mode 100644 test/pa_devs.c create mode 100644 test/pa_fuzz.c create mode 100644 test/pa_minlat.c create mode 100644 test/paqa_devs.c create mode 100644 test/paqa_errs.c create mode 100644 test/patest1.c create mode 100644 test/patest_buffer.c create mode 100644 test/patest_callbackstop.c create mode 100644 test/patest_clip.c create mode 100644 test/patest_converters.c create mode 100644 test/patest_dither.c create mode 100644 test/patest_dsound_surround.c create mode 100644 test/patest_hang.c create mode 100644 test/patest_in_overflow.c create mode 100644 test/patest_latency.c create mode 100644 test/patest_leftright.c create mode 100644 test/patest_longsine.c create mode 100644 test/patest_many.c create mode 100644 test/patest_maxsines.c create mode 100644 test/patest_mono.c create mode 100644 test/patest_mono_asio_channel_select.c create mode 100644 test/patest_multi_sine.c create mode 100644 test/patest_out_underflow.c create mode 100644 test/patest_pink.c create mode 100644 test/patest_prime.c create mode 100644 test/patest_read_record.c create mode 100644 test/patest_read_write_wire.c create mode 100644 test/patest_record.c create mode 100644 test/patest_ringmix.c create mode 100644 test/patest_saw.c create mode 100644 test/patest_sine.c create mode 100644 test/patest_sine8.c create mode 100644 test/patest_sine_channelmaps.c create mode 100644 test/patest_sine_formats.c create mode 100644 test/patest_sine_time.c create mode 100644 test/patest_start_stop.c create mode 100644 test/patest_stop.c create mode 100644 test/patest_stop_playout.c create mode 100644 test/patest_sync.c create mode 100644 test/patest_timing.c create mode 100644 test/patest_toomanysines.c create mode 100644 test/patest_two_rates.c create mode 100644 test/patest_underflow.c create mode 100644 test/patest_wire.c create mode 100644 test/patest_wmme_surround.c create mode 100644 test/patest_write_sine.c create mode 100644 test/patest_write_stop.c create mode 100644 testcvs/changeme.txt diff --git a/COMPILING.DARWIN b/COMPILING.DARWIN new file mode 100644 index 0000000..6d7aa87 --- /dev/null +++ b/COMPILING.DARWIN @@ -0,0 +1 @@ +To compile on darwin, you will need to use the darwin makefile, gcc 3.3 or later and the universal SDK. for more info, see http://portaudio.com/trac/wiki/TutorialDir/Compile/MacintoshCoreAudio diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..7dbfdfe --- /dev/null +++ b/Doxyfile @@ -0,0 +1,239 @@ +# Doxyfile 1.4.6 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = PortAudio +PROJECT_NUMBER = 2.0 +OUTPUT_DIRECTORY = ./doc/ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = doc/src \ + src \ + include \ + test +FILE_PATTERNS = *.h \ + *.c \ + *.cpp \ + *.dox +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e0ac4e8 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,81 @@ +Portable header file to contain: +>>>>> +/* + * PortAudio Portable Real-Time Audio Library + * PortAudio API Header File + * Latest version available at: http://www.portaudio.com + * + * Copyright (c) 1999-2006 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. + * + * 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. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * 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. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +<<<<< + + +Implementation files to contain: +>>>>> +/* + * PortAudio Portable Real-Time Audio Library + * Latest version at: http://www.portaudio.com + * Implementation + * Copyright (c) 1999-2000 + * + * 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. + * + * 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. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * 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. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +<<<<< \ No newline at end of file diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..dca537d --- /dev/null +++ b/Makefile.in @@ -0,0 +1,214 @@ +# +# PortAudio V19 Makefile.in +# +# Dominic Mazzoni +# Modifications by Mikael Magnusson +# + +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +top_builddir = . +PREFIX = @prefix@ +prefix = $(PREFIX) +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +includedir = @includedir@ +CC = @CC@ +CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/common -I$(top_srcdir)/src/os/unix @CFLAGS@ @DEFS@ +LIBS = @LIBS@ +AR = @AR@ +RANLIB = @RANLIB@ +LIBTOOL = @LIBTOOL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +SHARED_FLAGS = @SHARED_FLAGS@ +LDFLAGS = @LDFLAGS@ +DLL_LIBS = @DLL_LIBS@ +CXXFLAGS = @CXXFLAGS@ +NASM = @NASM@ +NASMOPT = @NASMOPT@ +LN_S = @LN_S@ +LT_CURRENT=@LT_CURRENT@ +LT_REVISION=@LT_REVISION@ +LT_AGE=@LT_AGE@ + +OTHER_OBJS = @OTHER_OBJS@ + +PALIB = libportaudio.la +PAINC = include/portaudio.h + +PA_LDFLAGS = $(LDFLAGS) $(SHARED_FLAGS) -rpath $(libdir) -no-undefined \ + -export-symbols-regex "(Pa|PaMacCore|PaJack|PaAlsa)_.*" \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) + +COMMON_OBJS = \ + src/common/pa_allocation.o \ + src/common/pa_converters.o \ + src/common/pa_cpuload.o \ + src/common/pa_dither.o \ + src/common/pa_debugprint.o \ + src/common/pa_front.o \ + src/common/pa_process.o \ + src/common/pa_skeleton.o \ + src/common/pa_stream.o \ + src/common/pa_trace.o + +TESTS = \ + bin/paqa_devs \ + bin/paqa_errs \ + bin/patest1 \ + bin/patest_buffer \ + bin/patest_callbackstop \ + bin/patest_clip \ + bin/patest_dither \ + bin/patest_hang \ + bin/patest_in_overflow \ + bin/patest_latency \ + bin/patest_leftright \ + bin/patest_longsine \ + bin/patest_many \ + bin/patest_maxsines \ + bin/patest_multi_sine \ + bin/patest_out_underflow \ + bin/patest_pink \ + bin/patest_prime \ + bin/patest_read_record \ + bin/patest_read_write_wire \ + bin/patest_record \ + bin/patest_ringmix \ + bin/patest_saw \ + bin/patest_sine8 \ + bin/patest_sine \ + bin/patest_sine_channelmaps \ + bin/patest_sine_formats \ + bin/patest_sine_time \ + bin/patest_start_stop \ + bin/patest_stop \ + bin/patest_stop_playout \ + bin/patest_toomanysines \ + bin/patest_underflow \ + bin/patest_wire \ + bin/patest_write_sine \ + bin/pa_devs \ + bin/pa_fuzz \ + bin/pa_minlat + +# Most of these don't compile yet. Put them in TESTS, above, if +# you want to try to compile them... +ALL_TESTS = \ + $(TESTS) \ + bin/patest_sync \ + bin/debug_convert \ + bin/debug_dither_calc \ + bin/debug_dual \ + bin/debug_multi_in \ + bin/debug_multi_out \ + bin/debug_record \ + bin/debug_record_reuse \ + bin/debug_sine_amp \ + bin/debug_sine \ + bin/debug_sine_formats \ + bin/debug_srate \ + bin/debug_test1 + +OBJS := $(COMMON_OBJS) $(OTHER_OBJS) + +LTOBJS := $(OBJS:.o=.lo) + +SRC_DIRS = \ + src/common \ + src/hostapi/alsa \ + src/hostapi/asihpi \ + src/hostapi/asio \ + src/hostapi/coreaudio \ + src/hostapi/dsound \ + src/hostapi/jack \ + src/hostapi/oss \ + src/hostapi/wasapi \ + src/hostapi/wdmks \ + src/hostapi/wmme \ + src/os/mac_osx \ + src/os/unix \ + src/os/win + +SUBDIRS = +@ENABLE_CXX_TRUE@SUBDIRS += bindings/cpp + +all: lib/$(PALIB) all-recursive tests + +tests: bin-stamp $(TESTS) + + +lib/$(PALIB): lib-stamp $(LTOBJS) $(MAKEFILE) $(PAINC) + $(LIBTOOL) --mode=link $(CC) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS) + +$(ALL_TESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) test/%.c + $(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS) + + +install: lib/$(PALIB) portaudio-2.0.pc + $(INSTALL) -d $(DESTDIR)$(libdir) + $(LIBTOOL) --mode=install $(INSTALL) lib/$(PALIB) $(DESTDIR)$(libdir) + $(INSTALL) -d $(DESTDIR)$(includedir) + $(INSTALL_DATA) -m 644 $(top_srcdir)/$(PAINC) $(DESTDIR)$(includedir)/portaudio.h + $(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig + $(INSTALL) -m 644 portaudio-2.0.pc $(DESTDIR)$(libdir)/pkgconfig/portaudio-2.0.pc + @echo "" + @echo "------------------------------------------------------------" + @echo "PortAudio was successfully installed." + @echo "" + @echo "On some systems (e.g. Linux) you should run 'ldconfig' now" + @echo "to make the shared object available. You may also need to" + @echo "modify your LD_LIBRARY_PATH environment variable to include" + @echo "the directory $(libdir)" + @echo "------------------------------------------------------------" + @echo "" + $(MAKE) install-recursive + +uninstall: + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(PALIB) + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(includedir)/portaudio.h + $(MAKE) uninstall-recursive + +clean: + $(LIBTOOL) --mode=clean rm -f $(LTOBJS) $(ALL_TESTS) lib/$(PALIB) + $(RM) bin-stamp lib-stamp + -$(RM) -r bin lib + +distclean: clean + $(RM) config.log config.status Makefile libtool portaudio-2.0.pc + +%.o: %.c $(MAKEFILE) $(PAINC) + $(CC) -c $(CFLAGS) $< -o $@ + +%.lo: %.c $(MAKEFILE) $(PAINC) + $(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< -o $@ + +%.o: %.cpp $(MAKEFILE) $(PAINC) + $(CXX) -c $(CXXFLAGS) $< -o $@ + +%.o: %.asm + $(NASM) $(NASMOPT) -o $@ $< + +bin-stamp: + -mkdir bin + touch $@ + +lib-stamp: + -mkdir lib + -mkdir -p $(SRC_DIRS) + touch $@ + +Makefile: Makefile.in config.status + $(SHELL) config.status + +all-recursive: + if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir all; done ; fi + +install-recursive: + if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir install; done ; fi + +uninstall-recursive: + if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir uninstall; done ; fi diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..2113827 --- /dev/null +++ b/README.txt @@ -0,0 +1,98 @@ +README for PortAudio + +/* + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Copyright (c) 1999-2008 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. + * + * 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. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * 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. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + + +PortAudio is a portable audio I/O library designed for cross-platform +support of audio. It uses either a callback mechanism to request audio +processing, or blocking read/write calls to buffer data between the +native audio subsystem and the client. Audio can be processed in various +formats, including 32 bit floating point, and will be converted to the +native format internally. + +Documentation: + Documentation is available in "/doc/html/index.html" + Also see "src/common/portaudio.h" for API spec. + Also see http://www.portaudio.com/docs/ + And see the "test/" directory for many examples of usage + (we suggest "test/patest_saw.c" for an example) + +For information on compiling programs with PortAudio, please see the +tutorial at: + + http://portaudio.com/trac/wiki/TutorialDir/TutorialStart + +We have an active mailing list for user and developer discussions. +Please feel free to join. See http://www.portaudio.com for details. + + +Important Files and Folders: + include/portaudio.h = header file for PortAudio API. Specifies API. + src/common/ = platform independant code, host independant + code for all implementations. + src/os = os specific (but host api neutral) code + src/hostapi = implementations for different host apis + + +Host API Implementations: + src/hostapi/alsa = Advanced Linux Sound Architecture (ALSA) + src/hostapi/asihpi = AudioScience HPI + src/hostapi/asio = ASIO for Windows and Macintosh + src/hostapi/coreaudio = Macintosh Core Audio for OS X + src/hostapi/dsound = Windows Direct Sound + src/hostapi/jack = JACK Audio Connection Kit + src/hostapi/oss = Unix Open Sound System (OSS) + src/hostapi/wasapi = Windows Vista WASAPI + src/hostapi/wdmks = Windows WDM Kernel Streaming + src/hostapi/wmme = Windows MultiMedia Extensions (MME) + + +Test Programs: + test/pa_fuzz.c = guitar fuzz box + test/pa_devs.c = print a list of available devices + test/pa_minlat.c = determine minimum latency for your machine + test/paqa_devs.c = self test that opens all devices + test/paqa_errs.c = test error detection and reporting + test/patest_clip.c = hear a sine wave clipped and unclipped + test/patest_dither.c = hear effects of dithering (extremely subtle) + test/patest_pink.c = fun with pink noise + test/patest_record.c = record and playback some audio + test/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad(). + test/patest_sine.c = output a sine wave in a simple PA app + test/patest_sync.c = test syncronization of audio and video + test/patest_wire.c = pass input to output, wire simulator diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..37e67ba --- /dev/null +++ b/SConstruct @@ -0,0 +1,197 @@ +import sys, os.path + +def rsplit(toSplit, sub, max=-1): + """ str.rsplit seems to have been introduced in 2.4 :( """ + l = [] + i = 0 + while i != max: + try: idx = toSplit.rindex(sub) + except ValueError: break + + toSplit, splitOff = toSplit[:idx], toSplit[idx + len(sub):] + l.insert(0, splitOff) + i += 1 + + l.insert(0, toSplit) + return l + +sconsDir = os.path.join("build", "scons") +SConscript(os.path.join(sconsDir, "SConscript_common")) +Import("Platform", "Posix", "ApiVer") + +# SConscript_opts exports PortAudio options +optsDict = SConscript(os.path.join(sconsDir, "SConscript_opts")) +optionsCache = os.path.join(sconsDir, "options.cache") # Save options between runs in this cache +options = Options(optionsCache, args=ARGUMENTS) +for k in ("Installation Dirs", "Build Targets", "Host APIs", "Build Parameters", "Bindings"): + options.AddOptions(*optsDict[k]) +# Propagate options into environment +env = Environment(options=options) +# Save options for next run +options.Save(optionsCache, env) +# Generate help text for options +env.Help(options.GenerateHelpText(env)) + +buildDir = os.path.join("#", sconsDir, env["PLATFORM"]) + +# Determine parameters to build tools +if Platform in Posix: + threadCFlags = '' + if Platform != 'darwin': + threadCFlags = "-pthread " + baseLinkFlags = threadCFlags + baseCxxFlags = baseCFlags = "-Wall -pedantic -pipe " + threadCFlags + debugCxxFlags = debugCFlags = "-g" + optCxxFlags = optCFlags = "-O2" +env.Append(CCFLAGS = baseCFlags) +env.Append(CXXFLAGS = baseCxxFlags) +env.Append(LINKFLAGS = baseLinkFlags) +if env["enableDebug"]: + env.AppendUnique(CCFLAGS=debugCFlags.split()) + env.AppendUnique(CXXFLAGS=debugCxxFlags.split()) +if env["enableOptimize"]: + env.AppendUnique(CCFLAGS=optCFlags.split()) + env.AppendUnique(CXXFLAGS=optCxxFlags.split()) +if not env["enableAsserts"]: + env.AppendUnique(CPPDEFINES=["-DNDEBUG"]) +if env["customCFlags"]: + env.Append(CCFLAGS=Split(env["customCFlags"])) +if env["customCxxFlags"]: + env.Append(CXXFLAGS=Split(env["customCxxFlags"])) +if env["customLinkFlags"]: + env.Append(LINKFLAGS=Split(env["customLinkFlags"])) + +env.Append(CPPPATH=[os.path.join("#", "include"), "common"]) + +# Store all signatures in one file, otherwise .sconsign files will get installed along with our own files +env.SConsignFile(os.path.join(sconsDir, ".sconsign")) + +env.SConscriptChdir(False) +sources, sharedLib, staticLib, tests, portEnv, hostApis = env.SConscript(os.path.join("src", "SConscript"), + build_dir=buildDir, duplicate=False, exports=["env"]) + +if Platform in Posix: + prefix = env["prefix"] + includeDir = os.path.join(prefix, "include") + libDir = os.path.join(prefix, "lib") + env.Alias("install", includeDir) + env.Alias("install", libDir) + + # pkg-config + + def installPkgconfig(env, target, source): + tgt = str(target[0]) + src = str(source[0]) + f = open(src) + try: txt = f.read() + finally: f.close() + txt = txt.replace("@prefix@", prefix) + txt = txt.replace("@exec_prefix@", prefix) + txt = txt.replace("@libdir@", libDir) + txt = txt.replace("@includedir@", includeDir) + txt = txt.replace("@LIBS@", " ".join(["-l%s" % l for l in portEnv["LIBS"]])) + txt = txt.replace("@THREAD_CFLAGS@", threadCFlags) + + f = open(tgt, "w") + try: f.write(txt) + finally: f.close() + + pkgconfigTgt = "portaudio-%d.0.pc" % int(ApiVer.split(".", 1)[0]) + env.Command(os.path.join(libDir, "pkgconfig", pkgconfigTgt), + os.path.join("#", pkgconfigTgt + ".in"), installPkgconfig) + +# Default to None, since if the user disables all targets and no Default is set, all targets +# are built by default +env.Default(None) +if env["enableTests"]: + env.Default(tests) +if env["enableShared"]: + env.Default(sharedLib) + + if Platform in Posix: + def symlink(env, target, source): + trgt = str(target[0]) + src = str(source[0]) + + if os.path.islink(trgt) or os.path.exists(trgt): + os.remove(trgt) + os.symlink(os.path.basename(src), trgt) + + major, minor, micro = [int(c) for c in ApiVer.split(".")] + + soFile = "%s.%s" % (os.path.basename(str(sharedLib[0])), ApiVer) + env.InstallAs(target=os.path.join(libDir, soFile), source=sharedLib) + # Install symlinks + symTrgt = os.path.join(libDir, soFile) + env.Command(os.path.join(libDir, "libportaudio.so.%d.%d" % (major, minor)), + symTrgt, symlink) + symTrgt = rsplit(symTrgt, ".", 1)[0] + env.Command(os.path.join(libDir, "libportaudio.so.%d" % major), symTrgt, symlink) + symTrgt = rsplit(symTrgt, ".", 1)[0] + env.Command(os.path.join(libDir, "libportaudio.so"), symTrgt, symlink) + +if env["enableStatic"]: + env.Default(staticLib) + env.Install(libDir, staticLib) + +env.Install(includeDir, os.path.join("include", "portaudio.h")) + + +if env["enableCxx"]: + env.SConscriptChdir(True) + cxxEnv = env.Copy() + sharedLibs, staticLibs, headers = env.SConscript(os.path.join("bindings", "cpp", "SConscript"), + exports={"env": cxxEnv, "buildDir": buildDir}, build_dir=os.path.join(buildDir, "portaudiocpp"), duplicate=False) + if env["enableStatic"]: + env.Default(staticLibs) + env.Install(libDir, staticLibs) + if env["enableShared"]: + env.Default(sharedLibs) + env.Install(libDir, sharedLibs) + env.Install(os.path.join(includeDir, "portaudiocpp"), headers) + +# Generate portaudio_config.h header with compile-time definitions of which PA +# back-ends are available, and which includes back-end extension headers + +# Host-specific headers +hostApiHeaders = {"ALSA": "pa_linux_alsa.h", + "ASIO": "pa_asio.h", + "COREAUDIO": "pa_mac_core.h", + "JACK": "pa_jack.h", + "WMME": "pa_winwmme.h", + } + +def buildConfigH(target, source, env): + """builder for portaudio_config.h""" + global hostApiHeaders, hostApis + out = "" + for hostApi in hostApis: + out += "#define PA_HAVE_%s\n" % hostApi + + hostApiSpecificHeader = hostApiHeaders.get(hostApi, None) + if hostApiSpecificHeader: + out += "#include \"%s\"\n" % hostApiSpecificHeader + + out += "\n" + # Strip the last newline + if out and out[-1] == "\n": + out = out[:-1] + + f = file(str(target[0]), 'w') + try: f.write(out) + finally: f.close() + return 0 + +# Define the builder for the config header +env.Append(BUILDERS={"portaudioConfig": env.Builder( + action=Action(buildConfigH), target_factory=env.fs.File)}) + +confH = env.portaudioConfig(File("portaudio_config.h", "include"), + File("portaudio.h", "include")) +env.Default(confH) +env.Install(os.path.join(includeDir, "portaudio"), confH) + +for api in hostApis: + if api in hostApiHeaders: + env.Install(os.path.join(includeDir, "portaudio"), + File(hostApiHeaders[api], "include")) diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..9e5b4fd --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,6627 @@ +# aclocal.m4 generated automatically by aclocal 1.6.3 -*- Autoconf -*- + +# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- + +# serial 48 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Check if we have a version mismatch between libtool.m4 and ltmain.sh. +# +# Note: This should be in AC_LIBTOOL_SETUP, _after_ $ltmain have been defined. +# We also should do it _before_ AC_LIBTOOL_LANG_C_CONFIG that actually +# calls AC_LIBTOOL_CONFIG and creates libtool. +# +_LT_VERSION_CHECK + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_VERSION_CHECK +# ----------------- +AC_DEFUN([_LT_VERSION_CHECK], +[AC_MSG_CHECKING([for correct ltmain.sh version]) +if test "x$ltmain" = "x" ; then + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + +*** @<:@Gentoo@:>@ sanity check failed! *** +*** \$ltmain is not defined, please check the patch for consistency! *** +]) +fi +gentoo_lt_version="1.5.22" +gentoo_ltmain_version=`sed -n '/^[[ ]]*VERSION=/{s/^[[ ]]*VERSION=//;p;q;}' "$ltmain"` +if test "x$gentoo_lt_version" != "x$gentoo_ltmain_version" ; then + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + +*** @<:@Gentoo@:>@ sanity check failed! *** +*** libtool.m4 and ltmain.sh have a version mismatch! *** +*** (libtool.m4 = $gentoo_lt_version, ltmain.sh = $gentoo_ltmain_version) *** + +Please run: + + libtoolize --copy --force + +if appropriate, please contact the maintainer of this +package (or your distribution) for help. +]) +else + AC_MSG_RESULT(yes) +fi +])# _LT_VERSION_CHECK + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +AC_DEFUN([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +AC_DEFUN([_LT_COMPILER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +AC_DEFUN([_LT_LINKER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_LINKER_BOILERPLATE + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# ------------------ +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# --------------------------------------------------------------------- +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ---------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + linux*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + if test $supports_anon_versioning = yes; then + archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ +cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ +$echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + else + $archive_expsym_cmds="$archive_cmds" + fi + else + ld_shlibs=no + fi + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + # Handle Gentoo/FreeBSD as it was Linux + case $host_vendor in + gentoo) + version_type=linux ;; + *) + version_type=freebsd-$objformat ;; + esac + + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + linux) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + need_lib_prefix=no + need_version=no + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 DLLs +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +# set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix3*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# it is assumed to be `libltdl'. LIBLTDL will be prefixed with +# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' +# (note the single quotes!). If your package is not flat and you're not +# using automake, define top_builddir and top_srcdir appropriately in +# the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# and an installed libltdl is not found, it is assumed to be `libltdl'. +# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and top_srcdir +# appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + +# _LT_AC_PROG_CXXCPP +# ------------------ +AC_DEFUN([_LT_AC_PROG_CXXCPP], +[ +AC_REQUIRE([AC_PROG_CXX]) +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +fi +])# _LT_AC_PROG_CXXCPP + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# ------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF + +# Report which library types will actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + ;; + *) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. We must also pass each convience library through + # to the system linker between allextract/defaultextract. + # The C++ compiler will combine linker options so we + # cannot just pass the convience library names through + # without $wl. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDGIRSTW]]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + _LT_CC_BASENAME([$compiler]) + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi[[45]]*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu | dragonfly*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + *) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi + +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$PKG_CONFIG"; then + if test -n "$$1"; then + pkg_cv_[]$1="$$1" + else + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) + fi +else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT +])], + [$4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES + diff --git a/bindings/cpp/AUTHORS b/bindings/cpp/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/bindings/cpp/COPYING b/bindings/cpp/COPYING new file mode 100644 index 0000000..c1c60a0 --- /dev/null +++ b/bindings/cpp/COPYING @@ -0,0 +1,31 @@ +PortAudio Portable Real-Time Audio Library +Copyright (c) 1999-2006 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. + +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. + + +The text above constitutes the entire PortAudio license; however, +the PortAudio community also makes the following non-binding requests: + +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. It is also +requested that these non-binding requests be included along with the +license above. diff --git a/bindings/cpp/ChangeLog b/bindings/cpp/ChangeLog new file mode 100644 index 0000000..0201a0f --- /dev/null +++ b/bindings/cpp/ChangeLog @@ -0,0 +1,178 @@ +Note: Because PortAudioCpp is now in the main PortAudio SVN repository, having these per-release changelogs probably doesn't make much sense anymore. Perhaps it's better to just note mayor changes by date from now on. + +PortAudioCpp v19 revision 16 06/05/22: + + mblaauw: + - Added up-to-date MSVC 6.0 projects created by David Moore. Besides MSVC 6.0 users, MSVC 7.0 users may use these projects and automatically convert them to MSVC 7.0 projects. + - Changed the code and projects (MSVC 7.1 only) to be up-to-date with PortAudio's new directory structure. + - Added equivalents of the PaAsio_GetInputChannelName() and PaAsio_GetOutputChannelName() functions to the AsioDeviceAdapter wrapper-class (missing functions pointed out by David Moore). + - Added code to PortAudio's main SVN repository. + +PortAudioCpp v19 revision 15 (unknown release date): + + mblaauw: + - Changed some exception handling code in HostApi's constructor. + - Added accessors to PortAudio PaStream from PortAudioCpp Stream (their absense being pointed out + by Tom Jordan). + - Fixed a bug/typo in MemFunToCallbackInterfaceAdapter::init() thanks to Fredrik Viklund. + - Fixed issue with concrete Stream classes possibly throwing an exception and fixed documentation w.r.t. this. + - Moved files to portaudio/binding/cpp/. Made new msvc 7.1 projects to reflect the change and removed msvc 6.0 + and 7.0 projects (because I can no longer maintain them myself). Gnu projects will probably need updating. + +PortAudioCpp v19 revision 14 03/10/24: + + mblaauw: + - Fixed some error handling bugs in Stream and System (pointed out by Tom Jordan). + - Updated documentation a little (main page). + - Fixed order of members so initializer list was in the right order in + StreamParameters (pointed out by Ludwig Schwardt). + - Added new lines at EOF's (as indicated by Ludwig Schwardt). + +PortAudioCpp v19 revision 13 03/10/19: + + lschwardt: + - Added build files for GNU/Linux. + - Fixed bug in Exception where the inherited what() member function (and destructor) had looser + exception specification (namely no exception specification, i.e. could throw anything) than + the std::exception base class's what() member function (which had throw(), i.e. no-throw guarantee). + - Changed the iterators so that they have a set of public typedefs instead of deriving the C++ standard + library std::iterator<> struct. G++ 2.95 doesn't support std::exception<> and composition-by-aggregation + is prefered over composition-by-inheritance in this case. + - Changed some minor things to avoid G++ warning messages. + + mblaauw: + - Renamed this file (/WHATSNEW.txt) to /CHANGELOG. + - Renamed /PA_ISSUES.txt to /PA_ISSUES. + - Added /INSTALL file with some build info for GNU/Linux and VC6. + - Added MSVC 6.0 projects for building PortAudioCpp as a staticly or dynamically linkable library. + - Moved build files to /build/(gnu/ or vc6/). + - Moved Doxygen configuration files to /doc/ and output to /doc/api_reference/. + - Added a /doc/README with some info how to generate Doxygen documentation. + +PortAudioCpp v19 revision 12 03/09/02: + + mblaauw: + - Updated code to reflect changes on V19-devel CVS branch. + - Fixed some typos in the documentation. + +PortAudioCpp v19 revision 11 03/07/31: + + mblaauw: + - Renamed SingleDirecionStreamParameters to DirectionSpecificStreamParameters. + - Implemented BlockingStream. + - Updated code to reflect recent changes to PortAudio V19-devel. + - Fixed a potential memory leak when an exception was thrown in the HostApi + constructor. + - Renamed ``Latency'' to ``BufferSize'' in AsioDeviceAdapter. + - Updated class documentation. + +PortAudioCpp v19 revision 10 03/07/18: + + mblaauw: + - SingleDirectionStreamParameters now has a (static) null() method. + - StreamParameters uses references for the direction-specific stream parameters + instead of pointers (use null() method (above) instead of NULL). + - StreamParameters and SingleDirectionStreamParameters must now be fully specified + and now default values are used (because this was not very useful in general and + only made things more complex). + - Updated documentation. + +PortAudioCpp v19 revision 09 03/06/25: + + mblaauw: + - Changed some things in SingleDirectionStreamParameters to ease it's usage. + - Placed all SingleDirectionStreamParameters stuff into a separate file. + + Totally redid the callback stuff, now it's less ackward and supports C++ functions. + +PortAudioCpp v19 revision 08 03/06/20: + + mblaauw: + - Made deconstructors for Device and HostApi private. + + Added a AsioDeviceWrapper host api specific device extension class. + - Refactored Exception into a Exception base class and PaException and PaCppException + derived classes. + - Added ASIO specific device info to the devs.cxx example. + - Fixed a bug in System::hostApiCount() and System::defaultHostApi(). + + Moved Device::null to System::nullDevice. + - Fixed some bugs in Device and System. + +PortAudioCpp v19 revision 07 03/06/08: + + mblaauw: + - Updated some doxy comments. + + Renamed CbXyz to CallbackXyz. + + Renamed all ``configurations'' to ``parameters''. + + Renamed HalfDuplexStreamConfiguration to SingleDirectionStreamConfiguration. + - Renamed SingleDirectionStreamParameters::streamParameters() to + SingleDirectionStreamParameters::paSteamParameters. + - Added a non-constant version of SingleDirectionStreamParameters::paStreamParameters(). + - A few improvements to SingleDirectionStreamParameters. + - Allowed AutoSystem to be created without initializing the System singleton + (using a ctor flag). + - Added a BlockingStream class (not implemented for now). + - Fixed many bugs in the implementation of the iterators. + - Fixed a bug in Device::operator==(). + + Added a C++ version of the patest_sine.c test/example. + - Added a ctor for StreamParameters for a default half-duplex stream. + - Added SingleDirectionStreamParameters::setDevice() and setNumChannels(). + - Renamed System::numHostApis() to System::hostApiCount(). + + Rewrote the iterators and related classes. They are now fully STL compliant. The System now + has a static array of all HostApis and all Devices. Only the System can create HostApis and + Devices and they are non-copyable now. All HostApis and Devices are now passed by-reference. + - Renamed (System::) getVersion() to version() and getVersionText() to versionText(). + - Renamed (Device::) numXyzChannels() to maxXyzChannels(). + - Changed some stuff in StreamParameters. + + Added a C++ version of the patest_devs.c test/example. + +PortAudioCpp v19 revision 06 03/06/04: + + mblaauw: + + Added this file to the project (roughly, a `+' denotes a major change, a `-' a minor change). + - Added System::deviceByIndex(), useful when a Device's index is stored for instance. + - Renamed System::hostApiFromTypeId() to System::hostApiByTypeId(). + - Updated and added some Doxygen documentation. + - Made Stream::usedIntputLatency(), Stream::usedOutputLatency() and + Stream::usedSampleRate() throw an paInternalError equivalent exception instead of paBadStreamPtr. + - Changed exception handling in Stream::open() functions. They now follow the PA error handling + mechanism better and a couple of bugs regarding ownership of objects were fixed. + - Renamed Device::isDefaultXyzDevice() to Device::isSystemDefaultXyzDevice(). + - Added Device::isHostApiDefaultXyzDevice(). + - Added StreamConfiguration::unsetFlag(). + - Removed CUSTOM from SampleDataFormat. + - System::hostApiByTypeId() now throws an paInternalError if the type id was out-of-range; this + is a temporary work-around (see comments). + - Changed CbInterface to use paCallbackFun() instead of operator()(). + - Renamed ``object'' to ``instance'' in CbMemFunAdapter.hxx. + - Added StreamConfiguration::setXyzHostApiSpecificSampleFormat(). + - Added StreamConfiguration::isXyzSampleFormatHostApiSpecific(). + - Changed error handling in System::terminate(), it can now throw an Exception. + - Added error handling in System::defaultHostApi(). + - Added error handling in System::hostApisEnd(). + - Changed some (but probably not all) C casts to C++ casts to avoid confusion with a + certain Python person. + - Renamed RaiiSystem to AutoSystem (class and file) as this is a come common convention. + - Renamed System::numDevices() to System::deviceCount() to be more compatible with PortAudio + (although PortAudio uses Pa_CountDevices() instead, see comment). + - Renamed HostApi::numDevices() to HostApi::deviceCount(). + - Changed INC_ to INCLUDED_ in the header multiple include guards. + - Changed the order of functions in the StreamConfiguration class' header. + - Written some more info in PortAudioCpp.hxx (Doxygen). + - Added CallbackStream.hxx and CallbackStream.cxx files. + + Refactored StreamConfiguration to remove the duplication which was there. There is now a + HalfDuplexStreamConfiguration class. Also made some improvements to these classes while + doing the refactoring. + + Moved all code files to source/portaudiocpp/ and changed includes. + + Moved all header files to include/portaudiocpp/ to easy a binary build if needed. The project + must be set to have .../include/ as a path to look for includes. + + Refactored the Stream class into a Stream base class and a CallbackStream derived class. + - Renamed Stream::usingXyz() to Stream::xyz(). + - Updated some doxy comments. + - Changed ``using namespace portaudio'' in .cxx files to ``namespace portaudio { ... }''. + +PortAudioCpp v19 revision 05 03/04/09: + + mblaauw: + - Initial release on the PortAudio mailinglist. + + + diff --git a/bindings/cpp/INSTALL b/bindings/cpp/INSTALL new file mode 100644 index 0000000..23e5f25 --- /dev/null +++ b/bindings/cpp/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/bindings/cpp/Makefile.am b/bindings/cpp/Makefile.am new file mode 100644 index 0000000..b10449c --- /dev/null +++ b/bindings/cpp/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = lib include bin +#doc + +EXTRA_DIST = portaudiocpp.pc + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = portaudiocpp.pc diff --git a/bindings/cpp/Makefile.in b/bindings/cpp/Makefile.in new file mode 100644 index 0000000..f60601b --- /dev/null +++ b/bindings/cpp/Makefile.in @@ -0,0 +1,642 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = README $(am__configure_deps) \ + $(srcdir)/../../config.guess $(srcdir)/../../config.sub \ + $(srcdir)/../../install-sh $(srcdir)/../../ltmain.sh \ + $(srcdir)/../../missing $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/portaudiocpp.pc.in \ + $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = portaudiocpp.pc +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(pkgconfigdir)" +pkgconfigDATA_INSTALL = $(INSTALL_DATA) +DATA = $(pkgconfig_DATA) +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SUBDIRS = lib include bin +#doc +EXTRA_DIST = portaudiocpp.pc +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = portaudiocpp.pc +all: all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +portaudiocpp.pc: $(top_builddir)/config.status $(srcdir)/portaudiocpp.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(mkdir_p) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \ + $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \ + rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkdir_p) $(distdir)/. $(distdir)/../.. + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-pkgconfigDATA + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am uninstall-pkgconfigDATA + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \ + check-am clean clean-generic clean-libtool clean-recursive \ + ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ + dist-shar dist-tarZ dist-zip distcheck distclean \ + distclean-generic distclean-libtool distclean-recursive \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-pkgconfigDATA \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-libtool mostlyclean-recursive pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am uninstall-info-am \ + uninstall-pkgconfigDATA + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bindings/cpp/NEWS b/bindings/cpp/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/bindings/cpp/README b/bindings/cpp/README new file mode 100644 index 0000000..e69de29 diff --git a/bindings/cpp/SConscript b/bindings/cpp/SConscript new file mode 100644 index 0000000..e69b93a --- /dev/null +++ b/bindings/cpp/SConscript @@ -0,0 +1,65 @@ +import os.path + +Import("env", "buildDir") +env.Append(CPPPATH="include") + +ApiVer = "0.0.12" +Major, Minor, Micro = [int(c) for c in ApiVer.split(".")] + +sharedLibs = [] +staticLibs = [] +Import("Platform", "Posix") +if Platform in Posix: + env["SHLIBSUFFIX"] = ".so.%d.%d.%d" % (Major, Minor, Micro) + soFile = "libportaudiocpp.so" + if Platform != 'darwin': + env.AppendUnique(SHLINKFLAGS="-Wl,-soname=%s.%d" % (soFile, Major)) + + # Create symlinks + def symlink(env, target, source): + trgt = str(target[0]) + src = str(source[0]) + if os.path.islink(trgt) or os.path.exists(trgt): + os.remove(trgt) + os.symlink(os.path.basename(src), trgt) + lnk0 = env.Command(soFile + ".%d" % (Major), soFile + ".%d.%d.%d" % (Major, Minor, Micro), symlink) + lnk1 = env.Command(soFile, soFile + ".%d" % (Major), symlink) + sharedLibs.append(lnk0) + sharedLibs.append(lnk1) + +src = [os.path.join("source", "portaudiocpp", "%s.cxx" % f) for f in ("BlockingStream", "CallbackInterface", \ + "CallbackStream", "CFunCallbackStream","CppFunCallbackStream", "Device", + "DirectionSpecificStreamParameters", "Exception", "HostApi", "InterfaceCallbackStream", + "MemFunCallbackStream", "Stream", "StreamParameters", "System", "SystemDeviceIterator", + "SystemHostApiIterator")] +env.Append(LIBS="portaudio", LIBPATH=buildDir) +sharedLib = env.SharedLibrary("portaudiocpp", src, LIBS=["portaudio"]) +staticLib = env.Library("portaudiocpp", src, LIBS=["portaudio"]) +sharedLibs.append(sharedLib) +staticLibs.append(staticLib) + +headers = Split("""AutoSystem.hxx + BlockingStream.hxx + CallbackInterface.hxx + CallbackStream.hxx + CFunCallbackStream.hxx + CppFunCallbackStream.hxx + Device.hxx + DirectionSpecificStreamParameters.hxx + Exception.hxx + HostApi.hxx + InterfaceCallbackStream.hxx + MemFunCallbackStream.hxx + PortAudioCpp.hxx + SampleDataFormat.hxx + Stream.hxx + StreamParameters.hxx + SystemDeviceIterator.hxx + SystemHostApiIterator.hxx + System.hxx + """) +if env["PLATFORM"] == "win32": + headers.append("AsioDeviceAdapter.hxx") +headers = [File(os.path.join("include", "portaudiocpp", h)) for h in headers] + +Return("sharedLibs", "staticLibs", "headers") diff --git a/bindings/cpp/aclocal.m4 b/bindings/cpp/aclocal.m4 new file mode 100644 index 0000000..38a7545 --- /dev/null +++ b/bindings/cpp/aclocal.m4 @@ -0,0 +1,7336 @@ +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- + +# serial 48 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Check if we have a version mismatch between libtool.m4 and ltmain.sh. +# +# Note: This should be in AC_LIBTOOL_SETUP, _after_ $ltmain have been defined. +# We also should do it _before_ AC_LIBTOOL_LANG_C_CONFIG that actually +# calls AC_LIBTOOL_CONFIG and creates libtool. +# +_LT_VERSION_CHECK + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_VERSION_CHECK +# ----------------- +AC_DEFUN([_LT_VERSION_CHECK], +[AC_MSG_CHECKING([for correct ltmain.sh version]) +if test "x$ltmain" = "x" ; then + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + +*** @<:@Gentoo@:>@ sanity check failed! *** +*** \$ltmain is not defined, please check the patch for consistency! *** +]) +fi +gentoo_lt_version="1.5.22" +gentoo_ltmain_version=`sed -n '/^[[ ]]*VERSION=/{s/^[[ ]]*VERSION=//;p;q;}' "$ltmain"` +if test "x$gentoo_lt_version" != "x$gentoo_ltmain_version" ; then + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + +*** @<:@Gentoo@:>@ sanity check failed! *** +*** libtool.m4 and ltmain.sh have a version mismatch! *** +*** (libtool.m4 = $gentoo_lt_version, ltmain.sh = $gentoo_ltmain_version) *** + +Please run: + + libtoolize --copy --force + +if appropriate, please contact the maintainer of this +package (or your distribution) for help. +]) +else + AC_MSG_RESULT(yes) +fi +])# _LT_VERSION_CHECK + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +AC_DEFUN([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +AC_DEFUN([_LT_COMPILER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +AC_DEFUN([_LT_LINKER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_LINKER_BOILERPLATE + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# ------------------ +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# --------------------------------------------------------------------- +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ---------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + linux*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + if test $supports_anon_versioning = yes; then + archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ +cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ +$echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + else + $archive_expsym_cmds="$archive_cmds" + fi + else + ld_shlibs=no + fi + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + # Handle Gentoo/FreeBSD as it was Linux + case $host_vendor in + gentoo) + version_type=linux ;; + *) + version_type=freebsd-$objformat ;; + esac + + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + linux) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + need_lib_prefix=no + need_version=no + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 DLLs +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +# set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix3*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# it is assumed to be `libltdl'. LIBLTDL will be prefixed with +# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' +# (note the single quotes!). If your package is not flat and you're not +# using automake, define top_builddir and top_srcdir appropriately in +# the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# and an installed libltdl is not found, it is assumed to be `libltdl'. +# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and top_srcdir +# appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + +# _LT_AC_PROG_CXXCPP +# ------------------ +AC_DEFUN([_LT_AC_PROG_CXXCPP], +[ +AC_REQUIRE([AC_PROG_CXX]) +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +fi +])# _LT_AC_PROG_CXXCPP + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# ------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF + +# Report which library types will actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + ;; + *) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. We must also pass each convience library through + # to the system linker between allextract/defaultextract. + # The C++ compiler will combine linker options so we + # cannot just pass the convience library names through + # without $wl. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDGIRSTW]]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + _LT_CC_BASENAME([$compiler]) + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi[[45]]*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu | dragonfly*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + *) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.6])]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 7 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +AC_DEFUN([AM_MAINTAINER_MODE], +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. +# +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/bindings/cpp/bin/Makefile.am b/bindings/cpp/bin/Makefile.am new file mode 100644 index 0000000..5f97f94 --- /dev/null +++ b/bindings/cpp/bin/Makefile.am @@ -0,0 +1,9 @@ +BINDIR = $(top_srcdir)/example +LIBDIR = $(top_builddir)/lib + +noinst_PROGRAMS = devs sine + +LDADD = $(LIBDIR)/libportaudiocpp.la + +devs_SOURCES = $(BINDIR)/devs.cxx +sine_SOURCES = $(BINDIR)/sine.cxx diff --git a/bindings/cpp/bin/Makefile.in b/bindings/cpp/bin/Makefile.in new file mode 100644 index 0000000..fa45b04 --- /dev/null +++ b/bindings/cpp/bin/Makefile.in @@ -0,0 +1,470 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = devs$(EXEEXT) sine$(EXEEXT) +subdir = bin +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_devs_OBJECTS = devs.$(OBJEXT) +devs_OBJECTS = $(am_devs_OBJECTS) +devs_LDADD = $(LDADD) +devs_DEPENDENCIES = $(LIBDIR)/libportaudiocpp.la +am_sine_OBJECTS = sine.$(OBJEXT) +sine_OBJECTS = $(am_sine_OBJECTS) +sine_LDADD = $(LDADD) +sine_DEPENDENCIES = $(LIBDIR)/libportaudiocpp.la +depcomp = $(SHELL) $(top_srcdir)/../../depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(devs_SOURCES) $(sine_SOURCES) +DIST_SOURCES = $(devs_SOURCES) $(sine_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +BINDIR = $(top_srcdir)/example +LIBDIR = $(top_builddir)/lib +LDADD = $(LIBDIR)/libportaudiocpp.la +devs_SOURCES = $(BINDIR)/devs.cxx +sine_SOURCES = $(BINDIR)/sine.cxx +all: all-am + +.SUFFIXES: +.SUFFIXES: .cxx .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bin/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu bin/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +devs$(EXEEXT): $(devs_OBJECTS) $(devs_DEPENDENCIES) + @rm -f devs$(EXEEXT) + $(CXXLINK) $(devs_LDFLAGS) $(devs_OBJECTS) $(devs_LDADD) $(LIBS) +sine$(EXEEXT): $(sine_OBJECTS) $(sine_DEPENDENCIES) + @rm -f sine$(EXEEXT) + $(CXXLINK) $(sine_LDFLAGS) $(sine_OBJECTS) $(sine_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sine.Po@am__quote@ + +.cxx.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cxx.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cxx.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +devs.o: $(BINDIR)/devs.cxx +@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT devs.o -MD -MP -MF "$(DEPDIR)/devs.Tpo" -c -o devs.o `test -f '$(BINDIR)/devs.cxx' || echo '$(srcdir)/'`$(BINDIR)/devs.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/devs.Tpo" "$(DEPDIR)/devs.Po"; else rm -f "$(DEPDIR)/devs.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(BINDIR)/devs.cxx' object='devs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o devs.o `test -f '$(BINDIR)/devs.cxx' || echo '$(srcdir)/'`$(BINDIR)/devs.cxx + +devs.obj: $(BINDIR)/devs.cxx +@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT devs.obj -MD -MP -MF "$(DEPDIR)/devs.Tpo" -c -o devs.obj `if test -f '$(BINDIR)/devs.cxx'; then $(CYGPATH_W) '$(BINDIR)/devs.cxx'; else $(CYGPATH_W) '$(srcdir)/$(BINDIR)/devs.cxx'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/devs.Tpo" "$(DEPDIR)/devs.Po"; else rm -f "$(DEPDIR)/devs.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(BINDIR)/devs.cxx' object='devs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o devs.obj `if test -f '$(BINDIR)/devs.cxx'; then $(CYGPATH_W) '$(BINDIR)/devs.cxx'; else $(CYGPATH_W) '$(srcdir)/$(BINDIR)/devs.cxx'; fi` + +sine.o: $(BINDIR)/sine.cxx +@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sine.o -MD -MP -MF "$(DEPDIR)/sine.Tpo" -c -o sine.o `test -f '$(BINDIR)/sine.cxx' || echo '$(srcdir)/'`$(BINDIR)/sine.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sine.Tpo" "$(DEPDIR)/sine.Po"; else rm -f "$(DEPDIR)/sine.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(BINDIR)/sine.cxx' object='sine.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sine.o `test -f '$(BINDIR)/sine.cxx' || echo '$(srcdir)/'`$(BINDIR)/sine.cxx + +sine.obj: $(BINDIR)/sine.cxx +@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sine.obj -MD -MP -MF "$(DEPDIR)/sine.Tpo" -c -o sine.obj `if test -f '$(BINDIR)/sine.cxx'; then $(CYGPATH_W) '$(BINDIR)/sine.cxx'; else $(CYGPATH_W) '$(srcdir)/$(BINDIR)/sine.cxx'; fi`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sine.Tpo" "$(DEPDIR)/sine.Po"; else rm -f "$(DEPDIR)/sine.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(BINDIR)/sine.cxx' object='sine.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sine.obj `if test -f '$(BINDIR)/sine.cxx'; then $(CYGPATH_W) '$(BINDIR)/sine.cxx'; else $(CYGPATH_W) '$(srcdir)/$(BINDIR)/sine.cxx'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bindings/cpp/build/gnu/Makefile.in b/bindings/cpp/build/gnu/Makefile.in new file mode 100644 index 0000000..0bc6f28 --- /dev/null +++ b/bindings/cpp/build/gnu/Makefile.in @@ -0,0 +1,106 @@ +# +# Makefile template for PortAudioCpp +# Ludwig Schwardt +# 01/10/2003 +# +# Not much to edit here - rather check configure.ac +# + +PREFIX = @prefix@ +CC = @CC@ +CXX = @CXX@ +CFLAGS = @CFLAGS@ @DEFS@ +CXXFLAGS = @CXXFLAGS@ +SHARED_FLAGS = @SHARED_FLAGS@ +LIBS = @LIBS@ +DLL_LIBS = @DLL_LIBS@ +AR = @AR@ +RANLIB = @RANLIB@ +INSTALL = @INSTALL@ + +PACPP_ROOT = @PACPP_ROOT@ +PORTAUDIO = @PORTAUDIO@ +PADLL = @PADLL@ +PACPP_DLL = @PACPP_DLL@ +PALIB = libportaudio.a +PACPP_LIB = libportaudiocpp.a +PACPP_DLLV = $(PACPP_DLL).0.0.12 + +SRCDIR = $(PACPP_ROOT)/source/portaudiocpp +BINDIR = $(PACPP_ROOT)/example +LIBDIR = $(PACPP_ROOT)/lib +DOCDIR = $(PACPP_ROOT)/doc + +OBJS = \ + $(SRCDIR)/BlockingStream.o \ + $(SRCDIR)/CallbackInterface.o \ + $(SRCDIR)/CallbackStream.o \ + $(SRCDIR)/CFunCallbackStream.o \ + $(SRCDIR)/CppFunCallbackStream.o \ + $(SRCDIR)/Device.o \ + $(SRCDIR)/DirectionSpecificStreamParameters.o \ + $(SRCDIR)/Exception.o \ + $(SRCDIR)/HostApi.o \ + $(SRCDIR)/InterfaceCallbackStream.o \ + $(SRCDIR)/MemFunCallbackStream.o \ + $(SRCDIR)/Stream.o \ + $(SRCDIR)/StreamParameters.o \ + $(SRCDIR)/System.o \ + $(SRCDIR)/SystemDeviceIterator.o \ + $(SRCDIR)/SystemHostApiIterator.o + +# Not supported yet +# $(SRCDIR)/AsioDeviceAdapter.o + +EXAMPLES = \ + $(BINDIR)/devs \ + $(BINDIR)/sine + +.PHONY: all clean docs + +all: $(EXAMPLES) $(LIBDIR)/$(PACPP_LIB) $(LIBDIR)/$(PACPP_DLL) + +clean: + rm -rf $(SRCDIR)/*.o $(BINDIR)/*.o $(EXAMPLES) $(LIBDIR) $(DOCDIR)/api_reference + rm -rf autom4te.cache config.status config.log + +docs: + cd $(DOCDIR); doxygen config.doxy.linux + +%.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ + +%.o: %.cxx + $(CXX) -c $(CXXFLAGS) $< -o $@ + + +$(EXAMPLES): $(BINDIR)/%: $(BINDIR)/%.o $(OBJS) + $(CXX) $^ -o $@ $(LIBS) + +$(LIBDIR)/$(PACPP_LIB): $(LIBDIR) $(OBJS) + $(AR) ruv $(LIBDIR)/$(PACPP_LIB) $(OBJS) + $(RANLIB) $(LIBDIR)/$(PACPP_LIB) + +$(LIBDIR)/$(PACPP_DLLV): $(LIBDIR) $(OBJS) + $(CXX) $(SHARED_FLAGS) -o $(LIBDIR)/$(PACPP_DLLV) $(OBJS) $(DLL_LIBS) + +$(LIBDIR)/$(PACPP_DLL): $(LIBDIR) $(OBJS) + $(CXX) $(SHARED_FLAGS) -o $(LIBDIR)/$(PACPP_DLL) $(OBJS) $(DLL_LIBS) + +#install: $(LIBDIR)/$(PACPP_LIB) $(LIBDIR)/$(PACPP_DLLV) +# $(INSTALL) -m 644 $(LIBDIR)/$(PACPP_DLLV) $(PREFIX)/lib/$(PACPP_DLLV) +# $(INSTALL) -m 644 $(LIBDIR)/$(PACPP_LIB) $(PREFIX)/lib/$(PACPP_LIB) +# cd $(PREFIX)/lib && rm -f $(PACPP_DLL) && ln -s $(PACPP_DLLV) $(PACPP_DLL) +# @echo "" +# @echo "------------------------------------------------------------" +# @echo "PortAudioCpp was successfully installed." +# @echo "" +# @echo "On some systems (e.g. Linux) you should run 'ldconfig' now" +# @echo "to make the shared object available. You may also need to" +# @echo "modify your LD_LIBRARY_PATH environment variable to include" +# @echo "the directory $(PREFIX)/lib" +# @echo "------------------------------------------------------------" +# @echo "" + +$(LIBDIR): + mkdir $(LIBDIR) diff --git a/bindings/cpp/build/gnu/OUT_OF_DATE b/bindings/cpp/build/gnu/OUT_OF_DATE new file mode 100644 index 0000000..e69de29 diff --git a/bindings/cpp/build/gnu/aclocal.m4 b/bindings/cpp/build/gnu/aclocal.m4 new file mode 100644 index 0000000..c80e0ac --- /dev/null +++ b/bindings/cpp/build/gnu/aclocal.m4 @@ -0,0 +1,57 @@ + +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN(PKG_CHECK_MODULES, [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + diff --git a/bindings/cpp/build/gnu/config.guess b/bindings/cpp/build/gnu/config.guess new file mode 100644 index 0000000000000000000000000000000000000000..297e5c30f41b65e95341322c77994c4d1d447134 GIT binary patch literal 38293 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 U)O!4AX9|J+poD;K<7?sn03Xu03;+NC literal 0 HcmV?d00001 diff --git a/bindings/cpp/build/gnu/config.sub b/bindings/cpp/build/gnu/config.sub new file mode 100644 index 0000000000000000000000000000000000000000..6eea72728397be8ff2576ff2874998620dd1a617 GIT binary patch literal 30339 zcmcItZFAd3lKyP{3Y_dcSu8;kNr{%?^X7Dpv+Fv)l_l3+%JwB72$6`0mjy_Qy7G^| z=jomq00b!8$z7ZhfSK-|p0}Q!o}T8zfANmSae7qFb{=}qv-CQiE{k9hXQ{Ue=J7;d z%jLMpmWw!zyfQ4}d~pb95AgY25l?3e@A30}uYZ0%IN;x*{5_Gsr}B3sf1k+TGx>Xd zAQT42$HxaA{`TcB@bNzMelDWOyUeZ^w?PqkKWEES89DG?rs3hv&LU2tauFo?vpvH5 z$4~tJlf4~~yqd+OcOB0o56{PO>g7e8hH*ZR_PsDm64Yyvc^9utj^Ue z0&rADX&8CgwHJ6v5YAX-P+2&#<#IYj*(H*Kg?IV(^@|225DJ6Tn+53vJP3>-bLe?5 z7v3a`N-xb8UYz9fyA~rv1~Z!#xn_G(SfXju4LXWb-OR`CP zeFqvyLd!)3_y8|ak(8_$KUn#{MQKz7bMM`9JdZ=~RUAfX8F@kJ7!x0f%_x0mQ4&;S6}Hf6dKI4bSgCjEZWU9;ZrZZ=5RakZi^U$1Y^I|o50?j zVF%vnxpx(zc_Q!KJivtTy~`yD42Q>T^Q?+=$3n4J&3 zixRw-c@)MNU(q^@q||&UJMAh+HA(_)0n?bQ)iv+fc$i~;?h6^z-oT<4J#%6W)^ z=doJ}4Cx`fNv7!mX^(gFC;%K}%LElzgfj>Mbj80ZqrOS{_i4I3%!=t>Ih>Z`gfm(y z7OfZ3BG;%kC`i@wsDS)H$w{zarJh6NOruxX)Qi$Zai=5ed9xuZDUQO8c*leXNr;^+ zjYCNM|3Sh=11|3J2=u^HPMIam!oI!c+-bHoK`B8X0)t|@Ou!2BESzc5WoEK4922+UM)GHSdT7@tct!0ugW+(`~(2cn(qUACSqi7<%(pW1>R4yw~Av6u-iByt(&%O;HV>oE@AiM#KC3qk$%+qX|N{a!2 z7|-8*kV4A?ue>W4QKDZ0jkd)YAg&A#E^J8@q;Wch;L@4fgHY@>mJ?R@1(qROG}{oP zEYH$19%FKnyCTZ70&6p-|11Wmv~aUuSSs4lEk07&Vu5jX1+FoK3oC$7^?-!Y3LN#I zy2MJr3VYX(SW9q?EQ624j>5d_B1@2EYBxu}0>3d%O!G(HG=qQ;`G$(wWg7(~K`yP% zMqLF(oGnXviaH{zSl~?|BU4be%e2UwYYbx1UNE*YFj1lgsLp1d^cE-24?7PZpx1uA z`sLjV|MkV24?kZ#zxwe0#e4tlyBF^-u3o#^|K`Q3F6u93hTIkupi<=LcknT(^N zj}`w*J4_xO?1PxsMse@02BI&2i=ooysYmhKwCFz+AO3 zO=cIKjCU41lTv3bT$z!(?E<}h8M0Vv7g=spW$HO0WGFh!@?Os3>%~)VTtvZ*F5)ndwR_`(cE>}3Su zPa$=^{|Zk|4i2$$e4!9wGSngA2$>;<8soo32C&be`0@7Bz`yxvXbCg zIq;)I$P|m@#!s_VU`7r&^&i^ynlH{0rOdCqjOVKsDrV?o`2+9GSM895nxZD*jS#-XnFY1dlfDAsLNRu(ikU9 zrLhvJnP41IP-Dl-l@)KQR+f6g$pR&lv1l08u}!<4wiFlgIX+) zqj`3FXa-qE@wD^6FPCW#BV>Q)0i@Tvf=dlGs5wAc-Ebbr28$Y{*i@J(x`P!}M#w#Q zfF6I~qs}67lQ@@Q=aodhB4&?n=&cAV~r3N{x%9LQf z(3wI8(2H1Juwzv|(y$O(&@@ZJ8rFv+%O1K{0A}%mHY>afm5=?wP;GW*!#q!AVq zp_L_2I0bn!Wjgw<2>7yC2#X{%gM9>w0TL(KJjZC`>kNj!Ir?kPkEvKM@Dh#_eq$q! zzX=usv;%7_&5G?~#Pnbtm+Wy&4*YFQv}affOkb9cO_C%6;hll%;#J1)D|-YgwdG30eh4 zFriPl?8=_)@K4s+R@L?i`|A(aWjVPKdViPzritxSybcck6gS~K*3sBx2gy0)x(|g0 z;;9JonH^Fn^3Sn9zk`xtE5MJ8GgGEUzUboR{&8aDer?cWJ(*;;B}A$zrF(=rup_*s ziyDEvE(!Qy`AcZWqPWBJXE#_^V9Ed%r#OL?fYl&>f-Zms)Yyr1qZSpk zYRWF%>W)oiPgS-?S+cM`^xiwwg372sRQ4%n3#WLdo~v7UtihMGZqPWD!Tw0YB8(3} zk3w09LF!J8)YiIdtUM(^WO;wke{y=v1?2SXm{R|X7YxpC%o`RDW(9mkoVRD6tIyL> z^*;Leq{_;};Pm6@$>$o8(TRl}ooo+0l2@0+}`1^4@ z|I8H&uhGZ(SePx671#Px_rZ6Yxhj;&@MH}%GhH-k(m!4yZ8FryoB)$D?~m4N1-LGT z$4I*_R{A|VgVuqB+1aT+^PG)0!=r!r@wiV0_(A5~+sE|QrlXCd{o~;i0>oz{d7SGb zaM}6bhS~q5sX;N4;h;bg#w?TMg&@h#86BZKy{g&dsPNTg zrTt@cHgoXCrqJ#wb2Nm$r|2lsPRk)ihh#&cPoV{Jeq;seE{XXh?~@RpWH|p_{+Qm( zGgwA*Vwg9nw0jq2(0u889%2|N;X51v#uNQ0XCP6|sLq~nbmJ9@Ee9OlkR(H{oXHR@ zp_JC3&Brjpix4hn!UP{K2|IT(S@Nm5d^;O)ib~=f%7lI8DVTX*v2_Jtbv`!a7qs6} zfJkYJV3rYlF@xQa&sZe`o)C}t2DC!1Fw2p^hvD=#a&5mpqikH4Ft?D}S~k~rm`iwH z;M6uy8vk>4!?mrk8a!)mWc_7&lV-Qrddb>~DK7nn=Pa~ueHpouG9W!1iJHxhH#+bCxWKW2Vid{Ty+vc2 zwnB%PDz6IrIxe}U+ON=U$HO5Lzjz4w#R9a9$tP~I{ zHU;v;z5Y0`uWn>Qv4Kd^Wav2hLM;bx!UES}O~s2D2uw5mFRyb4AmhW~^;t*vWri>@ zxav2vWaLzu%VxG{JFb+`iP3&GX;A;EL0Ju`1%`#c2_{<5CKwf;2AFC>buiI?9E^N5 zS(l{3v^#2UzFR=G#sSD?`$!V>qIyZA6C`xd5#4A5P_?5v<5Y?qkZMRSTa+RD#pO!? z(_D*BSLR7QNpq+vS$Nx1((R%n35;k-`u4kd=%~q4{iMExH$_wBsmjQqn>4?SAaW{{ z=2D4rL{yEkpD?550#uZ+9kO4gsB$KWR>QI%)UoWlXj$f?B2Q(@LWpwaKB;h-9K*G0 zTu9R*sbMLAYF*Vk^sedynpf=ux);7G0xRu4tAZ({)xh-2bX2+i(PD~DCYhp@x#ZZ2 zWl_=;Aa>#yiKj*&1hQy$78JUj?GP6!~ zK25b+pTiW@&wkxW*Gk(!NmBJdHH)Stz`9ddy?{G^J@~ek2X!OC*@0?9Joycr=|Ik| z=pm$b1D<5@>_E;@)w2$I%iBw+0mHKq4uskYX^f1T8cOvLa7H^E%D#t&cPw#y&=}7J zc(L$JY95-GGPs641(`6nuXC|}H8h-Ox`8DHN4>*HrM*!BQD?ycYnyRVW`cyQlIi6n zHe`cIHjZH6X`_$>tSkax&|m^xT7IB;#&A4D6|S-1w$Yi2lK}y;W$~PV4Z`Q}cy!jr zLZPrVG2h}Os8SnF>SHwXW-p+UqP}iyCCm_|)+)OPfCaO8n=lnX&9imBD_0IDo{9}9 z!Ba-DX?bt=b=v1diKQG>r=v za#pjw!6mz+!UnB#E@)TPF{`N%EVuC(@F2yM1SrGbIG6|UU2fM)Hu3f(%%Dx~&=LkQ zJntBKNW>XYaA)A@u@z8`m>o*m9vPxTgJP{9agprH z(IqnQ(#BHdNzphV;TMCoag)Zt(!k5N(HK-TaH5MU@Q4==d#vkke#^-(RS)%BQ3T(D zOB;ZYOK5W;Q{BS53IOMSzJj%A%n~%+~|5JK?jdUyXt{Ue4zReVmnc!V`;I zNO}5%*}`rOos!U&9*uF2V*8R(Es+9fSe9LAyByt|%3sTrjvRx zm>SlH^DL*H*&#S&K+JN>6v4Ky;sVF!ua-O^Jj=JP;|_%|RVg>;a*8N_Fji-I?Ymt! z?Lo9j#pn6WV3WelurEn%d{mNK!3O&9;{eB)+YxS>;G>PwYTxbhI{AG93QtUlQssKW zHX0bU^*TQ}6E+lG--!vY#Fzi|`o$0MwGu-w%cp%xaJNi`I@vQGJ@Ra0me*d-Z(wE` z$Y})9t5>A+=#mEmgm<>q1H&a?I^4QH{YlnLSCCYh&Hq$I;UWi>)m0UHe;OXz{K*o=EHjkMD>q(} zwSqkY!<>&T$jzM_0c|x@b&l~k>99wLVhT4vK&v-}@l6y>&j*&O*|G<9>Ed5qKe8b`Su+fuXeRKAV|rAOBo)T-uB zgRkD}_|27liooiaFw(N!UN#Td5JPip))f0@nl%zplDkQBB&hOtbW%A4DZzF>eJ{BU zV@Hy7x?VBaze$%1H$jlV>(REMaeogUscm+oO)L)An{tge ziY)_fi!3`WF&o2yKo()up+nXLvlOwi(C~VN!qqXZ;}aMVk!z~M`D2BjI-x_zwA(@0 zYRU+OHq7CJzF$#C6XNu5bu#yh2tH1xQ1OL#nBta8?_31+jqNwx$28& zbJCOLA2&8OJrJa>R1J{RAz`i3z$+;m&{$Tub~<@F`v@PeZafO*t#}wucR12)H%ZKcPKY@-p5R3=vAZ8^uD=aQ z0l_af*K+wI}V1J9n{-36D4%i~+9kx6kc8O!R1zL3h;ee%OCrqpYotA~qbA%{q zw?UO>=x6!qu^xnF`REv@Lv0+ZH^LX()TE&Xier-cCv{;ndqbktWTDs!(8-uPVlC+I zZ{00zwGw0{B6p{D0^qE&3nUL~!ige1M@nxS=y!9UhvGbFy#?Uit=}l5p5f0Wr`={2F=}(U z;fNpvx|+Qr@dvoaiDY-H;ncj+>rA`xBz=Fw`OcJ%tUpwGy^-KNT5CU0Y-WC~4e5K@ z#dEVAZ6Wuxq!9Y<+LRqTdQp#SW3+pxM}bqdHCM8{+Uw~iqdjnB$=J37fs;KwwK{Yp z)l%aKK}779pje1EF&|xxBJM3!9m?T37jr(kpe4NtEe^i`$Kh7H8iZfhrg4e$bNKhQ z0k`@Iz*nga&1yQ=rmAf@j>Wg>ehm0NZQw**76(!IqZk5+eO5+LAdE0F7iHR|$bc}p z7PiA~1K*(y<-}Rz>G9L1%hXMt=>mia75TWH#~zE5GUIy(b{*7Ir@F`|jh2^B+ITVs zH;%KcjiSt#9h*L;Zt}UHKj#+Ws^;33!s+Z{*}=c)WQf_tT*H2S|BB0*9di@Rqg>wH zwB!K>?~hJSDoE*So-T7IBuyh|9evU$z@gbqHOd`sEA7T`<&bJ+0jayJ7E-OGlg^S< zHPr^_DhgN~MRj7;%j!06w$Pe3Og0AxDIQ&7LPnZ$YTEoOoEaz>EezGO5jD{w3ns-f zMU1v~H|yN2hC|oJtnAvD*@1AEz-6oGIGEd*^=#|9tH@&5VaPMrxlY^rKvUeJ%QFIr z+Y!X?4vj$fyADxIXFRw`SCWr>*0yr$tS9)V+wkGccOSl7{(zrfcj@r|+l~yc(sq|o z%!|Kig~yIpuhZ?|E&0B{u;^Gt)K6l4W9?J)lW;x`3%Zh`HROrg;~m9e*J?~^I!j9sZV`9r@+A(_;91MQX;-1$Gi+Bes%-~WLz)7@=JqXs)Uw-f8@jjpA9aAK z<9VfaV)O}Y)i8M+;I#LK1aL(aKkTQkWRR| z!_69QBa=Jd#g;_4#|b%;$iU{-ysQKwEC0Xm%s*W6t{&7 z==qa)3KuX&^V*y<_nQ|C9$Xx-`c{XdJ)SopP9FpAd@o6d38IK6QzJ@B=x^H!KWW5- zdL4ZmAF(rzLMtc{q83WDr}gfmtlVXkr}geG!aPCfrj1BNdc5R$HpZC_5Q&-uUBgED zw1rBzC!&}LP4HSrkZgt|F;_yph8h&&o)TLe zQy>7V2)n?xxb#?Z?}yR{Sl3KnHlwn9F~#-2VB3O?)R$VM7-fX*E~{vBC*+s7TxLl( zeC08<^mMwJdpKC$Y8O6W*svoxMYSN^yg9HhF8o-tIw{oPfpCU^KLC@& zt5n{oZJR`KPpP{l`#os00)>kv@{CFgix@2=6qs-6Z5bx)c3!0K)%=^`Acu%V%x12< z;QUCQ^JS`WuO?Fi;sz|h%ezGGXz7$;d3t?A%QhD{9EpxOvR5G4%M(;y3AP92_Z~?%VQW&%ot_ht%>C z;8Kyiz$Z?gSujTYu6jioMu!D)pRAznO+wvB+9XR5a7JF~LDi&y{hlHUZIGhP&a_e# zX=F7z9}5sJrZll_@GQx7QL;8*?xx^HAaWC_4Q>(g4INltbgv<41q3e=>$NoQN0RL% zhI}p8IVLB#9!HjB9+|#p^rZ$F9-G=ZwzMoIH_AaV3lRTjBJtw7Kj8xwX)XhdHjqRbp*MmAntJP3aM5K6~z| zm(d9>$QzD+h=K_P!DZGw{d^lBlc>~1nQ;G-27oUHt6Iu@6YegOs|(UrR%FpJo{c0< z1Cqntsl2St&fwi&?=f}(!dyu%L2WJCNidB~ zSViM=rpe-_BCm7GZ>hAj07%^50s#0T<<#o`4Z47Ubm;-y%4DV5H@0gz0%Mh(L9J-P z9^KEf!dUEK4cp9m_CIwb{gklEc0{00LREtaAYV2MOKJgc6I(X=SiWo7^(>oA2Thk= z-8WEEZC6HsD2gr}tEeT!m?`LO%e#KsOkK=uUagpLVZ|n7jm@VnV=+y1S8Wg{B3y1c z5LYiYhF#6p|rdH0QUu_aWun^dc@>7wG;`gQx``qm-Wr(c8pQX zU*j>983_|1!eQso-x#{?0FP{98Aq4y?3NGz!X_R{!Gls%Z| zrkObu)D?KXa5VOO_Ek4qE_GP{)GyZa_KKYv?Aehml6aFd)%O=Km9T8fTA zMZIOtBaML9Xvq_lAdnG8>c8ZGO*CVIGMv&z%fmKX`z;ZTzBtZS{1G4dU7<3brucmd zVCqklfKjOxBYc0Q1dz}HBtfMRD0vT6ND(f#5HkQPB|p=HX2Ra{9=i-y<3jw7II(n( z(3jYroE~sY?x|a{ok+4on#m)%Wt50R0MWTg&^+$VY{VfPmNDdz3*(LsH-~AugR=pu zuE=mDfW{H*ODc|GJwi}k^ay`5jn+jTUpr=(uy?T`^THbHeWZo zC$7FQ{PkeNW6Wd=q8k=dV|y-YGiA{}IXtctFz4e95DH);VHq2nKLo&^_<}8-Og*E>ehtl28f`W$k&uW_^A-oTuV2s3F{Ke*p^)NhTKhn#f%$Jn_Jy& z;>n@8w?L{@hPbo3wyGU}_UOd94=$v)ASp~=iD_8-iBlf|=4p~*74=s~ocL_4N_rel zJ+H?qSq4qp_7CleUJn~9n@P3ORJ=!*8JiB%gG)vrXPewOKI&0Js>OEpH*#@gu?24? z=MrqB+J(xV^-r-#+^icWT;M5;DhV?JANG(ZrT8{+HhS(Fwj@`#RV+EKyRJ?!SK9Pu z^a%{_sm-C)#9^3-+BT2WI2t*-#mpT-s@qIhAZ(Vq3*`ErMj1zyYE?_ea=A61A2t>Y z11^gZ2W)ZFmt98clEn^X(&h4oV*$363jUsJf%we;#tXOQG+NLd2-w_8@9g<{$-65D z_qS{^O=6CXQvJtl9*eSS7<$&kC%3s(``RdJ=CBuCFR{|hr-i3Q!IgwF665;KHf_wt z9yVYWr;#DY5jICQM2?)?VyarU(x_ZoB|Js*xQ@5z9kOWNiZv25p3xs=%4aw?WAq+Q zfBU;tD%fbeq)?-tQ2ii){&YYdhc|*U&#)=P;@AMekK#}hd1jBWw(YzdM=uIwFWo(` zhA=kEg9nD7tb&rjiSa;wH^8Wm4h90L4nZqtgNB|tn(h4qwE{H&#+2hOU(BD4e7P~~ z@)I#0-2>om+&c~{M>$7DY^x0-Cgz8O5F2X)Vlu7sDaP1FzP%&pNT}tw0V6Jz4nT~e zv@oavs{y&uY&ICTt5oG8=*V^3VriM6ai~FEy%iiLjfRbUdtm1vXcTEcbTlds4UOS~ zri=!3i{AI`Zd|SHB}2y-t!s^vDknb!V~j@4b5OHUX(U40@b2Mmd1U6%(IcG(N4qA3 zzmVF|pU!EZ(nuxoJC7+0Uh(&N^mo(nn{N0)u7`-w70iFYuW?Q$@W9A!ygm6{NS{Bw zCJCjtSN;0dJ`k!e{vubg_`%zCznS!GZ?_4dzv2Xtzx;6L|K)g)@Xure2qFRyg8Bll GJO2ylD=8@e literal 0 HcmV?d00001 diff --git a/bindings/cpp/build/gnu/configure b/bindings/cpp/build/gnu/configure new file mode 100644 index 0000000000000000000000000000000000000000..69070c66d4f20c3c0d865bd202095a8f649f1eaf GIT binary patch literal 126971 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 J@?Ix8@=wG#YQq2k literal 0 HcmV?d00001 diff --git a/bindings/cpp/build/gnu/configure.ac b/bindings/cpp/build/gnu/configure.ac new file mode 100644 index 0000000..5457c53 --- /dev/null +++ b/bindings/cpp/build/gnu/configure.ac @@ -0,0 +1,214 @@ +# +# PortAudioCpp V19 autoconf input file +# Shamelessly ripped from the PortAudio one by Dominic Mazzoni +# Ludwig Schwardt +# + +# Require autoconf >= 2.13 +AC_PREREQ(2.13) + +AC_INIT([PortAudioCpp], [12]) +AC_CONFIG_SRCDIR([../../include/portaudiocpp/PortAudioCpp.hxx]) + +###### Top-level directory of pacpp +###### This makes it easy to shuffle the build directories +###### Also edit AC_CONFIG_SRCDIR above (wouldn't accept this variable)! +PACPP_ROOT="../.." + +###### +###### SET THIS TO PORTAUDIO DIRECTORY +###### +PORTAUDIO="$PACPP_ROOT/../portaudio" + +# Various other variables and flags + +PACPP_INC="$PACPP_ROOT/include" +INCLUDES="-I$PACPP_INC -I$PORTAUDIO -I$PORTAUDIO/pa_common" +CFLAGS="-g -O2 -Wall -ansi -pedantic $INCLUDES" +CXXFLAGS="$CFLAGS" +PALIBDIR="$PORTAUDIO/lib" + +# Checks for programs + +AC_PROG_CC +AC_PROG_CXX +AC_PROG_LN_S +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_PATH_PROG(AR, ar, no) +if [[ $AR = "no" ]] ; then + AC_MSG_ERROR("Could not find ar - needed to create a library"); +fi + +# This must be one of the first tests we do or it will fail... +AC_C_BIGENDIAN + +# Transfer these variables to the Makefile +AC_SUBST(PACPP_ROOT) +AC_SUBST(PORTAUDIO) +AC_SUBST(PADLL) +AC_SUBST(PACPP_DLL) +AC_SUBST(PACPP_INC) +AC_SUBST(SHARED_FLAGS) +AC_SUBST(DLL_LIBS) +AC_SUBST(CXXFLAGS) + +##################### CHECK FOR INSTALLED PACKAGES ############################ + +# checks for various host APIs and arguments to configure that +# turn them on or off + +AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no) + +# Determine the host description for the subsequent test. +# PKG_CHECK_MODULES seems to check and set the host variable also, but +# that then requires pkg-config availability which is not standard on +# MinGW systems and can be a pain to install. +AC_CANONICAL_HOST + +PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no) + +AC_ARG_WITH(alsa, + [ --with-alsa (default=auto)], + with_alsa=$withval, with_alsa="yes") + +AC_ARG_WITH(jack, + [ --with-jack (default=auto)], + with_jack=$withval, with_jack="yes") + +AC_ARG_WITH(oss, + [ --with-oss (default=yes)], + with_oss=$withval, with_oss="yes") + +AC_ARG_WITH(host_os, + [ --with-host_os (no default)], + host_os=$withval) + +AC_ARG_WITH(winapi, + [ --with-winapi ((wmme/directx/asio) default=wmme)], + with_winapi=$withval, with_winapi="wmme") + +# Mac API added for ASIO, can have other api's listed +AC_ARG_WITH(macapi, + [ --with-macapi (asio) default=asio)], + with_macapi=$withval, with_macapi="asio") + +AC_ARG_WITH(asiodir, + [ --with-asiodir (default=/usr/local/asiosdk2)], + with_asiodir=$withval, with_asiodir="/usr/local/asiosdk2") + +AC_ARG_WITH(dxdir, + [ --with-dxdir (default=/usr/local/dx7sdk)], + with_dxdir=$withval, with_dxdir="/usr/local/dx7sdk") + + +##################### HOST-SPECIFIC LIBRARY SETTINGS ########################## + +case "${host_os}" in + darwin* ) + # Mac OS X configuration + + LIBS="-framework AudioUnit -framework AudioToolbox -framework CoreAudio"; + PADLL="libportaudio.dylib"; + PACPP_DLL="libportaudiocpp.dylib"; + SHARED_FLAGS="-framework AudioUnit -framework AudioToolbox"; + SHARED_FLAGS="$SHARED_FLAGS -framework CoreAudio -dynamiclib"; + if [[ $with_macapi = "asio" ]] ; then + if [[ $with_asiodir ]] ; then + ASIODIR="$with_asiodir"; + else + ASIODIR="/usr/local/asiosdk2"; + fi + echo "ASIODIR: $ASIODIR"; + fi + ;; + + mingw* ) + # MingW configuration + + echo "WINAPI: $with_winapi" + if [[ $with_winapi = "directx" ]] ; then + if [[ $with_dxdir ]] ; then + DXDIR="$with_dxdir"; + else + DXDIR="/usr/local/dx7sdk"; + fi + echo "DXDIR: $DXDIR" + LIBS="-L$PALIBDIR -lportaudio" + LIBS="$LIBS -lwinmm -lm -ldsound -lole32"; + PADLL="portaudio.dll"; + PACPP_DLL="portaudiocpp.dll"; + SHARED_FLAGS="-shared -mthreads"; + DLL_LIBS="-lwinmm -lm -L./dx7sdk/lib -ldsound -lole32"; + CFLAGS="$CFLAGS -DPA_NO_WMME -DPA_NO_ASIO"; + CXXFLAGS="$CFLAGS" + elif [[ $with_winapi = "asio" ]] ; then + if [[ $with_asiodir ]] ; then + ASIODIR="$with_asiodir"; + else + ASIODIR="/usr/local/asiosdk2"; + fi + echo "ASIODIR: $ASIODIR" + + LIBS="-L$PALIBDIR -lportaudio" + LIBS="$LIBS -lwinmm -lm -lstdc++ -lole32 -luuid"; + PADLL="portaudio.dll"; + PACPP_DLL="portaudiocpp.dll"; + SHARED_FLAGS="-shared -mthreads"; + DLL_LIBS="-lwinmm -lm -lstdc++ -lole32 -luuid"; + CFLAGS="$CFLAGS -ffast-math -fomit-frame-pointer -DPA_NO_WMME -DPA_NO_DS -DWINDOWS"; + CXXFLAGS="$CFLAGS"; + else # WMME default + LIBS="-L$PALIBDIR -lportaudio" + LIBS="$LIBS -lwinmm -lm -lstdc++ -lole32 -luuid"; + PADLL="portaudio.dll"; + PACPP_DLL="portaudiocpp.dll"; + SHARED_FLAGS="-shared -mthreads"; + DLL_LIBS="-lwinmm"; + CFLAGS="$CFLAGS -DPA_NO_DS -DPA_NO_ASIO"; + CXXFLAGS="$CFLAGS"; + fi + ;; + + cygwin* ) + # Cygwin configuration + + LIBS="-L$PALIBDIR -lportaudio" + LIBS="$LIBS -lwinmm -lm"; + PADLL="portaudio.dll"; + PACPP_DLL="portaudiocpp.dll"; + SHARED_FLAGS="-shared -mthreads"; + DLL_LIBS="-lwinmm"; + ;; + + *) + # Unix OSS configuration + + AC_CHECK_LIB(pthread, pthread_create, + , + AC_MSG_ERROR([libpthread not found!])) + + LIBS="$LIBS -L$PALIBDIR -lportaudio" + + if [[ $have_jack = "yes" ] && [ $with_jack != "no" ]] ; then + LIBS="$LIBS $JACK_LIBS" + CFLAGS="$CFLAGS $JACK_CFLAGS" + AC_DEFINE(PA_USE_JACK) + fi + + if [[ $have_alsa = "yes" ] && [ $with_alsa != "no" ]] ; then + LIBS="$LIBS -lasound" + AC_DEFINE(PA_USE_ALSA) + fi + + if [[ $with_oss != "no" ]] ; then + AC_DEFINE(PA_USE_OSS) + fi + LIBS="$LIBS -lm -lpthread"; + PADLL="libportaudio.so"; + PACPP_DLL="libportaudiocpp.so"; + SHARED_FLAGS="-shared"; +esac + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/bindings/cpp/build/gnu/install-sh b/bindings/cpp/build/gnu/install-sh new file mode 100644 index 0000000000000000000000000000000000000000..e9de23842dcd44d2953129c866b1ad25f7e1f1d9 GIT binary patch literal 5598 zcmbVQZExH*68^mU6_fR*TL=3RUoUsp7zToC(AGFO3GCo{K#`oe5_iQ~5(Sa+W|8K< z-!nr}yH1>@xd6e+A~`S5%seyH(Szm6G)q@zN7)gX#(7m$G#{Q6wVmB`s-BU{JJb3Z z*^Ub3)!I}VM_!l4QEqGPXx-VG{&RA2`Gmf$jbHZORLgM6Eu-j#D~}hV>j&HJIbGnmot zW>nk4tnphI=R32)=^3e}AgAG(XLFrh`>pDC)*8|Q(XA=))|bjd7(1d?_Ew8U!O6yYljC*UYSjT=Vw_>H z0dQ;`AElM`WfH>9+&wD0U`o69{1d6JZ(G}W(`-I=Du5tr*uF;9g6hTMeDQig5JW4@ zFcxB5ajPN4K@Q>#QEk7fOl~|d!GbakuK@P}WQGkvV$lP<2_)C*+^kJLgP?6^yw?pd zGXQz-%7Q4GQmY$a(pc(r+i91A0+?2eI5a?v>y1|{Q?W&&_Asm;g%6_7J;!i}(^xtD zJ!W%a9Q8Za@#)1U^3QrB0hc=Apo0fDR{E-%WVR00ypQVPtljBN=Bfdq0GegUfs$mAoz zSSiX-dAyGDY$10AiR`Zg>7Q56lZiuRqgLRxOEH2T(Fj4x=VgE~SBP^{?S{j)(ZN{c zuOe@1E;q!Ei!bMDf*4n#+CtG#&4u;yYKjO%wuubm7Fou7wWsGV&tJc~eEAathpM;y z>md=AbDRZz-uv7(Q_o3DPv?YWMS=Zw@g2LyC51vmAUkMBLSZvg_A=gQfNnFq*~uysv4+eaCtLTLm2nm6J#@)(;=IeFL?-P|tdR(0%9 zeaqglo{N98NAvm?dh#~C{o$3o&0Bt3g1UxAMe zu|NNG86}r^jb#qUuzdCU@;ofdYbzl%KY2o5u&(AMqO1l=|#W5H$=<;2!zp%SLCUHM%Na3f+Uq03I zS(TQBB+MrA$PxQGAsZHwz=n{RN?#|$9n(HalOf?g_2n*R{_N2)4VlC_b1gNGF#HZS zC}`@IbAPs6POra!=jx86At&zW8ML5(p99MI86y@i!o z$P+^3JP=EdKnpcZ7;z87Kgf)h1hY5=j_7=S=NK|t4ftWm z=6P1;QZ&^ex409W#+HfpyK`RG5HSoewYqg_BBgP1k zDlos}l0g{%O+H|o5^VsKb25OjyiWBmK!Q3xc24|@<;pY@bA@!>R|?YxCoj7ylX6NV zD8Q@4P@Ls~qvjekHT(7L^39{kYCB9|7u&SgVk-!Dg8>3Wx!}*Uqg_Oeq>FUO`zzkO@49VEwWuz3e z*}LBL3bzn6y+x?@2b`n=AOwwv3NG|o^_4&W@#<_k%BC4VV5Gs%eDZ$3_7nt;FcGpyA88a!E{5_R6=o>}2e!z~A29FRF&IYJ7J z-3~ktkPc^ODT#!U`&usmX}TTCWL!m9k41;YVCOb27?5D zW5Q` +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=devs_example - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "devs_example.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "devs_example.mak" CFG="devs_example - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "devs_example - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "devs_example - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "devs_example - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /O2 /I "../../include/" /I "../../../../include/" /I "../../../../src/common/" /I "../../../../../asiosdk2/common/" /I "../../../../../asiosdk2/host/" /I "../../../../../asiosdk2/host/pc/" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 portaudiocpp-vc6-r.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../../bin/devs_example.exe" /libpath:"../../lib" + +!ELSEIF "$(CFG)" == "devs_example - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../include/" /I "../../../../include/" /I "../../../../src/common/" /I "../../../../../asiosdk2/common/" /I "../../../../../asiosdk2/host/" /I "../../../../../asiosdk2/host/pc/" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 portaudiocpp-vc6-d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../bin/devs_example.exe" /pdbtype:sept /libpath:"../../lib" + +!ENDIF + +# Begin Target + +# Name "devs_example - Win32 Release" +# Name "devs_example - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\pa_asio\iasiothiscallresolver.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_allocation.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\pa_asio\pa_asio.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_converters.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_cpuload.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_dither.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_front.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_process.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_skeleton.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_stream.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_trace.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\dsound\pa_win_ds.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\dsound\pa_win_ds_dynlink.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\os\win\pa_win_hostapis.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\os\win\pa_win_util.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\wmme\pa_win_wmme.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\os\win\pa_x86_plain_converters.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\pa_asio\iasiothiscallresolver.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_allocation.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_converters.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_cpuload.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_dither.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_endianness.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_hostapi.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_process.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_stream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_trace.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_util.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\dsound\pa_win_ds_dynlink.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\os\win\pa_x86_plain_converters.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Example Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\example\devs.cxx +# End Source File +# End Group +# Begin Group "ASIO 2 SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\..\asiosdk2\common\asio.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\asiosdk2\host\asiodrivers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\asiosdk2\host\pc\asiolist.cpp +# End Source File +# End Group +# End Target +# End Project diff --git a/bindings/cpp/build/vc6/devs_example.dsw b/bindings/cpp/build/vc6/devs_example.dsw new file mode 100644 index 0000000..480c4d5 --- /dev/null +++ b/bindings/cpp/build/vc6/devs_example.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "devs_example"=".\devs_example.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name static_library + End Project Dependency +}}} + +############################################################################### + +Project: "static_library"=".\static_library.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/bindings/cpp/build/vc6/sine_example.dsp b/bindings/cpp/build/vc6/sine_example.dsp new file mode 100644 index 0000000..2539cbd --- /dev/null +++ b/bindings/cpp/build/vc6/sine_example.dsp @@ -0,0 +1,252 @@ +# Microsoft Developer Studio Project File - Name="sine_example" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=sine_example - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "sine_example.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "sine_example.mak" CFG="sine_example - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "sine_example - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "sine_example - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "sine_example - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /O2 /I "../../include/" /I "../../../../include/" /I "../../../../src/common/" /I "../../../../../asiosdk2/common/" /I "../../../../../asiosdk2/host/" /I "../../../../../asiosdk2/host/pc/" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 portaudiocpp-vc6-r.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../../bin/sine_example.exe" /libpath:"../../lib" + +!ELSEIF "$(CFG)" == "sine_example - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../include/" /I "../../../../include/" /I "../../../../src/common/" /I "../../../../../asiosdk2/common/" /I "../../../../../asiosdk2/host/" /I "../../../../../asiosdk2/host/pc/" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 portaudiocpp-vc6-d.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../bin/sine_example.exe" /pdbtype:sept /libpath:"../../lib" + +!ENDIF + +# Begin Target + +# Name "sine_example - Win32 Release" +# Name "sine_example - Win32 Debug" +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\pa_asio\iasiothiscallresolver.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_allocation.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_converters.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_cpuload.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_dither.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_endianness.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_hostapi.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_process.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_stream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_trace.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_util.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\dsound\pa_win_ds_dynlink.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\os\win\pa_x86_plain_converters.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Example Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\example\sine.cxx +# End Source File +# End Group +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\pa_asio\iasiothiscallresolver.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_allocation.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\pa_asio\pa_asio.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_converters.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_cpuload.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_dither.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_front.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_process.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_skeleton.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_stream.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\common\pa_trace.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\dsound\pa_win_ds.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\dsound\pa_win_ds_dynlink.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\os\win\pa_win_hostapis.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\os\win\pa_win_util.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\wasapi\pa_win_wasapi.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\hostapi\wmme\pa_win_wmme.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\src\os\win\pa_x86_plain_converters.c +# End Source File +# End Group +# Begin Group "ASIO 2 SDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\..\asiosdk2\common\asio.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\asiosdk2\host\asiodrivers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\asiosdk2\host\pc\asiolist.cpp +# End Source File +# End Group +# End Target +# End Project diff --git a/bindings/cpp/build/vc6/sine_example.dsw b/bindings/cpp/build/vc6/sine_example.dsw new file mode 100644 index 0000000..04c4714 --- /dev/null +++ b/bindings/cpp/build/vc6/sine_example.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "sine_example"=".\sine_example.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name static_library + End Project Dependency +}}} + +############################################################################### + +Project: "static_library"=".\static_library.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/bindings/cpp/build/vc6/static_library.dsp b/bindings/cpp/build/vc6/static_library.dsp new file mode 100644 index 0000000..d33ba9f --- /dev/null +++ b/bindings/cpp/build/vc6/static_library.dsp @@ -0,0 +1,395 @@ +# Microsoft Developer Studio Project File - Name="static_library" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=static_library - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "static_library.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "static_library.mak" CFG="static_library - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "static_library - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "static_library - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "static_library - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /GX /O2 /I "../../include/" /I "../../../../include/" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../lib/portaudiocpp-vc6-r.lib" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../include/" /I "../../../../include/" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../lib/portaudiocpp-vc6-d.lib" + +!ENDIF + +# Begin Target + +# Name "static_library - Win32 Release" +# Name "static_library - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\AsioDeviceAdapter.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\BlockingStream.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\CallbackInterface.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\CallbackStream.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\CFunCallbackStream.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\CppFunCallbackStream.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\Device.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\DirectionSpecificStreamParameters.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\Exception.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\HostApi.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\InterfaceCallbackStream.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\MemFunCallbackStream.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\Stream.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\StreamParameters.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\System.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\SystemDeviceIterator.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\source\portaudiocpp\SystemHostApiIterator.cxx + +!IF "$(CFG)" == "static_library - Win32 Release" + +!ELSEIF "$(CFG)" == "static_library - Win32 Debug" + +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\AsioDeviceAdapter.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\AutoSystem.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\BlockingStream.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\CallbackInterface.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\CallbackStream.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\CFunCallbackStream.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\CppFunCallbackStream.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\Device.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\DirectionSpecificStreamParameters.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\Exception.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\HostApi.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\InterfaceCallbackStream.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\MemFunCallbackStream.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\PortAudioCpp.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\SampleDataFormat.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\Stream.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\StreamParameters.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\System.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\SystemDeviceIterator.hxx +# End Source File +# Begin Source File + +SOURCE=..\..\include\portaudiocpp\SystemHostApiIterator.hxx +# End Source File +# End Group +# End Target +# End Project diff --git a/bindings/cpp/build/vc6/static_library.dsw b/bindings/cpp/build/vc6/static_library.dsw new file mode 100644 index 0000000..cb9d090 --- /dev/null +++ b/bindings/cpp/build/vc6/static_library.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "static_library"=".\static_library.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/bindings/cpp/build/vc7/OUT_OF_DATE b/bindings/cpp/build/vc7/OUT_OF_DATE new file mode 100644 index 0000000..e69de29 diff --git a/bindings/cpp/build/vc7_1/devs_example.sln b/bindings/cpp/build/vc7_1/devs_example.sln new file mode 100644 index 0000000..c443bce --- /dev/null +++ b/bindings/cpp/build/vc7_1/devs_example.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "devs_example", "devs_example.vcproj", "{1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}" + ProjectSection(ProjectDependencies) = postProject + {D18EA0C9-8C65-441D-884C-55EB43A84F2A} = {D18EA0C9-8C65-441D-884C-55EB43A84F2A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "static_library", "static_library.vcproj", "{D18EA0C9-8C65-441D-884C-55EB43A84F2A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}.Debug.ActiveCfg = Debug|Win32 + {1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}.Debug.Build.0 = Debug|Win32 + {1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}.Release.ActiveCfg = Release|Win32 + {1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}.Release.Build.0 = Release|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Debug.ActiveCfg = Debug|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Debug.Build.0 = Debug|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Release.ActiveCfg = Release|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/bindings/cpp/build/vc7_1/devs_example.vcproj b/bindings/cpp/build/vc7_1/devs_example.vcproj new file mode 100644 index 0000000..fc065f8 --- /dev/null +++ b/bindings/cpp/build/vc7_1/devs_example.vcproj @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/cpp/build/vc7_1/sine_example.sln b/bindings/cpp/build/vc7_1/sine_example.sln new file mode 100644 index 0000000..7be7c58 --- /dev/null +++ b/bindings/cpp/build/vc7_1/sine_example.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sine_example", "sine_example.vcproj", "{1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}" + ProjectSection(ProjectDependencies) = postProject + {D18EA0C9-8C65-441D-884C-55EB43A84F2A} = {D18EA0C9-8C65-441D-884C-55EB43A84F2A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "static_library", "static_library.vcproj", "{D18EA0C9-8C65-441D-884C-55EB43A84F2A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}.Debug.ActiveCfg = Debug|Win32 + {1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}.Debug.Build.0 = Debug|Win32 + {1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}.Release.ActiveCfg = Release|Win32 + {1B9A038D-80A3-4DBD-9F0D-AF10B49B863A}.Release.Build.0 = Release|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Debug.ActiveCfg = Debug|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Debug.Build.0 = Debug|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Release.ActiveCfg = Release|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/bindings/cpp/build/vc7_1/sine_example.vcproj b/bindings/cpp/build/vc7_1/sine_example.vcproj new file mode 100644 index 0000000..b1c7b62 --- /dev/null +++ b/bindings/cpp/build/vc7_1/sine_example.vcproj @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/cpp/build/vc7_1/static_library.sln b/bindings/cpp/build/vc7_1/static_library.sln new file mode 100644 index 0000000..36f2ac1 --- /dev/null +++ b/bindings/cpp/build/vc7_1/static_library.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "static_library", "static_library.vcproj", "{D18EA0C9-8C65-441D-884C-55EB43A84F2A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Debug.ActiveCfg = Debug|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Debug.Build.0 = Debug|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Release.ActiveCfg = Release|Win32 + {D18EA0C9-8C65-441D-884C-55EB43A84F2A}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/bindings/cpp/build/vc7_1/static_library.vcproj b/bindings/cpp/build/vc7_1/static_library.vcproj new file mode 100644 index 0000000..d67324e --- /dev/null +++ b/bindings/cpp/build/vc7_1/static_library.vcproj @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bindings/cpp/configure b/bindings/cpp/configure new file mode 100755 index 0000000000000000000000000000000000000000..608a95dd2fb2629e568551b50b0a8b628dba10f3 GIT binary patch literal 702299 zcmeEv|6dz7^8U~9U$N)V8Ys3Q*Y>VZ_l_9SaOK-4kT!kCsWG+zUySW~?EshNfB!ts z%t)(UuYvZ`Z}&>>ig&frNE(esqtVRh;a{TaX>U-CFA5K%uczHOj^4ET_>Inn<0!s~ zC*8|(r#tEnI^Dqp-^RVxX&;|kgHF^QcUzNgwAXswJ?kN{LKxjacZ}3dbb1qgz5hJg zoKA-A;ovNKRQY^WpdJp#lg(+TH>{6F(b^-FLb>{IbTjUqUreIK`cky^#TSoO`1h~! z_fz@%nf(1+{{CJ5ez6igT3ub0ziTUif;W`IUzEdNl*37d`c>=6;8?)b77$EYcq3;}<1vl4ZB@nqaPodSKtBf_&Jcx=5 zZ~yP;Y4h9dXGc2+`=7+!$-83o@yF3(_j20jD90B|(O1<@_f2&$?f0WcUwynLm>3kI zD9MAD{pY*8^}VgyI-Va!|A*%OwQ?=J{1m@H1}N(?j;@B|P85&&y~(6EIFEpwg|};; z6c_$ke76!^UG&-)QeH=7GH#7;h&^;6n#Qg3E;_x{i%E+Z4h|7W5rbAiAt0s|N9FUV zsO}#$zurA~+&p^z_~^LM?Z;hwYq#QVbh3ynQF*w8KKlNiM7=?@ zJQ~Km>*XcFK!!+OH#VYf+-eujdWFY3`^}@Lwd>LOr%1dWfzBgM10pz|j>pr_KP_xM z-`uTl9&OivK+ENlEZ^QYN5FT1<94`t{4^SLyPY_yKg0Xxn_;gL>5L@arXygke$g7Y z+LP`$de$18b0W6lW_#T1cPB`UYo*p{yVE^8zv%t@b^mfO9Q`!&;a`et`;|KRZdJv%yn{_S@!zW+a;)u1k!+W6{;efRIgXv|>6;g=yriIw~V@$MZjBa6oTm7rnO&kf2sCdc+*%Cv| zqwT}ZXPd_d&x~^aQsW>c1lqnBM#YDo*%hO&IL{XrDnK*nm!G3z_qsQUR*O*-eU4#t+8}Wn9nO5^Tmpeb z(fBedpCuKL>VT)C=}3reIv{0UU33Se&6smsP_-B>?rrYu);?d|0AFGrzAi;S{R9H+ zP3AWfBP{uA^4CohpL*8fykQ&Ah@B@#`1@T~s1-B2)$XoDlh&zB{XzFC>h}gn!8{s` zyX{`w?PEq?v?dW4L3fP#{QssyVFkSyaKK~1f-&Qf`3;wzZl^aHj>(IMm%_vPt=@n$ zpmjQ&PPD!oTnBTQ~QRtmzN7FJObl(77= z(Wt&!j+P?Sba?}Gp4ISeV}su$F>bx-Hrb#B{MlfSYYXYgQXo@8an#1<$k#$=2ndoH zUmOf1=}Pe*tQ1;8mIr;Tk?rdDvHxCOz*NEtf-J6inj0UOehTT~HEJ7l1#5)rYXdm^ zLtlio3RQK$_6EZVrU9^tWdI$H0P>-hrR2-dP^{F51?QQOF zl`s^Iu@yWnGr-EBk|H6qXxUy2d zgm9bS%X-uukB8%Rv})jcsD(D7ahF{Yl5L?&r}3~)p@H&NG-zFR!O1>;1a!T{N=^2) zw!}q+4;#@tV-MdA$FD(o(!0~?dCV?iT9yA=S&g25x3eF;jxQ>X79isB`}Y2~!X)Gm zsRknzEfNXJK=_2LGpvInJCjRC`S571R$7Qkg~OvqwbEDe@M*2|2_7&u`@2WcV2T+y zXmbHG%Cy!r(8Jx${jcTE^UbffquqLQb8G9__R*0%?(XuZez3c{c`P66$KM~y!_LN(_{Bpb3yaJ`48pVSk5h1-4p|%)-sltp5vfcj0%R3%i)cM6 zH5OZqrBYTL#L%n(w?h5l~bfuskiu|iUr#6i+WwQntKT9cS*IR4Wv_`BN{?*2Jh}(ciU5} zIb3D|?6O-s;b6LgY-N#L@TZ>&Oc#ux0ZbBheMSIGloVr7OVuAR4CzW6sI~eQHR4~4n%1iN{3Czf z@lW-K7c7JS*pB<=U8*eKo;9u_N2R(E{a8BT{I743%TxqW%3?GHvV~)*#p{Lo!Tyt- zuOVe`@9w7gFv&xvOL4uJ65Ye$zTlELHX^UxbmL&S)87U|VV)6}W}zt#U@8l!7y!uc z9{8FIi^z309kfviwj+aRaVdHW{3~y6EUYaR-jPxyOFV6Z)x|E4OSY1$LC&*Qug@K+ zLCfS^3v!}xGXpmV9&=@2S}wvWaQ$cxJKfqUQSWLqupXW34tGBL8W|Er=}eJ`b#*&n z>W~xzh}HxTaXui|SZPDIlLIU0xQBO-76!%UwK71KhdjTfLGEa_wTrTK#H!#h6xM%3 zS`u2j25mKpAeTllN|u9Ly2G6)RT)@cC@o%gx$RR)h!O?mDnq}(Z!EYDprTdT2jt5S zg+&Z0+Dg%VFl?^X8VkES``h~mspLmtvQ|*MZg9f5a_9$kWQ}y{Bc#fb;fv^+kt!K| z60J2(kTb9NEiD%w5c&PPA32Xiv<~tXq)I3^n(;-q-;ZnPm2}t1q4$=YtJ8QadNff9 zWTb3<$R=6-OtQSH2=NO9aNQoDUn$UQq1A^Jg0oM1ENS zIMg#p5lJvRK3U?0bfuJ*+VxVf`2xR;AZO*c5lsuRsg%A z;Q+$Ejv7{CY$8F>@dW$Lp%6Q!*&C=K`-J}*(&PiO@wX<6nOH8Rxi;q{SFo}}PIyQ9 zeDDBsLy({)xVR*Q6@B?-16$4QgC|(SJ}BA#gi5ycf{ouh&m=-ALv&O!@-|0=L!=}D z5hQd1iM;Su_kBiSAE@PjNhP~}yNLHe!uufMVdH-<39q=Y_UnjuzgW7<7w(c&5!A2? z!y@e@I}z+sNsmIQu6V67U08%7oo>cMNRJ?~VJ)5`ht9BQ)gE#~!T&_ufEWW^qCLB9 z+svL3a%iHwOKX`PZ{h@uiZA?UU?Kqhn5V2 zlUfyP9(1ud`N1CQA`L)FQl3Md936HU@}M035y$xyL@E)K$wR?Z1;E&c-MT}9ZSd#q zgFo!nsnqe>mEUW(Zfp`$O6KD}Hay(C+EkRiP^`y+vHJpj6qN(m2U#JTpA(jAnSI7T z&j-`WaO}?0f(gCiiuDHVKI}Gl<~F#|LkoA#h#lE&@>k7~KsjI?bG{W(4t1nPQr-ALgbRDos!Z_c3*7|oVdKNu}InsdVr}6Y0W)C#B z5j}UUr0qFuP5aR{K4HDR8V_-9hAs#M#Q;=fJPU?B2uyX_A~n$We4^zw5-A zPu=&a!=cum0?31i5^IOmh?r)Sny+wHFla2{*oJ2ljYo~O#-pIh5KOr-K#TMvj)l^* zNK|~@ghGWGH^t;=gpGcy+|0gaPejeoECn}xG#VWq9PPYNhUbn%^CbZuivkx9qpjhf zG>Il^SHzPX&UYM~wjud|n4*Q3tFKmYCaV*Ua!gFQ4Xl8t&He7B()l811vFtiCKEn^ zVvd&iNmv1GGQbsa;(RGKZgPn2XmJRe7LYMmF(xr)#c%+k@n&wR!H25lk)n3OoXrD#UA{)%03O9_8471S<*M!vqOuxRqG@8e zpcRCtmcB6{jsBnsn=vV+>lqG?WzEHm!7QTn=HzM^oew7%zgX=I*OsD#L9}=D{SlVu zA(;A!)+*JZoh6xFOiWTJ(dvToXerwI*Vl)K(U&k&UHue$3NA)q;g^_Buj37aRx*=U z$^}KTu$*CZ(jGSbmN(j(f>LJ>C>FW*SHnz-J+cP-oEI9|Ut$2f_eibVDL=fCEy?kdDhCWH7!= z6HC|#Q5h*Ul}G8r?67^3qd9_MsnMiJhal-n6~%CNrgiWQ7y&+9frQ1FF%}KRz>!H# z(aDK|xh|DNQi{QRb!nghL@WAFcRVbg-k8k|Z9gI=OwYT`#CLv1&$c9rLiPvw(JLC&*k3vWX`PucA7A)ScO`(lC14cEFC%jGgixPRJezb=!(a^<6~ z&gD=wA5kBtU4054Kf;7kY{H{OHFUcIBXjl+BAe1!Ut|VCuj#5dMj!Bu7DY-}kTr0JIk3HY@&%!4z|H zjuE6U2#s?o0UL5ko(n<|(DcDFD8x)!+m|%dqj?@Cz`Ht>XWe%ZuhBL|Dg~zrPA++B zxv*T|4;unuQA`*?)W;a2r-$X|FXWJzf@vUNLjdjpuN+47?i~7V@OCp-#cYo!9WYn` zL3`DPN2IPUoEsKH%br~OtuTYE3(A>jc1nUP8u|lNyycKJnXRcjCoutk0V6ys00Vp) zj(WZX-1OOYBFWiGletIzA-EQP**n#&;5-@=cm(mCn?;DpdTiak6kAd5x}(olf0V&1 z$tE1`CaKr8^y?%4QHYH#FUjFHm+^;WrobhD#=ZY^<8_cLY=mSe>99`FY8y`lK@8 zc3`!t9-q}?fr(U8j;Da7+-Fj1Cwzmj@E9%BT0AP9UjIBt@PdiX zpQ9lttcM}m+y|cJhq}e&fE#DT5aE~cvzwTLMbWyAnWZMVM&^zE`5AdlQGrf$xxiR zKFU1O;W>*wiW>tRp>TG%1>_FOeUL1l$%^swR-a^e*({N05>R(6K2UJghr|Ag5+w$m z!f4?EbtC*IB$oq~4a^-Zhg~N>ilCn}d&yX7`E&!*+M|zr|?% zTy$c8hAD#$A@+m9_pmXz#2y>k8{I@un0`RtL#Uey4=4dSd7o7Yy*pvwi}TzGWM%!d z=z$(F+|lGR^8rFl>!N}ZfiViyBl)}(b#?OcpS z-aUSjJic3bSAX&19=V?U?QirU0Tul1%a2#1FTD|d^f`2p;_GK;WyIM929-X${M9ow z9u4Cx&FNSdkG_5O*9yWq>_Rhiy##d@J!?b|8=m7}OY|0c$i)y45K5;42YLzUzGzc4 z1Vvyk;A+64=N>6^Y3}kMwH-8F*xHZuO#;+(#05yW4++sU`b|uWv)*-0wlMu6+>H6L z4I`*QlWJHv7VurfE!aMs4p09r=WCV1?#|0o-9CYU?7no>tcj5dLZ(s@|7$Q_* zP;pwRXD_v4qwvrYqc5ST>J2LwUm@u%db;`Tb`!@(O*)PqHJ_rYB;!q7o!pGDvteeK zA@t7DWsZ(Fk7tXJC^IFFj<@Q~r`wxbh_#TaVbTF%Namp0NeAs#2$W_;qo(aV-U8`J zjj8M&hP5%kM|Ir*JsIg6O--8BaXTeMFb>?NDAYEuqpp$l+F*sKCnkSFUbZa zIumE`sz31r{(S&o=i# zg@vu%-Q$A;kj4@5w)K4PumHre6a1k-^CavI6HrWwfV?-K?;baI_UpUPx3-T8T;evL zZ|xj3pB)^4$d6r6C1e3zp&XZdq}vlB;y8Yz!UC2@6<3iCX3*{prxI%ctmr@mZgyiXc^8kJ}mNWm@JwM;pNPbo!0gd zouL5VRkb0j@ew#h{17(In5|}V9M_~dDd^JT=@})wR9c!d*W#6H{I3v0;2TV8_?>j| zcTE0SD*zj(!x#zIUM5js*Axg5-KqyEQJ@Rzh4tt`E{faHnn$=Glg0@!gptF{DdG=} zz-@VGB!L?s4e`{f$m0Sm)B+BIa#sjSMAft5kkSI&qq*oN{N1HFwl#vUGVIv^nO1hF4GKz_ z)If{XowO@x7dq2|k37P4p?#MU+2GvV+88aRTEK2-Ui5cM=fN@EvYjfxzv`py4gZIlfgcf!WEdAl#bpZwjR2vUr7u2 z5-ip4P_bX6!%{#2KBX4z@H4gwXcX6446ZEc;a3c02`iXe#=}pRT1qeUwUTUJ{6}5) zSuSjA70Fdb+|n(Ci96_m$pkxrsykxEf1gGs3oM6#iS zqKA}7#G!XpK@`S7MUt7%NY*V0hU|^7FftwfSJOZ=?WRsX_01NwI%f>ClRFzPv^Z^a zoEe{s?Ez1eP7}$KIz4C^zzQSC^g}T4u;~u#N&B=LWwD?Z z47e=xxn-MBysWbtTlVtIqfc}X_Dd6*1fvE(x@aJ3%dQ0JDR>E`e6 z5>k*m_?SHUC--2#`jhT!vY=a6T}}P2b!UD;CIem@7>%HHsSM#u@SHsQC->mcn6xnm zi)AH$MIS4#YX^funxi5qjxfk)L2A<4+2wu>!CF3r_0zFWg=on->0iU0!x&91|8MLi@3Q(`-=XV=tA_O-2nW^;p^oZkkWe zHkH#$O;$UrDpra0#+%@T=P3aM z5Cx^oQd})pn=nkF?V&A=h(!j+3pC$X2Sur$Kq6WwNo5{gqWxxwO*0#v$%~_anU~~) zfASQfnQdqTj<1rARxN6it0LIw*uD7H zBts@*L=G8S5qc9rq+qbO4}^SALUz(#Ksl6f%espY!U!Z@|DOG>@1EUx5UB#;OYodL zrpmiy`}O1?!gAOqrBGib_RGo;gFHcswR|Q82@PY`9#ke%`Ze_yzTmkLKuSLOCpRI& z7S7I!bC~^5h)90*RWX4RN=D_xktBlaLar^BskmTf<-~kz;w_X|#mSH$!v_J1T?NuF zJdzX5iWsIUibc~hR^(=$Yd+bYF2>0^lmIgo2<*oLh;aZhd9L|Kd%B48AjTKi1UOzy zwVQS)c(4TDHK89-&}qbOYY9r&`0!iu=%3u6B}H?jFw<0PovO7Co|8xaeRLyRAiCpXJRrW%e!n z6g(%7N#nKfY|B-zA8>wo zy>;)dMRVTMpHpwX1HR~-_B&N!(zv-P*(?bvS&0-&XGy(TNPeWH7?U;Rnr#mXu|^u?Mp`x1Oe9{rPh za2>Gnvn?N-jie>XuQn-Pwt;s~`D_$OH)o?@9|q4a^Vg?l1yslvY?ciN;68kD{VF#QW`c@lfv0-nfLT->J2ZA5M1yv zdGt^2!Of4P1yuUZPLp6SmVFegG0{EPul}U5X=N3S`eH4aeF;7!kN(L$xDHtPyq1eK zNw{0Iqs_TV)`6s)$81nClPUe0?X?=TWO|>#_xr^FKF=z3SCUFZTEm7pOrOm%K=)9zvOf!u}$xNp7Yd!|8K1V-cyE5I=oOy{zYh*CU%(Gc%QnCqI z3|gJ@Y0#gWm&Hz#tArcG%%^M%Q=e0q3ct*BEciI5(EK8~1?FYX$()~cCSy8V87KMw5f4h_W}sN#0xdDR{?x z(58)@Q}eCzZfmjf=%bF7_<3D zUmr8%P?XrbX+4=opXeU!H`4|!Wvx&PI;(u<#WfHgl1KmKTdL)9+Ujkuv?X(1Qy;^Z zWIUu~^2tBB2m8(RG^x*e>l0ib<|bq^q+jvYaFikt!q35T^5~yD&XSsE@uue4(x>dB zPjnCVt3T=fYgx7OHmcJkYt8IS@F98hPwv6>A%vepsc+aOGtHFd%|0i|{z<#wEINaQ z0Z9@AiEGmAvnwC>{1YF(^%zN+&8`z27(qQuQtFp;rR40zTzYP?Dv$!d(qXLC{$8yL z3}#?e;A_!a?xNh_&J5{jRs{)8oK=CP%r`2K^EpzuE1Po?%RJP2CF3A(e&}3LGqB4! z8FvtV4FeCW{m(KKp!#_R9y4Q+n0J(~72EkL$?|oej=T;vZ`WlzG14>Kd9N}j-N*37 z^HKeneDY83A)y9ZktT-T#@HNi7Z=NWbE(VXR#tgr9@w1;Wq4bMok)+(Q;|NyWM-22Jyw@_A-bvI%%^czkKGbe7ax_!2xP zj|no9Cd{snh$TA5f@(T|f_Qj7KyW9R(u)s;8c>;~FK;($oQRh$kM>LE)(B&K9&U~= z#Veq4KQk*`LTCi+_+xkQ2G(M8mkhsF)ZVYMOWC|B0$nBdSt`7xwIL+n z`GP9*Z|A^j4qJ{5lW;@bd9k;>4wnVFIT*eXV+qG6A;DZobzFSDYSwsMjeKz9@8Dhw zzsPmD!N4G><%pQ|u0VXCZ3BN*fbpXZ#|s*8XVw?B>Z{xbtK#H7+Yo2g$7*Sq-3>`H zsU4|r0~aL6Mc_&E4qs;NG3-O06vj`2X{AvKrmJxZT$qAVyzHqLKWwcuL?GN-Y!0JczQ1#Y4O-mGZC^2OWkg|dXY!ZxLRn%i zJ7TzLm)W-IPKrs4Kp@@^haLn_aU)JBT_q#ir8BgEokYX?3D{GwPOz~D5BM%wy>t#5 zgnx_n6VcRJ%X} z3Zn!2P3G`=4FG~9j4=uI$W!gI@I>x9k)H2-eGPzo0RED(mq z`UYG_PBI@xP=#vG`B;HpIrXa3Y7tF`} zo?zkDuS`N*rI6M5(ecn2kvi>lT8J^Lz5)xu#1$9GnpBf=x2-LNQ!2}Vx zOgSr?sJs}3ajOHX1o1H50%E=(KmtSbO4vofLA=NCyWEKbcSN|hVK6x;e*F!ihhB#m z7CfXelf>qj=`i+?=&pq$!OUS?5f@aVAfc6n8HQ+vyM88PFbZWv=|BtwtT?K@B*M8* zMIrJP#NqH3-|+PWoY7UMc7i`ikay30uR3y{6EgJ~^u2b{kE3#@7gZ!;qLy`^+8r)( z0#2@ePqIpo>N(t)*ON;;2R{elCqx@}AlnB{Ml0@G*If)M*HjCc6*kfC8<^7&AOJK2 zJh5_I;z5H(IikXBV?eD`BkyjH%pV3FC1u9AAgQhQwj&}W<^{Q^+=Iaoy{u4z{GauB zQLCFaWrjUf7t+K{4E@n07u2HL;eH1Mq;bwzTf)xB9}(P*O_w+zdhrDU!I8?DReUgm z2(FwYsDdskfT9;#<3aF{d!Kc1Q#HK{s;_WcL{%Q-UhCU#wPuF*d*!t><|pADA`I~I zYFuEU&Egf-NyF}U^R?Z3O#pY@Xf1W!`o{8*q`y*fvW(P4XQ zIEBkjI z)$90AVu_&C66Pi^yE?->LVyDRD0rv{d3V%B(1b3c9LRp8)77;bJ5+5TaW3J#L?%7M zRad??v}a2rUTIh?qRV`-C2EA1H8`ahm*F*nrJ+#WFeQ=+gNK$8lEKJ>8g~B={)%8O zY&OP8oLCr1LM{=~JX)xxULjV@6>=@HR+W9Z^rmj8N+1*B(y8p`JfZH>0GYn&6V8?}zFVQl(I(A;M^&lCPm!UDQ zVu7h%Gvrl`lN5Z-s_w;%B~u;{Kw^n2rSZqwZ`Qgv(clGs5`)IK+IT8L2)RP;>ME0H zrOo{O($6wVpX33J6CmPMp|GRzN7CU;5bs3j%XxtvKHJ7#(^UdQz|NYXM8@q4oH8Sz z$hZqdzV4oRse?3=_|k&Vj3DOYORirQip2I$g1|C&J+7v0UsY};IaOE*t3!*UUyps* zlNIze47GxrWVl)M@bOH7b!`TBnr)~AAt9igPf)y+G$u;)JuW?E7zN`S1w2|cieFQV z1Q*fdK`dbx%XOB7qa{i!66r!<4X{y3zF>8Fda$>R%Zdt5Fsc>-9HTuMGvF|{*CBfm zhQ++RgJXi|YN*DzRH~tFi{c5vLM8;H25JEG@QS54dTE0}bm`bS)0R|04IT;Jj!SoB z&pTxdPi*acc@|RuiMFklz%aA9{IXWU>i3$spg01tcgn*7Z)^hs`rR_b7KGl%&J6my z=%vz76)|26MoNWeaBzcA?@Vv0nL7)EGqEbzu&EO#oEtf&*$S@=w!+-&c4l(KhmO?An9dKj4 zuSVzb%b;YH-?g~cy(T@wtqUCPZaLvxGj&@49ED+CAgLBm__?hG_-yD0!DERN?cA znAnMRQ^nAROE}apjvAW5t#~P$cfTC@#Sa`=l*IN0(vfjaC_5crk_{Bsc5gdvcGpMG zpM(o3fam#P()0!{Y3))kI!5C!>C4wP)Qm)&XY@$;SC zE$MC|G;mV;y(@rfo|orS>;X*v(moKfv(c&|wvjR0918%*BbQOSYGXHuMT(a3#Vl%QzPEtbm`mBGHi zRg1^L+2ohC&1YY~f;vf~hIu$Ikxc!fPCo;636&z%irsNp?zxLJUAK7SDHmGq2OLLg zW04n88Ou5LDJn=UGKbtr)5D%mHfbW1Ea`TD(V}96k@M8W!=y4a&mtImX4k%O?QC&Lyiaik-NY&;VzL2IqExEL{N^1gJ)8Q3B$fJVJ`0)$U?lQ3H(g5Tjzy-Fzsza}<8`gEX>>z2{t z1*SURq$&hsk6+e~5d<7$#(!>(wmKbL20WzB#W7MDPgF!31lo!~z$_f8cIFJKCY-P$ zbFPMhJf>dP3ivm`1~@E*24)b|g=Pve@CHB54U0-E-+6N?Wj%gEL`P^pqVn#SpeODR zzoOb2cg*X_c_K+dTIW6J;XmLIL@ps5gL4fJh>fxsxGYt#)<5~AdLUXw>I~{UV#k6& zeI-dhY|YM>4w2TPOwGQ1F2XolN69mK!S}>U;`0KSyWYoMzaoodh zfO|lk*7g|U^Ab`%qk^6|s_d4i5I}ZnYYI>p;!zX{$;fjx@C!G|K80uzcSMS{ptEif z$A+Jbbc#z0{vr1m+@iYl%XFx}++l!xcdf9+++T60fA|7jhSyW6MvBTtvQg?9@D)U% z%6cn|6ZJkd#C9i+*y|mFiBHY1Sk*P1+d;p{k}eNj1*4X61)QMJzT} z^it4=(I$>Ha2!sAbg{<`rYI02x{Th~z!GtJO-om1nUhQER;n+5fWgSC<&|osvU0u= zuT-seFPde0i$OtMMO>JYSKoY8=q2D`8HXtLBwI^WEjua0@kwMkWaFVqm{rWAaH`^t ziu`C2CeqVLf@+?)JjI%M#miDTW5LHy<-*`~!kB^W6RfdDB*F0ru83cvh8>rv@PJEN zz!e-rBxgh%85tYX_xX2%wzND9xMHr$K~{83(PIWaXE83j4bM=VrM$bfn3TpH7R_ipuhzkEd=yvI2^-M%$kp(2XMHRa1c`C#4}bs`VF&e=q*kZ<%*TPfffrSKP} z@E4`<7p3s`^XLigjgF3nXA`i$ZuDe`yORa&D+o#7t`y{uFln)#iE$XtST445((SpR z3g^705;y6_!-trg_Ah#f`<5O? zhv3tkWfgmOpUZp~`$cka$W%Y?GAFz2=~4>1m(0yiKPe}h4qgw2SA&y+WgCZO#`h}| zhh^gXm3b4Ed2>gZf~dc7lu@--j->QV>K$O@9!`Ux`xYWLm70b?eh&sG9MdDJAO)yj z=jY^~hs95`aD2uYfW8|7vkV1<{1bT7c$`#Mew_z4A0B4no9=a$*Mr^QAOxCs4{zpE z8frc~BA=F-0&2E>?o%3+Ij^hJ(N`v|-4;Zq}zypssQVvi6E0UX|<+f=2$-g(6@(OZ7%#l@>7yYR9 zxfBavfD!4sNefCXAuFanVjpGVN|7MAeG{NX02_1*Gr$V(U`qBG#cJ^Rk3UQJJ4`$S z)&=uOWnT3mRxZ|$iwiZyvoFo#m?KR@zv*^IP%BWw=cS~?(A1>E zLi2-nuDA5&_+pG%}HC6v`gF-*?bLj zH*sIe#BQb$lEOX=jUr90MURxCEFG1ARysrc;n@zzo)Q*Pky+9Ly9)aK(#k^I`v&xG z%Z*HijR^6D+YHUq9(wIx7|}w4+uLZe_Ut3uAc^il9l_9(Oaqo1C39_(Z6NvwA2Bn& zm+rdlcrmV)swLhT&wr&-^}J{|Mqox^Bb>&QVO0{>WHX)~zExae4s>P`qmtpcRMf3o z6g_ecpUJ(J2VyM%A(ba)vILzb1n}3%c#7z~m^p(2ugge(S3<$&@oStAi%A{KLa{w3 z1rN9p=QwETC3%CpkBqOKx#;Kc#m6I7g7Y!_ z=iellJu69*yL&a5urIA(k?U_uq4eT>`dY%KGTg6+dU%R#X zwfj`Rc1!hZtR9?Q?2g6yb37e!J4Ia}wnnASN+h?S;y@1Pz~}=lhQ$gB7vo^@;+BVj zvjIap&E1pU^{eib%t1TK z`5+rhv$N&KNL3MXCxjlui6JD~>UW3aN^g~9!O6Kd3#=249v{5O2rnX|I0=T=swJBK z95Ke{h73noGBsEaAH)L=3p>|$>KQp?I0U~Mx*#mf2h$fg#E8$?X9c$^bL;+#!93b{=T=tF(AdGb-Dv{Z5R36w z5U_;O4k@BDPnZz-Iy+$8Qo*~okatE=IFy24tDY!6Sp=LIkuAD4nWOx(K~Dx9`;)v; z@g*9OA0V2lfI_e!QgQ(h`6IFmUL@gM7824A2q^7DEu)xCYk;1RwX%$dYNN3x4QwG_l%YSZFjkHrGD#$}&ydnSN- zlc^qT+80HC>ThN&tZi&$mPaPzAD?8JILMd8xHzZmguv%gd9j*N}TKmjaT9t7; zMsWS2e+Ey_jj~V*aG^>WU!;aZ2$dIg5Y;Ftjt-8{5ix2|eKf9NJ%4iE--k! ziW(F`i|{rq#VUnckWsl{HHV0-fCvo(o)Lt0Bnj&@t&r%qtwCP>|4_?13#BHN-PrjY z+Wnb)EhefUl9%eq?}B3&Zw8<&_LPmhy|B=^f_*FirSHu>1w-0XUx)KztbO zS^xlva7eBPQK3)ALW=W!@k_%wj>??!8Jq;_Eh@aIiQ>KhLwzRB22?@yCN$j_5EyzX zLHXSoRY7qTd#Ylf%ymQfAzJy@=c&$_?sZju<*S=TpvMb?~?~D-hqS(B~WP zgujZ5I0V1yPf@i545nHrz{$}o*)J%Ie#_oJ8Fl(z3w?~yU;jR~RRQ!mOtu<~ye*+eSWi#0oOE{s| zcJH-Zkq-U@*=&kKUC^lZ8SA^MThfYb?!5qvwCpP5ek{&7EyK^oT$Kqh$I}>;=cGmK z%#*w`F3CYg0!1^ina%?$9SCw0tk0bW>$3X&s5N(mfUP->n!wjqoOXELP@7A=y21e) zaL~iKI5{FFpQc*dOKv29JiXf)=N@^C<~@MKE*$9KKcb6z0BFM9ph^Hxep^8^e_8(| zstEdMwDrq+bO(@o_F>8PV}38}7?s5`Q^JvjPg9II93Opf|B=0*#RHT|=a^ME-^HPt zO*}uG>-QVadjcW`<~C2ZW|t5vgre7B9)Y1YQp;<_UHR{*3~nf6Dlx4#H(T(UU)k;X zrLsKIG^#!8$*3B`g#^VjG{XXEu*)x1{HOGlsbrv5Dp#kPSeNF}o3YGa2u(T7+vtwA(m&0-v1!32yVw#>8>)~{8z$2Hwje1QJl554a$`=}0XL?OzkDA+FnBj+u za>QMa*_P4`4Iw4z(Ebe!m=FxCMq24p?bfh3q^s$~?rQNNx5Ze|60}EXU5A(nJ`Y8uVNWfjl7uY z!}8U9!Xe7=ycDO*u!ezdy4zX7j(|xTuWEvrlE{OF7BTa9_}Ce@uIQMHBgZo}-|=R= zV`w#C$3m6IF-?VpgSX(2hP8Lx8&0`|+tDeePD`Byy5kb$W!0Cxpj zH+UFM5$-~aGr=453~M@=iYsSm5Cp;?@93R3#l;u%>gehA?yf9TZhC2kiexBqCwwSP zH)|y}S;EEuYk_GHk0Ne^hR^qgg;n_$Q22TmBfVxExbqCcM92+`typQM$r}Qg@f&?ML`oqx(Mr^&f9itwC{8Sqd06vXjUZ8f% z49Uh&pNz;RAO|E>|-aUeD+MvGPvP%$C^ z2q=RMiM#N?ggYldRI&}=492{tcs1x^0;6DH@-2aB&LE#91;IWmg?Vz63uB}Q?-8sO z#KYd`$66e4(}nH&(}U)IRJ>O~hR)Iwb;9_Zl8;}ZX{@=ke{{ULyX#g9_s#5Q-oQ`~ z*Qr}8%z!1mYmh?|->5|qc{@v~N}Xm1XW758(J4r=-G)npT2=;eff;%U=Opm*fw~`9E2cb?c~p5FKnC zGeo-j0E25WY!p^4t{ob-%<8P5CFK5FKAx|A01MD~g8*xLeJJ(qBPQ7d{*W+Oh!~N? zV8E%xblM8l^w#9NC>SC7pfc#VJ>;VU=50p&Su6b-M2JQy*btet+}1cl{D4gzL$yiC z2O#6OdNiogpqLv=G)UI$3bUA)DRYEbfk6WUabwP`Geu+v0R)P5otrT(CpOitQ*h1_ z)46jTWksEMgz%DgK#r0~!D4e`J4S(`jM-pg1%kJUFfhs;!HR>}G(yx^%-?{Mi5;($ zUuRRR>=y$&(9wt|6+m(0_{NNYp92}g4kMV&R8cAmCn zz>X&5N!%dJA6*ferKIc=qQ4Rh1m_3%kMJTn1(!!TUtkJmkf>NBVb(UC8^=(e!bp;t zHs$h344AT7w=WBO0f?qO=fvCOveakP2xuuFekM`BBvOW&d@Bw?2RcoK@0v5eDX(Qk zu}Wo`7WveqO6<09UN;=W^UB$!i`JZx)C3<7)jKZI&}Me$4V<_b%qq~Gll*zs>)}CE zweogF!-{Mq#O+%ZWfW#x=-P~HXow&q6>I?k4JgO|=dGYX5>D6PRbb_V#S+VyESJac z!jG~FVr73$i56S$2wNwI1d+ZzMO+d3bvau(hHM0n1pXG@Li#O3RrQVnJ*FV-6(L1Y z2t4bJ0ju4oR4yf;xj}doesUX)l=TU$5v_8+3^y&zk8maHj!T2a;H@RSD>*;KUMWI>8Gf6-XM5sO?RaLXLMrxyjP!Yh<+&4`%i1jFt!x3DA|na216`(-WiuAL=ibtF+=cfD z{2sH}`EErZ58GA|QyInm)LoKOb+Nq!TA~+`1fSo9LMrP~oJJ*q+Eo^bZNMX|U5 zIl>t z!n-2IjgZMH9niAe9W$*$__L5)4-EjA!x>CTp&J18zKB2+DAcz=8wC3ugvg!3*$`7jw^NX;5wC|QR@e>!Juw24z<>waFHUne zsCTNLcx?gpkE2l+=cZJu@R*)6iXKdQaxaZ;q{i655=Bo978aDOf6TX$P0h_mxJuk{RPFu_Jt zXcV-8voGOZpew59)xlaVY~sHZ>I|W)=yO9#rNAxtd(XApg}HmI`iPa5YOh=HEnU`n zL%YeNW``rEpK|Ms1W|Awu`3+J*rr_SP142q;~zeTt&ix5tmMZVJ|Uf(8V3p$(9>xg z_62H_L?Zy>L>LG{hJf8jra2l$=HAU|EF|sGqPMokBEr*mut7;|0W(YX?CQoKek9O{ zVGhH`%67t(ZIW=ia(I6duUxNOml&$&5=S?}Yt9%i7Pd05#`1Qc4E3kZ`NAt9;TPg6 z>`xY6RX_f?ifA%b1e5`!m4#~6+2T3urjcm}jB`+pO|jUTt4F@8>%>e9{oG>x=nOo1 z$RN4rF=Z$D3?>C)eGL1IIY4Qg2P5u8Lhc|4vSUF&6p0g)yRIQv?(G~M;aV{->|b;B zf>V*D*NO;BFFICS)|CLRLad|+?MOw8KF}7|LMcHNjeICB7&Q15@_;h#$7jg=o$b|o2LD@*xSPfT1zg`@C#aMG0M-J7lRYcyw zvTj>77P3v0?y_4N-5I9_JcHm$O8=m41dJ#Mv|U-1>0~6RHrL`6{r;#TVngec^B)=q z>c|)so^UFQ~T3{2zKq7()4@?-eoTvGkC4S5u zJuy6?9~7@hX;^Tvz@kATsJAA{DuHE^coWCU0j-zZWX0M)i1wkGI-1Z?9bD@G(P{Z2 z;$w6og?P(?8ecnnN#p5BE_Yp`AY8yCt|^EK`&5gNj?N3S2Yn|u6mY|yYy(WYt}1PH z92Bt?;||9=w@;RN)aN+gNNG{wVe|I44j=56#6K)!e3&%Ntxx@+L z^)r6-78WfJloU%~M9c*yMn0BRbGEKtV{YNkfPe6x+Uq`ywl&nL5RCF99IAlBS`;X* zj72d(#mumChn7FJl2bqReZ;v*rN9NKGrhdLk%f+BH+aZSh_!`BcW>R4|Tbi5Sed8BPG}ZI!pK*fV089K}z)MCC&88O4>cLvbub^sYsSeH! zbvHPwkDe$pgU-6&{$RogO%_083FxSDJ=a)rKDAzvj^8~!on{T9=jJ!t zWwO6_RGGw4V_}g=OF=tkC+*$E^QJO+$~DxUNtMD=Sh=?V#CBGtad-uPQXN6ck0A5^ zpw7YK6I^Y|4Y8QMaJi4gd@!Id0@Hh!q)#+{-Z1%BP}ZO*O{#(#RX7L?PUH|0(;v26 zwrl@IE~2KV>QFypsl+M7KLvd0pa1;lM<0DuGkn+dwd6K3h*^OM zZUT>jpXeUJt+DjuAce^<*Iunh+q}35@+i;^-fp45)Ri78CNL@pYIgK^5+Ytb&P)j< zl{`x1;u94>m#u;SShlv=QJ}LecT<|hGbm@o?C|vPK1BvYcUqFs!4W=JLX5cXaH#2a zcIv{Vb6S8wWgFap-ZhEuv-5|_YWuiJ;;lIW>n^Z&Pv-z=Q9y^IR1^V#=op_xl?l2X zj8Z`*zL{jdu3J_CQ2049nVsW!5w^LRNVWDhN39zjSb%Gj0?Lbdr))=D&sYuWuGsKHzqYo)bEI3&`@UH9?PME?zB;9q#R zXJ+CmeSd(EKt^wh05?RDckToAup;`sQwJ;jKNDDWj(JDDPT0^uZ~5Sw4h@ zvhRwBzf#zIetbX`JYm>l9uN!T>5CYnU=dkMbLzD{&21Gw-QL{Ver8qc%bdzJh`LnI z`gZo89H5wc%qc{M%%FNKl5A{HCV4?A;L7czES*-p5|?I2^#;^7^ail3gtn9Bl46Sp zodC7Z(DB2pQjU;MTucOtRRU-AxL_garrUseGYbDkTnSO$Fu5GT-lRQ)O?J&m<^krc-H3 zpERxS+F_~#Z_!NsV#Xo`|4@8{V{M&(uiPYno5r;1sDkgbU`tx@fxo;T{t}=Rw~bTu z_??(a*pQI51nFr86MRTW=T0^gmI@E$+;MoC#>^7@y|SD{hEbPdH?OFxx%T`LduJ}A zwcru0ipX`;_o!4yiLnEV zf5a1O!iqd2^gEO0URE~=@5P(|{w}?EN5o;^%Ce*_M z8U`E_%Wxkf(d=Z3$Oso?8eieGW&j9c!Uxkm38Rm#Cd_#Ih{Nbkt)k661Pv0{G_;t# zYlfRsX5rqBzd1WJG=w`X>VEJ@`%KCCju%0lMP+Op7LbnPvLfOXI|}V_=BuH90o*+OG|9$={c!4* zvb!=cdv7A6Q1C7agtm73Eo{TJd(9+slb0;!ivt5*YYg+>+CqM*jp+H&HuQ}<`^Wfi z`&o1EU~AiDMmeXy%gZ$wit2E_b%r}|SjZ`z(tUZRKPRIaKzkhI!OQ4kGd*e^KYI?1 zDs1%9J#9YO+&$W^l^*)z>}&=p$nW#Y8V;mfZ6U8X$@iiB!|DF0tfBTn^=i*fN`$^@ zH1c`4A*Vut##gvBE50E&jxXS>BHMMlpUIoSLT}-UO6+ymZ%m@idefO*KI84UFdU*4 z#G-`2r5P(?31|QrROYO`m;O?Ka_jK0$t#Iz544!vV6;>$93DJ7-h95bb70>q6}nNA z8+{Ay2^`DJ_TGVmIt8a|dOsXOt8G5tJ#Oyo*LR=8@}X8N?@*IwmBD?e-Jc>dZaQ@# zU8T!aEU51~SdTuGi}2+uA3Tc6-_cN@42!rPOmey%@reTu!gYJ%?amVRNPeZIMNNjb znQ9JggzBldy1w>keO0WQr18Wdf!Tqlf=ZpL@q_WCQ8eK)RtK_?VZBZryT8 zIO|ZkgUh(zi)sgO{!kmTdOe@@KLbyKO>SdThcD?yi;hrZ?)@`^tiYj9nDuMENg&1DnrqgT;z)IZo1&3Bc(Kg&o^`}^?;--eJ|xWqKi zaH$EI+{rn7kzD=}etrL3Bu5uR(oHL3$hAKxVLm8fGD;Y?dQO_MvS2+j^$Y1GoGG9v z*{peiORO0Jfs2bj|M?8Joo(K+hRq1T?@9jsApX*aSx?_T*vH;#x;pnPQzk}M{QV&P z%Ec>AkiOfh4vdCIviQl0z@glG>n{11@q`a7;2tbM4)4WqbKLzmG;Q5Z4f@IthV#%_ zK_*PBkdxI;EEk}bl&~{1f-z*VqJ#=!;2zMeR|Cn43F$D6Yn+tGUK(FO1BN zOHiB)bQ`||^KpwjC4^MlGn!;MYf(o5cybTV5q}IOT3mu?8Y#XmV*MqK-!PmUh#Q<( za*0nD4bl@Qm!#7`gNDXWMquHgTm}-LRw{=oNquyEv@eFwVc1NKZp5~rVbs445Vw!$ zedzr0;3=qKcbF;WmB^B)m}fX?b)ijOaHvtou{*8?tV-qvQ6K?9MxGk!Ron>)Yg2jth6v zrl-y4J;HhJ>rA=IJ|sN=Bl@(P?bK)b?JX92T?be%6EiLe;-EU8xrcN zTw+?tajA*qeW$47i{uJC;n(-C(FHyeCX`g=S&{mXCbF-$!6U=^p!fY?e0Qhuom-?6 zy)V`^QSb(F3T^qj)1z+y(?+p~p}iCWZ6`Y{aS_LkuK{zFE|*9UUfVl21cB(KJHl7y&Lk?>elt3;=K zX0Wqkghqw3OT!8=^jcy?AolevQbz1Y2GL!ihxfR94r68oX2EvVC$rlhK|g>jEyUD= zCeH#~I&KMvPO+23H4qH?B~77@aWd`ER2fZyg(xbA=JuXZ`2!Y>f#Fr2gvt=|UNsl! zz-CRJGi-hyj6CyZ3T1bf*K14Sh`S_^k4`q3Ez4R_NwC6R$(0(P^8(}7&^JjCFh)&7 z+a-*YAcYp~7Nz47fqB*47=20Tmq8I}7|-lLA7WXJx?_ou2g`W$?wN*6#HUMB0V711 z#Q#Oe;qH%9#!*vfpidR^abECR`#iqXUb~o5LUO=1*Esp2p``rPjrJY08;r&C9xU;d z>-G@w`S~=#knp!7e@C5D`Mo~+eor1w_5JkpTwX6*Bl(4}Bfmrad-`v8-2f`WBiiHI zDrN%q;v1@0j3%MgHDU<6VL2uIUq+e#Z>UL<3GH=0H?_RKXqK8j+XM zB8ZJ60-d0;I&YNDiFq;@mN>DG5OGi9l43%_IbkZ7=8w?!%LTfmgWuM@AKB5A?9`H5`#BWTHQn_Q&2pkt4juQv`^e6HTcfj`h z%&Niz5x1l0W$W~ntffnZ2f?`+$JQ+(As0FYaDyww3Y1A>OprJa&^2T?jXDTA^BAPEr)o{eKWDN0WIL3s6&ant-~Q%qlKk7>9~{8jEhMsBxW$s!Aff+?kQ4ySvK5@!Gc3BGI6)v*xVXog!rZh7 zeF&uuncyxk+3@Q$ILlkkJm^kpC0wI!<4P|$2t2aN{E<~NX!ftDhe;n~W>85hqrgub zh&1k&$wwtOc=Ku3aQ-0koxaAh#_5`LCzCSH#ArmGm_0{?WDeSaPC2^7t{B{(``Tc( z=!HFvlX963;}Es}J1yt$(v}R{o4G%i(gGG~XIL_i=Q}#}Yb_*-*?v-Sl3OaTi^5}5s&MYc{v?~mUzNRLMWzLsEO@8b z*hMF9T2W)7mvZ|gyn-4};GGJ)HQbG~c-8IqArnATF@D3-9O`kPr^H1tzKno@gz*I9 zCGi!g1CpQ_^_%mn-e5&;5^|Ly<{K{=Lx?rr9}2kz+7hUR7JHR$g{l-@&dN=y%P-KE zBvL9?Uv3)Zk~qQ#5L_`121`n@MU}hJu&96W50z!RUr?5kKi>Y&T`Dgdv$Vi|uf3B6 zS9aSw=w_1bUb0Itua5h!gcKBcQAX~3#1>1h6fkj8G_ah0?`P%vb?d%srQ7ViUr!dn6ugA1rYm*3tb!_EoQtdOI@EohI_=tmexKW{IXroIO0#a!X#X6h z92T3yl}%tXbpi`qPeOHqmy%`o<5z)OoxIZ#oQXdGO`U>}1?Vvf7}Fo=ge5bo5FOn? z5l}-Lm5d71rqrKcA#*ML4HTdA_#&4re2VyXwJbObYkRc$DkCe zG!{)YW_r3?So&|N%nA5@dUXgHLw0%iwN{1qQRmNJ4TLfK0ZeGlxDrih=E=uycVr8I zlE7_CM3O@U?}Nwxf*#&21^SUofj-q1^!wcE{Zf$GP-ui+DsmXl-tT|MLCZXw{<$#j zwMamNW@ao+1V;OxUo0N>&UmR&)NBIZ^=4BP6`1F+z(E}3OWak8GyUG#EywnmMTPWa z)bPKup!ij?J6;2R(816eNUqo}zllmeM9Xk`2{Q+`(Ln)?q8VH%JZE`9VWon6W}lQ| zrQVq7=U5prQvQQL`=@&j7m~GkB}(xoqdLjqlYGXtX4Jfz{Rnb=P!!T&3;)l@W`L}O z@;~6raOUM}%$bm_ib~XWfhjuw@6LZ7WUH~bc5d2H*ABY`!(!kPh_@cn*mKUw3<9?6RhI-gzabEW+u>@tZe)k zx88L9N6mEqRU1wz;D?MqhnsZor#Va)x!0P^)4*oC-8}zqmt)smTr`$2Kb2v^6fS}! zr7+ED@tJPUi)@h|5=4ev1h138Q~x`A#AIgt&+HEa7Vu#?2RZYI4Vp_3{U69A`&U2r z`>>oJtiu!H{x<93S!tFDVxjpJ%sC!7uByTOs34gHA~jjlpH=ntfvx%-##%6>Sd>5P zk|=tB{izoW2?a0j%hTlpTmAXoLBBfA{4Qzz*I=UL)hR)iBqc(BDjAvr$8IUaKKQ_F z|7apnc*gNThW%i>_CX~jVc!1OGOTzp|5y5_&<5ZaDX{))0D0PwIg7~s51hPC=Qagc zDwF8GaHb%dFR|ed^jb8+guT9BN^LFk&D3|SuMPmego+$ho%!-ETX6x}HUh^M$A83i zr+Np0T~?3^Wt)7m*jJ|Kyf4IqM|t2N76Z4ppw}OU@qC&(w&6%j{$b8!7ewqF9YpoN ze-Yq&_9X4D!aqx0*Z%t#??GV~3=#lJ=s%~l)X+A6yj|f#cL&Co@uUMcj>^SXg;ZK^ zm`S>ctCO2i7oNANoJi(T6I0<`yT>b_V8h7M(X(N{KZJc7-2R~4)$2~<$*>Qn5AmgZ zRzHe9tNg75d-QR;N^zkQo5L@zB%8wA=5$JX4|p8%imZ1Vg(o|^+wi7aTpqV$*u@Q& zqQxNRGMzQ092*qj6(yH83ViFeaa`CMN6WaCWP}gq(W7b0BbqkgA8YDuzysJj|Bhbv zUeW(I1%vkw3ox|g9BnWtS|1JMSGM?H+&|ihPH&u-6rCR=Y#*veOud2n;efAAhBDw{t`<*lBg_g$WI{KI zsMNTA`m_XZqig9~3n4GZJeNRk1``;71Csh5Ao2?Ce*v&JJglW-^LUKeKV@i$$#ekc zr2Y*N7fSF(Vn z*?D*{sV@?4s3I6N1J;z0^q;pF0bqS9m&u?ybZK?9^p_ec0;1${Du}Z4&$>=dAy+YzSOoxwOX_q{Uch7)}!(o=#*5j^LP(737@M+ z$Ic5uL+-HaV8UQ@+{MLQ^o_Y}!GsxsCgIhD``^am5rC1AcpkXcZE&u4?2wqV11=4H zh*Nr8fE7JCI9R-1;)qGxulw!KecNC1V{3^`C!)i~v!AkX;ubQ@L%6vQr;Lws4Qh82 zdo99+%a|_9XP9?L=<7JZ8vO7MGXqW+yVq zb*67f?=VN(8wH#5c)`2|@F1FiO;a!pP!Kb$M5{{-y~*d7tFIz@RYu|Gwd6BLb#62Q zAxF}LL~4XnWBJE^YjECw)2~74h?OWv&`XLqFB*jhO-aBBk3mR>5B3#eDe*yb zh*&pHJ?PB&K4=dAIB|u3JI!HwGebF}%m?se{ST4crc${J@^9mwX%w+DS|2E*W406~ptqH{g!2 zgB@E3TQb?EN>r6du9#k&##3Cbc@q`SS+EEPH#FkvqSvNZn|L8$=Q2W9p;+kQzd`p( zOS-Kj2L6Oa;r`~;S|@JkX+a9lHlp+LEPC`+RPA)%R0mUB=lPRjlh(3ne4S9mRwQ8; z6D?af+BQh!Y)rO6$6GM&zy#N(htWQQV{qIbA8jdWl-T^Z`!=)5j-aFk4}C^~kEJx%z~Mhn+1VcA+H(eMT3VsJg-VcPo2q|D!v)xR+iC2B-YN{+mDk1IO)~``D(+N z8<2BKZisZ^2j$vbmYkDSWDhLYp5Q0dUN?D*h9wgFn|oLe9&gsaIojPk zdRi+rN>X1k3w~CG0?l7&tZy^d7zdg3^5QU`)?O&EiEWVwib_xH1s0pJ=)(|fWu7$P z)y4^e66U@jU;{##W##jWK8-KtCDM9EL%zsQQCrGd+-@uEUBX za-#x6T%V_h<>xP?ZMf1K^gQr<%Xqf5l_#in`= zU51E&M{7*91->6em#>Kzaz!Gff*1K-AC9Q~lzBvzoZ-)fO-iDB0bS}&EpiIFhVi=U zmd3mg;~~Nc~i!VuVv^f}K zhqKt`HDu#+LRJV}K(TJCkqoTu^V{F&sp{_O8I3L&ym7MfZjdz7_pYw0u4|$R#9!2G zIl6Q*3|}h-2<$h#g|IoZ&bKmZ0SV=fCJ>j<VQi?oh~xEhwfL{? z;{UD}zeQB9m6iP3@y1%eV7@aYhsRGaI?zk}0V9iL;XZL{W4&8feL~}5V+d9aaM2qL zTz~Fcd+t}T9x^NgyV8E(cmw45$X{_dhF}P08tIW+acJN-;^u7r5Xokxz=ls zI$iV4I^rK7&VV@vdj<%>csURpnjpR%aG^~oWY3$-ML0Rirg=6UW6tPx+$1z&o5FeM z+HhjndeH~)tYi3!skl6iDuONW6k!a2dATImghdE>V;f?WJ(a~PrzsjL#O`7!Hr5pm zfKx#v2Qa|AXvjT@!7p(_Y%50$RCbP|)Bxgfa(@6I>apK#h}(B8oHqtqX$zbfz)jR! za@1?m76;zqj&7JubKg8L4-FU@n`6g@Z!UO!obYu+#LCIH3Z?TLxVy|ox%fW{PC7|+ z8x8ZV(mDLTWC6K@V66S1qTvRD=}No^F1>(K4||WPeuKmRo_VsbgErWMyd#4wU)&`f2gdQQAC2Bng*E=@YZEme^ukxc1xMOax8wLA$U}s;g=#_( zjLI80_9{?4B4kJ)#45s7buf-&&mmCsae{Xe42l+9=*lhM`$^?F8GJ`h%1sM55OgL`kAke z@XlAxAO5hrzaQgeqwJgvgpA zap4p7HE}wN$?LcvPIsWyrY{ddze#NdaB@}Sz$(;5Xwad|*7EyLwS%!{;XeQ5&^PWF za|U>D0W4~lmu|=dKKBwG5guUZ@h!xQ6*MVZBI`H`GTqt^*4~1C%)wkIGvpaL0sME? z$E{;$hv_;oLR=R4T(U-*XL$BE{P!CFUAA{B1O7$7i(HaCc3^m8`%di2t;v#P(?f7b z_CpyQ-WsGnu%Xbw86IYHaRA=ax1JLXv*G?w#l(E3IT2;1NzhFx{Isz&OGcYU*V& zOrMOq{&RCt-ZFk7c*+jNL@R(;|JJIhwd4Y0k+ra~VJjkD{uGRrT3p=SH6nxt|Nhe3}&}lLK>sGTmw}LS+hf`sGDlv}kET>KC!EN6{ko_0}haUQd&H z7cp2c;b)@tjy#pUpU4+~-2w@r3%>Q@UuUq5%J$Cgt7oaKN0R4a;r0GI@On=&1B+|a z;u=Lh8bN|aQ91uT&bqZ+hQcb;gMDfcx6c+aGYQAS{%Xw3ZWvlIICaj);x*)Bh6iqkl=UcQIA%@y1vHQ?BH@@bsR{JS zlk`Nf>9a_|Vu{Z*Sy{4_NXfi8gs2i>qD)IJ5qr@nA`wE<5jHV! zHq8fVPkYC4*xYf_s-i`WV=Xcl`JHD{h?%e>_M*m2D z;ZqOz!Z93fJnB}ya12LS+J$4dI`AzV!xxU>2wAak4EH8T6TPo%v7hD zPS%*SF># zKDC#r{^6*ZPcNhG#=9J4K|}5 znf&=VP-sDk>u#>|#=L&WwJyqH-+`)0w`HB;oe$8lGU)ZIS zkUCa`ms~wI$pbzGax~G%bjXo1^Fodkz9HmD8ur}{-K+>je-(r~>kw1(S^ zu5fkl7>0EXn6GjFrLod;**{CI>?1pWxL7Qsv{R|JTUA)A1V5HsET3c4wigT zKA8dmXNYeX+*lxn#)uOVCi`%q0p(=dI>&Nm{AY`UvT?VSgZ~UA;Fb z=Qo$6$YX>~Wy!ndb)(bhoHhpcgavO(qJTK_7S;h>T2FZ#DJX6=I%oKA!j$DL*!0l+u_SpmGSY48FV?v_k#}7?QVo^#Df$_SqkTTdJ9W^SQSi?B?0H%}B z#@89w)~prR&I%`wfqJ8A4NUS(oGUQ_=0&;b!gFC&6#2q;YO zt$LtXq~h!Vg4fe9uA-T^4~t^V>;p0bE5uFS7{O#VHRAxul?gn_BzQ>KjIfKuiB9Es zaqmUG5n>m6vyB<}2cip*iGFo> z4#CIMo8lmm*7QLJ2EEalMw({8HpFIT4-$q{ct4Jv=$Nra&+vtrT87$+oa|K$)}(V|$zr=i*~yOLr1tQH-Kk28jb<&LYvAz32iT zvPCPFisK|{Yn|$4d3{O0*ARSZh+oJcR<9d|;$FM#pFPlM+}vwszabj{rkXqvqEl;|{S&k5#EU|A zR@^CFoNM~}#4%tsg%PVEpA6O`Ibmys?@#FZ#^(J84M|2V)My}9d#4A{1z?o9N{IGk(gI_4jB+we@eCLKb;4OZh!BuY5Vjq; z#)C)ZE3?7$3USn}#9KCKAK)AYo9h6Sr!%Y}P0iYS+4K0E3sVHjAPof|Gn-37rGS0~ zw=erb_@ar;c!3Ach(v4_ETG}qBO_Qs5+2CGDTeoPe-N+R#tc%a?6Hu_=dX7UZcZzA zFPWi9W7g}fiLpFM^>Q-fGycu-#zeA+bJmFvgIjaQIBs7^6o=#RKW}vPQKxgIt0rwc zrf0cWFEjQTZ*Zu~V;)$^CzFLsOj zdxuA#PUTaKK!PsZhy$?8%Dstq%%aIpCI8_9GNxo4H!+(=zqh;!=|fmoIF>9nBG@1R z%|~K7AU;R=7!^NBox(A8@8x_75k=jcn-JR;NcD_<1 zp-ePlg24mDO-ZqeVl6fDQ$v_S#5)2KQfrY_8No5sc z>}@Cu+Tv1)f#{W(kR}Bz%S@hOb$Rn28%Uu}Y1no6hQ!R1OoQdbohOfV;t83s1djzy zCfq7_lV`+5BX^N_CW5Rze`4;VNWcfk*RhL|7?CW+YZac=oToBlL~0IM5z|Z5C>oSR zV1h;%mPLYh;#5OYh@3Y%WK3Q#{4_M5U`2pa;V$dsBcGwC8S)fis;uUoTOER2o{K33 z_-9U8l;6a}G*bepL?Pk6%%qK*Lnz7<)KCV+tH!c9FDW%YZ?(%o-ITcke&YgY&aHF6(sCK*#gr{VcqPa%;wspk8!q5 z>d(uu-O6G)#43&bC-H1{sfE1XlwETW^GW=gf&y{x6oyR;U58_n8lTRxN%b+F&5m_W zrcFu*T$`<(1#*8}zD*`QlX0_4Q;<*aZNFa*O=j@tO_g>%lkMVrm^760K|w$V?^-!| zhL_YcV|O4*2ntE?Ld!LUk8RjY(g3jZ<#yd)6u@xpKwO^mYj+|A@N~?_T4flvEG;}a4qFk-?xz|L0*M3>WNWS0FuP*KB0J+wLiny!&XpSP z%jt66HG56UFKBNCcO$u_^Z_HV#G$bytpAy~QiGf0ge3+FO{ z+g77Sb$~Rvcx^d6#5PH$^eA0ebM#oU9F$HU>AB7)M1a`qndefA zWt~Thdgkg3hFZlrJB*8FbqW#?FTs0ga~zW1zp-}Rwd+90lW6oJ>hH8)LrNfmy|T9) zoIviZy!To?3U@@s=-N_{jG-0>z-z+gt7yVw?GzNMLY73WY)?xZvo7nc)i{r-uM^9r zXC%?6K%F28(WBz74ON`vrXj8X@DHlUuO5kVwOwbT;6mNN7vvn$KI&5Z<>j7li6TOz z%jS_{;$+Fa{SK+6t6e4%Z`!6HE5u6`Oqt?4Jr*K*giYI9eT!|vktMC=Ndi!<#Snu> z(4FGw;uJSs;%!SePGs?8aDk5ZouD7{oflY$aGa+aM;a{?!LAl~(9Dx(PYXEZcLKU> ziMr&)1abD7$2)RfrH#oI=)aRu!x9AHcC365t2+)k_UxrMl8A3sGC$S+J7TU})smpf zL~8-p%0zK!*`J3=C*E6daTuQ52dYVZE_~JuI8w`4{gwE<1%n%BrKZ-*LZ}YwVVms!<9tu! zSCc#(6dxFMeZ}ZdgwK2AEFM8$Cm;p`RDrZoSy(~I1TB)1s6d#c6D-A~bDMo)y+S^o zmN3pjxrJ_zOXy=t?yL#g&@49NqHp_(~;segVHObo3c4xe# zY)~*Cw?WC0)@V8?M@BwJJ4R?6y_I|Lz6@`I;Af7kq~L%1u-2(ZNGrVmG%Ur)TzNH8 zaF4OUQNeZ}n^%JJ)~kbyR@d^T@j1`91Cm&!dOgAwD8GNSqY=M~U0k~A?bfNuzrSdI zEaLt%VH|AABKM3|=bH;FVsH83)?}ipCIP-r4xbhoK@-{Ikj2_`JHbwm<4OYjSdF;= zTtr_lUu53rlc#Gcesp^xX#roph$-wW8cxQ@A`@!oU%mhnhx!ih;#IeU#D5i89K54) zH^@r+5etJB65S_D2pP4!ju`p#ijfn`_jr^thGa*{p1A?&N4AoSjknOAVr;@4C(C+1 z8IK)@jFE%)L5HFkIPml@XtP8`uI?EglMvorAj2J`W;cHjnma3e%XROJ+z=F@&$_F%Q z>5dZicv*^1Qt|9QvO13?hv)014YX-OGe&A3rP>42w_TP;Qfz z@(Zxd9dh~cmBH;*u|I22xH81Uk~SuH3+om15p=9wiy%Q>0D#<01&7zRUpK=qVZd^1!)JZI^i2sCKnOreU^1F7ICay3ld^?@7$|#>jW%gfI;6H}jM!Q>y0x1Wd3;LD*V)Q%d z7UAwrxMF6mg?)a#YuG(22FvScGH!R>-dGvw0vkA+c%Sz!2#bS8t#{UKL4@F9%F$Kf zbO1p?Vlv~je4Ylf7TqCcfBiwn=rK~#2|JeIc`sXTe+@dX5Jv0-t=(A*b`YI9IJ+0y z&-ZpJJ1?FVXycFb9+coQk>6$eE^A!nf)n18-(07nXqP?J~S`dULsfXG?M4*|*{r{-m8r|LW3MGf@p`{3cwE#w!ZE5E~K}9HHzS5*OneRY6lS<4@BV+NrH%G zAbSx$M@K0OXQQY~U3o_>M5ijYX@Y>P5KDTBSKa*l^Pq9oxcudpWX;g5jitpU(ybHG z4wgshCeB{J*R5k^iE9zdC2pLX?qn|#P6oc2lr&=+(kaKXr}>c2X;*i`ss)m>#y>|b zD1oqO+(EcY!@Ea4)aliL-vwC6>pl!<2<-69NxX)Vwt2PMz5rcc6_j;P{I0PMr?3FK zf;=cEC!NBDy^25HnXhT!VjHe)9-=i`qH3I@9Wqlz)(CPxrIOFEdRK zj5FovRkwys?_b>Cl&ydfC_@yzIQ*Z(wHK}K^Pg~R1@r(&?^<=$Cdq&bwMfQ&f53=EY zqqSOW-T&s%a%ol8X$av6f@5qMK3w@ebCVTazk2fDPk(#?d$p!pAA7;Z0u9cq{is*J zngy?^lhGVB8mCd6=jyHdPHi%N*9X-z1nFpNlOR(f)d8LB)qN3b2MSK+vn|l)| z*Sx?s)SS{g6u^bOzy)v>(Bd?QpdfujC6Uyb}q0 z71~oopm__7!S=Yn`;8$z3RQJ^+N0aK2s1mlL=0ODBL%3(|7%dwGP>5N@9NG8;>*vl zXc)x@JDLwqWu>0AuU6JtKi|js$E21;3IMU!%J=n#Kw%&HU%J0br#OD#DXzGW{FizD z6UTp2!T9*A|Eg39&_HR`DJpTE*p=m)y@X`Sqyt!y8#GTOVB?w~cHSRdZmgF!*9m0u zV%wWp>>gvB~#0T5O*L#OMN`*=?!TBf9uWqha9zC!#Q0F`W znwu`R9hD462jv$$aSrBLWmEul3kGN5nXoC`W9#z1jQ6fN*xLaK07<}MKOOYm!U7oh zdygz;>(bmWT~ak(C9=3UzcL?=OI0BxA1ZKP?(55x;;VjfOn{jSN=-9pZCqS8{*z!)mU0f72kdB$^ejy?lR@ zJcaH_5mcN-@R2C<^8ThR@aO^GKYEaO{pdm5M9^{8?^zX(x zOBfv(?(es{qf0VGr6uT)>>THBt=kxqDv>hWl<-XHbn5mUE2MtqJ{?%-md=Adr#7E# z&ZF0EUfvyJ|E*uxFAe5##&SE0ZaT1F%RYY9rMMaI00;(aR3){nH>6>D|ht%c$S}e!- z^fT^&!+qk+~6@1Dy37^-!Cc(-Ja*pfXlyDP#_W&Ks zXGxK7K(;mhhoZGk579c&iE?~Xpd-9deA=zbyokyBs`-0kz!(fl7iUt$Y);BDQi2}4 zwZY6e1PIb{0uk=fxI>3EgR`YqK6l*<2RW0!$y}oS7t=4EMsA*NXx-NB3@aDUC>u5D zu!0M)YAB|m8laeQwkm2NDpfZMN1eG&!WV# z@&Zgg4O+DTQU^0Eql1mA9hPgv8KR ziMNqX@c^wW+oOC&-Isx)ISpOGENa8wJ0V9XqszUEQ-kHLYx81<#V zBS}wqF8D9GA<8N0o7AZRoHi?z**oZGDT_4u65pPWys(=C}pM#2Q zGqH*PxH-n`>T?-m)M^#!vBG7@W~r|gG99c~x%P)lo=cPmKgVGZlg~2M=DY7I+dI3j zo-M7d3M&W=b5uHq*UswNl6~VM4(cltgadS(xilR|3CwDnUUOtM!}h5ZSfUo&EUzrR zXILDn!K@qR`s1aKZUm`-J8WNBXV1NAmkn$oZKH5WKoOX*snsP=_1m0YQF6=6EQ(h! zQY4qYdYq#GVDITpB<;PGP?-?r!WlRPaR z4eT9B20nhH%6|{zUJhQzpyCSNsF*|{e$H(4@UDUV-+Q}$<$@O#vlxsUB=3V*{l_w4 zgaQo$L81hOYuG=bMql!75rjVHEpozY#*4*8g%SZEzgRLtpZwq6y;XdcAP}KLd;-*M zymK!Pg7e^(Lb=!#M{ECB`(O~=)E_imcpy{wtS{Zk>dHFVyVD1;m9Nb6=6|pyi^z@v z_JXDDagKL4S)3S73d-*PQ3)1qWs{f?XTWOZoryi3CQBVFC_+?`DG8psbhrCd!9O7} zN{&{sfx*mOZ>Zu;nb4 z4%D1>|C2@Ikc!9gZ6~!QvC|kymw|349btcu;Bg?LV};=Cj^7xs5YfaNWq2eO>HC= zHtnnCKv?i;f~@EF_g?P4e6?l0w>cCS#$bG`B;`EZ5*^%ZDh?K(6!|0D66}#g-UODm z+w9VEgh1zAG~~QGc?~Xx5lLvX&d2m-# z8b)U#p<%>EYSQ4>_mKW)E$ zx%cw<7K~Met~W=NxZX3{qhXI1J9zQHABhe(b;OE-k-79(WFOJe1vKOk-qP>M=N*Dv zWngo#QSmN1^x>e@Z#S4@c~6~wU>M(hE4L1qCNMka2oZH?H3hp)a262$QVtAnpL=lN zYET(}F=!zw7#>#b!2S#7;icZ-tdt-EplS@q{KuFTL#rhBlec~{=$K;lZ~LZTY@C^dB{9Bk`4kXF<5@Rn|-UZ8xE6f*y!xOM=lQ(1gbYVD?=W~5>J6?+N&JX1VjiJ} z6m_WQ_{6h0_)#9?ixMTAL{aS_+>HQ5ZpshP2I8)H+8Z$-;6Fz_j1U$ePq?n(Pey%U!}55 z@oTfE$bMCNZ*A&oF?zwZ2PQrGhKf2dBDOXw(D0}g%w6*%^j?e&Q?0|+hMv$+6~O8p z+CI!fTzp}sCw!n&qA>{W83t3sKoA>`$sDQ%!M37vtGDxhuu!PHg$Wdk9Z3EN^If~u zX$@g5|5vKnzGKkA!H~bOJ(bGg(bFBo;(~t825m#XEriOF7J{mI;qo8UPyR+f>KR*MP2maCgEY`dAgI&r`g3AhEzIA*pY(t$%g15S4Pqai~d*nIRD z;*v9A_dX^m>vfu=W166ae}i8dQ6$@os&EA-x`<%G@DgDcG|Z~=`(nITVm-zzRb(AW z8`l0*?Iz&F#`usR%U>$aaVQ2m8_Wmq*n*W_u+lcpz+Hb^$C+EO z(!VpO{{<_JAj%EL)Gb(Pi6&Pf`J`}QGAr$+8#5EKCZ+i1Smfo$IV-<_u%R`)QW3+_ zAyN?^pQv=V)b5=XL^9n$GBUbjP~MU0{s1{pZ?J`cm6qifb-`_PG%MLFWh}ZH;NO0ExQEpbB==!j$0!T~F^(yvz5SH7K{;uWYi=aFzjZ9Ex?;U=8 zjrd0Jm&p!s6bI!Ix(AaTkiJD!o^(_m5ITs#0{r{AV)Bf4^a&Ap(i%=6LmLOy%JYJW zz#1P)9WNzBnB`IT)uDM%x-=1dIf-9mhtGPWhFJa$(`j^8p~r=~h3STMi{b5;jv}_<&l3!7^{o z^zmH0_aQAyYmP05mu|u6r5QbsNfXQOBP=p>D9k&=+D+{XRD_Ia7*~YIMN~@(KMTAE z!$uhO9a|>PVL~x${9$+d>F(=8v*B1knT{C5?!Df7V;+|7!`ksGS|fFaB`oZCfCl9U z8YS<`HEOqNL$bzL2>Z|4dRj3M=)P|Q)%cyz!mo~DbId4tY1-NH71?c$T?t9hFKXcz z-XIGQzL(BvHVO#C^8O$uqvaEY*Ti~r&2&HrS_?RhpcSk{=O+{O^xhVkvk7baxC7bp zthnd|F&3~;R6)9K*b@YUehkx5$r*1ak92TOHp^mx)1{4qEQaJauEOj;9HWEE6L z8OvO%Jzy1nPT$YwDt~;20fh*R^s~!} zmrp7JRHNnw64B&cKZ`)Q^1l!IG?f$yQE9Ie&agk?`@9gc)6TQj>Oh`uE$LAGx(!_j7 z>zEnef*z;V=u`P{3WJLv&GkK`o%_vq(t&5bqQOb3zlZRW0sJPn(~y;}X0okD}8edZKk1jk?oR7Y+a z3o~K17+9U8Vwi^;GP@Z!mutZhrzpf!?TcHH*c_maWj3enN`bFcn2+x(<) zN3f43jQD8v^Pp+J4D%o3xm#=%^!#OT@?ve!@0SZ43Y@nkNYu0a?dOLDd8G(VUz=hLuiw0p z*Kxry`vIapsm-LZt}3GSSknViK+O%B*;;=8sdnJXJ9ixe;lYzb-?-z@m^ROOvDYpy z{T-gqXG>4hk+rb8ArcEv%D5nPM%}DCs|N?>uF@5U_8XXutfPDBy+MGT&njB#rrscg ztBJw0bmynX&(bo$oHA~Wq4f!ovamsReJdg3%=~WT&LrB_B371*e-)CvMXW51XXY(9 zW5-+<+-wmm>-U_XJ0@vk7;%0nOcs6-vIwFBau)~H3S9hACrJN|(pD{(2p@pQ;4$o* zpfO^tfcYr8q=bujS(2}H5id)mLaWEQRVK|nKGBb3ano2SujnHr3JIS2u!<1hb)*VF9Oqw9lWE&kle0_=oVraC;Sr5(Tgvf zI0EH1#V*iVL2iJo;4p>`K7aHWlUevBlejLJZ3J-{gP=ul+C@Yym`^VdheXW(A`r)d z+5Vi&ws*ap9aSqOhnH|y!uWoc&|06TH>>nSgduVA+<;eyei47SkK$1Qj^RH;6C<;w zN{Q2LCUr~CzW!QtOV1`Kep31*DW0uQvMt<1ht&M~>!c3Jsb!|7Q@4&B)Y$Nbb%q(C zA#>SoB5TIb^w0RK#y==IC zTZ%t~zKGvj&6;W8KURKd&<@HBsZO$)OQxo4rY>&S>$Q1@Y_=}>lT-MlM3~u4eNlNZ zpMCxHO%-VgXh3_h`VRAVvH(0s4kW&X(rv#%TeAkdGY}i0_YRz33&}tDL~af$Q-+yP zRDIV#lyIck#-GPVz8!2I{ZKjFJ=lJ|ee~+Jx(mUxv^5}*<@r`sW>Pq41KTfZU=>G8 z4N)JX2r8EudIZ43`-)4rZsh`2Ia{+?+HqJL2vySSB7Ts-6Q=*(Hr<3OP}^H$EhJc| zyV^YD(jN=3hnpsS*9Fanu-_>2JBP&i27B&J5Cm0l`@JS(rpQNt#T!KjHjVa$2z#t> zX;x!%rhlhSSfPYkUFiq$Bs7XV(MPv2rrAi$iIX2z@TknnF-UzmNYJX2cQ1iLYkCTs ztpO4Y5m*f(^-EN!n_xWF{i0Bu-;`TLbiUOXq65(PZ++TL0j34&yA9NrT3i8EoHb}E zYv(;h!J%VKvo}ISi|L4&XofAwQ8$}Bxh>EUoOk&%MofqX@c(!uA>Q*(li1Hcjv;0i z+LBfUp#)|(0Va%_bi(i3#)mOB4EpjoQJr=JJ00Pd6a}Vp-V-b4NSW*q=}3$OaOp5# zVoNRz7_DJo;0Il5$_+HXF(i_cQwAyXSq^7D@n<|cdL`xUvJq)5-?I7ZC z55Z4pxD0_MxJYlHjS@hVgI2%Y7$QN^UejFlM&MRp%EiACQ!q7KXQP1_fH!$En$<68c;xO!s@(JRwm^UH{x6g1{C4$LsGMY@%Z^^Y* zEZX)cG5`I9%pI8Iz%>9Q_5uqMitn=#>~(^&PF^`!aQ@DgOh^1%tkvItcWb31{)}s- zfjFv+@O@?7;uYVQ(tnhDS}*Jp@`5j2)2pX zJLXR&Wf{2$on%8NEn=a++A`N+Rl*p20b?lM6|`}+_m~7vbhB))chcRY9ELwB$Q0Xr zS4rb&71UX_RUAWjpPlPII^I}7a#EMm?6S^G%MnCJ9Z3~=iYuzLDCghn7a=HoDFxk2 z{ams?CysrLkWw@U#+IJNktv=9gP%+qx}V*YAlfMw&ot!cm>ZB!=B-qZ z9W(H%kj4ecOJ8EXU>l@q$v+k(@7m~lLGo@$@~pisLGSD{#mNwwm+0p{UJYS~`_iky_!^W(^ zet~xeJ!Ypl;_j#)?zO#eQ7_wQVkh0yP0S}^nWFMp6i;~B^k!+}J`9YI75mkb|K5Fb zB+<9=Yxm7Af7w(SB50s|Arb+@PAp#d6I*Mxpx~fLpi{kUbw(Z2ZgkI(%^T`Gh%P$} z=ncnX$`8&YdPFpvS-MVZ!MPddpsv%<47RF0Bqxi&;uXxZQtQ+!nCDG-D=06@>wr_j zrbZ(#=eD2hJk8M-RW%f+qgK0KLBP{po){KRBRF2|^?R za|A&#r^pRqMt%BEBb>T9t=1tgs*fN->QR1yXqFu|ip@E#p*Q*?FIT%)hS5pd@peII zRcmO}n9cR|bp*pf4;UNdT8P$;kSoomv!fW%%!TdLM+~fP&f2|GRPQspO0T;D8P@K* zMwfooh_R0gG-64#E*o_fhN-g!p+?ji+K{l%&<>Bp@8|7>&z#p{E&WBPFUS9Zwf4X1OA0f~gh>Yup(Le_1R@RB> z7`kP^2tYQ?JRlA8fj&li>h`d%9gGo+O(2|gCUgeS(6&yg8q#eAb-gRQynGkw)HKef8wUaq~^4FQP2165KV zqIp^A5pFDvdUQ`h>@d!Uo2ahkL$*31U|^V>Zw%1pY`~@f22f~rhplS6edT8RQ*RI< zRSF=k)-W;#kup*aifI=co&K=(t^u&^AaHwYSdHFd?Dy;vQxC?h^V9Q6Lx zfHs9H6O3kX5Ap5+a6`b!*}0bLLx;oQB(@PZRw+0fad0NGlQqk>T^x8tVeu{^Ad)Vb6(CM!uh=Tf~?r=+lzw835qo@&x&^Cf#FHi_c3@JMnbgtkJof9&* z=-Ym~I;83;+A`m4e7k9uAsl{rw6^)TwKoTL0NHTQ(jfp;JFT;7FA6t)n~#usOs3hd zzm3jA5RhFqSh@kW9Z_r>gK+B(dlYf|sS4$wsJoh&YXJ8g&$M%z9&fiXJdNrESf-Y; zUwi#V*M3EIN(<2SLG_F&BCh=0j)(})0g9&$Y=3niI(UV$``;5ML0Dt19#VBC^b#qMPa5c>hY#;Rx^ovW%E-n{_{8)GYKI0$#470-2Lr_w0o#DX zR;}Yd6IGiHkd%MXM1k+JA@Bre9$76iUz+1J^FWs)^F6}WOsl+V?rUX5-GV4vmwx|$ zYM8fOP(L0$gf<7w+kCXS@!)|#>3MZful1nVB@t?YQAy0lEVls;oW0W5?9pv}`{>d7 zH!^n}K`(0h-k%Oi<_FL`v-|dKgT0vp<{AS*(K8<*ZdHTyu`009Xd6(-R*kBkE+0FM zzQa+LX2;YWdXz2@YNH0@LD{?tz^kJ427tdo1=7)A^yop!?7<*a6iapw(T^|yLcbH; zV^pA7Oqf=E*J~+9*Y5TDI76TX4%Iyqb1f>TtC&qS>UBflnRdQ69^L=ufsR7{W}Yyy zWk?(WVS<7)B_&MppJZWRXq&kRC(0`kGL2c?fNyv9E`q9xgExyw3@LuG;4UwsTJL^o z^W8(cwb`v~tZzP8ClhA_*#T3a2JjYYKYaH{zTwe>(&p%5)3)?h@j>}S#6jDypI2UN zzcFi#VNG&It<{>PIuh87z&3BjaTpZj{ld{o&^8ns^>7&3<2+IO0b7IP1Mw+DYo*nn z&7EJ?))42PmA!$?q;~Fae*H*6KU^vg{d+d?rDc?GxXv3uCuC!X#a8zo$VLIb$$PG(MaQ%1Fs*WI095(FbjYGtMQ_5| z3Ma{x0w`7;?Gzd_4f#!{W@`pUJ%kNGI)aHPLJAG|CQwn2Drf3WGQlFaI|nkSiAAqx z^W04a0CcIxx?mdEuQbM4im}zsc>~*sJ@GOFT%4dsI29T`s9qqYSLYNLBQch1_S#H* zD3Mur+#4|e9nwuJ2r|AKNfbyaXRDv3zUpu8vyns;(uz|I?q$%1B>zj3kbghUKN3Q;5fRX6apz;2S)=fHQQRa^+mh2!O)E8E5Ytrq|Fi~F)({PvgC z;}z-T2p&HXZ((2{!E=c9I-0W}Dbg*lpgpV?$Qn~_?qEtx+$;uzOYwn9?&z>rsj*x+ z$HC#MP;8JO|D$9|tLAvQgzoce=nfYMa5O`6yzzLgUw~`~`#9%_>=5PDP!eZ<11Ey8 zL{mprVWo;KnI0mvARA%kic(A#;8Tmngujf?_f1H)^C6VDJYmGNAwxm6*|F)(Xt3_EKPb zR_Gz*2(C@bM8FgEFYYUk7T2IW?)l!~(NC`0d4Ghf1_Z0>D<#@MTUItm~k0`HiRUbX@m>f}UJ*cy52kVwIy)G;rO@yW86+%;b zb5=9T*Kk}t@P%yQI5>Ycpy7dV0O!BWgc{jqY!Nr?)0Y4F9#D;L{q&h<9pulj_|pgR z#Vx;F5x~~8Kq7b(0`-rEJvl(wj~LPufR6I+KAkG@{}k`bwnjZ5*p>>kf?`i!`}3W+ zzQskJ#s!l1vPnf!w>hK)y@Y!}gY$U>fz*#L_udG2#r3zJq&gw=#jl?}dwF>Dqr)f4 z@ZF`%ppL7?&g=bWl*@~p7K9B<4-O!t|Ghp`5QDPCa-m*8ipmgd8NKTjE|1@@-`hC; zSine!19NE#$Lkvp3n#!`CoIp3nF!S^6Y70Y}JTq^}K~cIT~Dvq=s1n zNMh+4i^QzpFPL%Hj!7DA4NESE8&q`?~y|EuJJA&#yL5z8o=YOkIblS1-H71u=*vPN(HwUe} z1Q$fPZ_HL>wTp!@E=TBEctTvXdIRO0I8;8Td+FP#3~f0cB+Xb?@kEShQ7bTP1s{VH z!Mm@X#et4${q`v0e@m9h$swWaduJ{yRHxffn=BCd$4erYa!;D0Zf$wx{l~24@K8-| z$u-ds2?bp}CdEZY`N!_Jw(}TTmeHWQyuO0C;v6I<0buDBtZ}VJuQn zplbenmgfQ6aM!$~$P;G;8|kl3*lY5`dO7X3!KRe`wsbp~<$UwRS@zX9F`KIT7+H>| zL9RLetI12RG+cpHsTN{ilCwqi4_hshypZ%%_}QSu-8dl zc3EN;_Kg7zvV!@me{y7Z@=oWSDbf*ERxNkrzsXiv@!TCfalVj!$J;bFlt=mnWAR5L z;BUR!;YYW6c7}Tf)l5W17BZ;DVW{a~s3Mds0NwkumoNBn1kx%uWE_-K6&|YTbreSk zLcl5{U<=3~>riLm2sx^dtSRiDHM&qzSxl?bgE+U{C{g%kqlZm`R(BW670h?>TtDc< z5a69y1o_U#MvD6(8YjN9a~Utf$?&F)%S+uXS1OVgy|O|eb3bsS(*mRexH?saMv&bq z5Lp{~oblI!9r4=L!wN=NHtT7yw#u762Ho!yAWs{^3u?mbn($%=>6MZ?!4771jgEwn z2f_+r1lR2M03>~&9kB|viGFzYUif(FBQKGl$?aaX-l$t)MfCG8ro8mtZBPDi_o>O@ zX6q=G`*hb_f7|6vGICCw)ywy z7OEg%2$#4X%b8$QXflsyz>xTB7dTw+g&}Jlb26T?bf~=*=y* zi?=8*1Cn+=#CUexKf>ac;WGhLE0EI$bzw{pYi8@U+enPGv5joI;gVLb7rkz#14y3VPoU{`@w#JO($ETWLVg<)5aNa zhqXqi_i&4KH$vMeu=vmV zj5=`AOdy;$R0jvGTPTB;^bLCVdv20rP(>!K+`#51>MPbs$W{)iJQ$rqWIP;+7)F2q zdh$NQHvm=)mWozn{~Yyr!@!zA4@pgP1bxXlr3MjLzfJ?nPp3+;Di3<;qFwO#P_RHB zDnNx9*Lx!@evu8bbEs^(XF#-=QoURd^+UsKfJ1u&Lx3gxu1Lv>j1mRbAakXJ|M(;i z8UOJw$17|2*jPIg{m3Cm2-Tx727Cv34Abyo4y2LNir*6mnqVwS^E-5{BbwMxRySkI z)&u+7uEL1G8JUX07do1#R_(L2*d90yf$Th4W?74{=Yn4ojEgN+T%BMAI3oR*=j8D( z@8+K|FtwtA>PZAWP(G6&iHZxm!OIBh(8dXb4}!R839J}P1pTeDmsQ)v4!Lva#iOky zikpPuidN*gC<*-%}kG{Z4K<>EMA1X83U8*tp;ckZDr*h)YJr-_RS#DfKxDB=T* zS-FaP0xwY-lc+knWaP6oeO8Ljb4xnhTs|@U+!B!mP1h^!I;tuP6DC%lVGTT5ra=ri zK~C2O(2MEk^sswmAcJZjtAkGpxi{X-7ZrcyOwqIkP@D7~c zBGlf^L+#0Ojsw-6{V+onQ!q(X`3#Rv0;!FEwO*6h0c7GeXW=9ns zQ+<>?r4|%CMVLv^Y=umE7QefFYBnaT9s}$o%nvI%nzDuVS7w-XDd`8Jtmx5U3Gk_o{fan}xCBoR*dCWfGyXeUuE6Zxb|+&&7* zV5oH$(oD76o2>;?O{>Jwut$aLe?bUZ>J83Hfm8q(;y;Y3wy+^|*6bM1gs%flnV7$2kCcO6g1dKRX9wtXX9uPn{2@^c z`9Qvit;!*+w~~J6G%BH~O%G;I&g3RqQs0Yz!JLEI71+r`I$j+l9#^zgeW^dnwZSMX zbEs7h%hj+&jE|Kt)>HhxFt5^HdzWrXVx7(Dx z2c`C(N`d{S<#s)M{Ia40-p7}6t_^SSC>OkcvHg5+r?T@xYx`ei8upRkdUf*%L85Hs zxFB40!lEgQBfB)7DIIe{H*mJpuw@!jih~*JKPO{MKmNaCD{3`Gxc}RMsa6+97r~8g z&|*e&;`@o=rdL-77cO`_u(%nTRP#L77)QO+7lU>eNFxVoDlufN8q^n&%Z4pQ=TKM~ zuKg1KuGL`S*oa@~&lQc7V#MvfR`ajvg)cw*2te7q^3Uy0U+uUE|9x3NE}`aKlb^Bx zVjzx5oFZ=)ZFI{gc{P`Rlebet#s`z9>7;tk|GBif_UAu~D}65d^FP$LzuIn9qvD_c zoI8;KC$E^T1)(9ZK!`MhDT#517}fCvi+yYS7?z#qfJSSHN6UC?YiohHBDE{F7@TX_ z1_G0wwQ2$q&Q2?rk6#eZDOD@vJ@P1cpoJrhb#6%82_%hB(l7ET_U)x{(|i^-){-%$?|1&4oc>0&KA2nTWp3}M*(B)bd zA0OXTqFEF~*HWO>jPMGn|8Q`!QqM|uEFkI5RXHay1Yue#325W=wDOb4f`<}_mxkl8 zJtYN~iuOdpwiron#kA7(tQaPy9$MKUaI_;CYh#`h4vW$%3_8cO&4iEu%$!|27bf0W zbgzA6*Vpj`{n64hfNYMmBA{q{x}#e?>9pL*#g$DC8zZhk?gSy`7Glb{kXx`v6}pi) zayf(8TR|HdtOZ9M4TW2q1xU`xN*ofyS>SvE$H%Rz_a%SBJHf;;!alGUWAca$vU`wR z2pKufV_e!T2y1MyqSzZq1F_TM#$W%kxwN#px@vwx+C$o8q{g!~14wwVmo zju^(krvq?sjp&}V5KaIyLIT1;uRemsw~MeOw(h7zwulkDXeJKlayTNj{sl{Xj^YUT zQN0!zW-C#l18Z+Ow2)8mwP5E>lje9R(h3aH5z6%(#`6*nR1z^(5v|x}o)s>GF%aMd z;D+PpBArSr*nUQtMY(h*YUpm=7HlM#x*mM?>l&3-;)Z1y5@`vWh1dz=`6Qw2FjX{0 z7YPjcC8PU-An^4)W^$BfIQt7mN0Zr$uK|gMt;VM)2{Ubp)&%!YxcnkG4fv`xpnzdd z+BhAZ743YT`e4a9YBpQMRCg>NK$rnh=Z8&BD&OUi5XlLsBXt6j2#;qOeMlGN7*d5P z_f4RNT=IhMi(lh<9@oi~1SVeJ{?**k;=s!+HA9acebH%_>~oT8;*FV#*aw;;3i#=EudsO{7`aX-V`)8~RCz4J zm&+J(@MILoF@ofm3oY@P_+s~ zXoyyow{LUK3);W3zJ2kGgeh{b<$~#clwDara*!o>0H0Uki&%A;vk@gN(!ifC#))0+ zQb(h`dj~^=E=5Z(;r_a1F9be)2yey6dIPgzif?g&KKc>aR4Uabgp(Dw;PMp>GF%DU-rs)tyaIkh;!W$#M&nnvuj1BfkV;Bc z9ycOeoDo}8Hp<(ET%b6sxg<9>f)}^|P6iH_ZUtxZh!bm0WgIW4YuF7@j*zGT_U%ZOi z&BeWy`5~N~PHtHeU{)lYaK?qG5su7P+EB2F-u&t}910x~0GW(lb_qb-KoVB{B3VU0 z^7tWE64s^yrqJe$FXuK&4@;W}S?6C7QvB-^5qEY?VeKChVD9g`uMhWLy)3W2hu3)W z$=c)o<9|Lz)IkcB*a!q8j;90)^XNKd0gQaA8&igqM(8f?$eBFaUdS`Pwi-Db~roJ~o!W(V@;z1!mG2-P8 zA#rv9-s>WafQD6I`$PN(p@9`iEcFp}08#`bo*AfcfkJi!YnH$TDo8lkXA(wqcom*Vi5+r$nSCyD5AsPMLq7tZc4TLX_ADKipgyg$ zk;b$p$>dABUC4C-bI0M*uqxq%%8UsnVjr&(hIp4z0REs!_3oNO$lZ`yg|}r!2yaNr zGg-qO4P+Ea0q8FMN?@g5NqG6JT2=+dNTI^|`Rb}nh5FQf$?GTgZ3o;JWq`<(22pLD zdla=gIOf>9PM;%VQxf%CpSwU{db4Nr)^d&^GZ}ovN5BArT7P`p6$Sp}9vBj0ta&~R z+Aaj)ID>eb$6W*w!SMH*Ai$Wf9qd5(QXA%*S>hN#Y6n5vRYU)tA4Rb@_?TI{*{+^N z;20SYMPr5gMnr)x4Ovw_81(Q3S_8u$~?4fvl>;cbDwO)C*c2kIN~6@Z&bI zq?iwIOgsXZg^1LnwbLH9V8Dc4&}}2~jBbtWE|;Ewfe5#Rpg2S))gpF-fwsFtMuz0s zlDgyDhZCNT)3sy+AEF^UKFt^s#BroHlM(tr+VgAm$7byxX7#JJdLd{G%*+y*1vkY? zFq!g6B0d<3o-E~|<#Z!iUHXKnB|&HUyjb=olVW{v`q!J%lEyup5>2lh8w%v|2z5kO z7}(Zx!dOl!58^dVMdK?&qulKFiZ((Y56L7X@0GNm@p1ABn?(+J#@WnZIBe-RjoQMf zGXX^ySKVH-t*O_6{CfhAwdwXi#36w!Foq0AlX=q=)w>_uvKRo=k#t~p=Z9AntSMv( z?wUDA7rf|;>U7#k1M58JVe>HVqT-S54vz_uP&qew{aGHEuZ!$p%7NLq+zs5X!GtYu ztU#8=L>WSCk+06I3VQO!QujMu#APgUu^g3dD zA+lkFv_58;m#eBdzv?4<*$N_VYhp~%o?r zYPN8W3t=TA=?UCAAD6Z?GNVg2%u0V5tCY_uwWXQ3!pPHzyk+e&zW#dsn?xPN;G|Yd z41u(YMoH3si5A_EO2Eug43not)hH_GzvraW=v%a8c<$Cp+=;&adSi2P4s?cR)5|88 zR$G?{w?f_|j540vL+8{7=z?I!9d>I=g|MdhBH5G}wE!NbYT^NKa6m>OP#V`c3ATi! zlo2$f;36;_R6sSxLvs|^^!SVruFUHwV&X6i3W$Vz=)~pr9%454#)D7qqpglR~nvL zWC~4n<14OwJV3FBE@j-(x18jMsL`1=xQw;2c;V7R#`#`UNAD3JoyOCPEEDL4m9t(i+Pm+c%PmYJ70;7@Am_ZAl7LZRNpw!7bm|ya}!a z+m|T<2}r2J`NiH%caa1j%{7u;(Bud=b8ttf zxJ)6JWq)k&P#2ehBLnl~5s|8#(0u1IQwqwls`m}||> z4doHT)PviBL?C4_#*+sTDudO!n(okcqIxf?|9aN%iv_0+>%SSD)g`4w!<0?%kdaGf zs?kmZpn>PnsE#}@F#SEF>qDwjzqYcjl3> z0qGIqJ^}4nJ|*xVaLX?vxNNJ9zWkVo(*M~-fQJxAqWIX-q<0KuJUBb>l5QN7{)Z4f zVx4cvB=F0|y8nh$;P$Z3T*^#1;gS5pan)D{YCp@v1;VgdJVZF>L76%w|C7=T9z>u{{{@Z zlHvg!eV8y&aIfGoZ9wew2$3;6>P3$x4o2}hdv!G@_ma98xJ3X)x0xwqgcM(11?659I6A-`q&4aYGv^B2BVpFy;q6`zP{%tDt$gZ@YMoav zCSm@xiIZK#i5OclKk?Mo1T(M6YP$s)Yaw2ASHxaE+x_!u*7Y+3f%{R6gJCd`40dDc zZD{6Db)c^fpRH|V4Royjlwmqh4zqD`J;vGy;ZPTBtcdR>wI@>!hK0$dLZrgu_-4yi z{XZ)Y!A-j0p?msq^2IWCAR2Xh5qZi9lNsxCQbApqo1hV4<#9yiv$Q$7*yK6YU-4aP zY`N0_JXYWaTjs%Hj$4L#4EoZ|IHR`z;F@urlN>UGvi4jM5io=aTz!sMu2`-2@SR8= z5@}sC!TH~@co=65Qj+N)=7ne(XKwQ4(CyD?I1Pq%1Mv5gDct12PaPYV+@3i~PbUdJ zL%H*qq+z0zK3GR0fF#nEvKWx1Fq0`vF&e*5*K-$rNq?KkTSoh{rT!*C716P@iOba;!Z+6i3*Bqgb#ol;)O zry~`rn4MUBOdqQZein7{k~3I2d@#u49tZAVyP)0x$|HJx(|2h#)H{rg zhU}RPR3>Iwt;|x{Y>9R&^o(mG%QB4x()-yYE(jd)IMuvpYvN^$YS`(EVF=uWD8eoy zd-~W|wTI)}H5sLFU~Dwi)pa?gxthB!tE7#7CT=Ng+^TxS{CfYXSc}0W%YKv19(yVW zCbei%GQ$jxT8P-D7q|ivgf2|fqG4zQ2TY*GNHhmxm9!laozZ^vpXPmNdXY!X~+->SZ5#f$hG8g@6j(h@+3ltSBetWLjsXcJIsyA0gNa z(&wVILA;HJ+FQ!vNM{*ZqGr>sc+H{x@GWK9@VdpN^;ee3k?46o(X=Sz%9(&fPpe{E z2#DPgk47%|+6?T02T zkR%zNd@IhrOnP&cB9!Qwq&&z!9!z$|HFA18v$5is5iraGZ{hZs)vU#Ygqb43l36sB zNc9T{(rmx(Ee}&oOlJkB@uwDmnIL~;U_>j$o`Dou8T;u(-bw>=*a0_|7N}4tn;Qu-o*mQY_r}FZl;>{rVD18_hJAKZg5o$`v`%UFdP%kf1|B0 zJ5CW-fAj)Jj|t>8oDK~PY-^bWHd&TLHuWUSwl`hG+xI44z{WTE;F@;6z^&r`FN+b< zQH^#v`s%`zfDe@$8KbQ*sD8d@cE0)wxKlNGPzS?k&Bo_M95|@udV?z&W2+?**rGKW z=qT!96iD%QlJJ>O`@xp8Cx$4>`5~$naG$G4j*vqLpRKL(spdQnpR;{eHd%ykfWJ$^ zd}&38TwNvi8-7W1G6`A4C7_teTk@pB$`~xc2COa|G2;6{Daw^-)Z-vmaw*DgqD;ef z$2RBkOtUO8CE&$_01(}tXHl8qT1=&ojeBr0Xo*)x1FjP7k$9fPHK|*D2dmAxIlU6? zEbQ30d6PJ&khOqy8@X|fe?cn&&PMsv@PSb5nsj%ka17-C+X_38FBkm|0*plxBz7kej z9@6M}7Qn~k{rzeC^~=4N&p`-I5CXX%=8OVKPFit%BJ5*9{CAE|L`72kwE$ho6*cyw zZd7fCVaI$lgxhP``a?^aafSaf9XzmeIL-EY5kok6Ks=v#7w{16On7;Ri&Zf8+PRGT z^NKUbggr1;J`6V)Y|l9Ne3OQ=P6H+iOH~OW2j?dWfM5pKyQsiEN8^$xYl-Ix3(yL! zWSjuTnz}~HA%}r|r9I8~j=Ojt=Dr#q8O?=Zfu9X}oeC^uGG8|NQY$0ZDZ?{!FqaHh zSgBvZb=Hc2D)h_cyNmN4Lh-m^P&(va!OjsjAaEvcHe_D@1%aQ2zCa77phR=NWEOdJ zn64Z(`c*i#_hdQ!OC@l+M*bm8=tfaxKlL;^$1wb!;25a$03vMzp-^IiJ#rDK%cJgF zI2aIOeX9&bk2p3E=m}av9GwwX#I2qEnc5GvvFAc_VXa}d)=xgub_)5IFTi28PT@}+ z5yZQ22WTON3BxPr&)U7yYTLE~i{8FG6^7@yP>9w_t7dJjfUne(qd$B=J^fFJfAY!B zs4Bh-u`Nv9u{kiAK>bJ&uzzEmz~8Rh`~y*qpeu^MGnm ztZc+fS*kN`@Lj-Las;GR?7pk+`J{OgEfpLVe6g)nJG!>@v|Cugk>NqTiveP1D4jep z%LTDhK3T~tBJ3f6d50F^v`=>7h|XGFalI672;+fS6nX+MG!Wi%R}K5O%t`gbY3)O4 zwO(2+XlHf+LXO?IPO7%Y(^`RU8gTcZYdeO9Ps*U|f{5WBc9w3RkvXZ0??!4R%DKw( z{Z~)6_bacSJwvRc%F*_d{oM-XeY6Wg;Az?wXO^Lanl6{^mfJ13>(dqfp6MWIqL z0bv|)oXZ?F#3hjyr#9#~m(LTX|Ll0`&Q?`9cga#r&h?`lPedU5!7-fAR% z?s-)lHYBi@GUHt6D)?Ib|Dwh8-@WG0{JkZvrx=9XQv%O4i4y>J9&E1X=h?eZZ)E!;0kbY1dY@CR zmi3&mIv^NRHq5U?Nau)dx8{chxWfPGMnfY_BCFar-|WI zih^6_@Jg0g-XIqQ?T@X`AnvgAyg@({=kgJW2g&o7KVpcotVwnbxKwF(iH^yU+k5&E zgE2>2ywL(XfM|ev0~cV98vj~+jk&0v_?OJV2q6ySh&MVG3e*IfESuP4BO8DiyYj9! zXwh4UZNvEnD!}UCO5r19`1YSxUjO*AajCH2S6hpRhzdI8~1aF`vXI0;UKPxk9S*1d~$;N{#gEuW$SU-U^v7j?HH2=k?;Z!OxBLlIXi} zDxgEcMb*Y?i_CW@ys;5C!(XLu@0Zp~o5xg)PaGUhG%yAleEq}MrTdVR=*~dZ%>LQP zCK}n8x0M$_Bm>&XeN)=ZXv~dX9q-w`pMo3v%&|&AhgFCm4jbSmnhyNjOvjF+PAo$$ zFCN3D)Y{-tNOb7?L_h#+j0LX^qLI7QzuYf+W2e|8sr=gt#1|tHkoM!%j z2bxG^=yPUq_?;LV0#_nz^3Z(u-R`Sr)C6Wl-j92{7yAUmq8_LMJctB*+bn%s+CbV6 z#>5~Y!&L(z4J|SmNkmawyd}(y721sHr**1hOZ+j5UrVkg`!}@9U7tfM`JUmLrE z8+=L&uXq2x$0&{vrZ(QS=$brVE6HR_SOI^r{J*^BLy`yow+vBia#1M=3)a;X?{BU+ z>*6Vtthk?`T*1xR-N(tQ*z*V!QSFQxZL?i6&#LWrJ+rrGzI$7HIQ+HxUx-Q5htqqB z+zh0j^el-=-Nx{*_8d9q<-5wp@%%>(WKzK094Rai2S)`M0omsX>a@tlP^VyHISEe)z2mrugCLVioIQN++=$x&SSJCOKp zdnaU}8JK}@iY=T;-g(pP3+ADC+F#z3y{(eG<5K2ZL5s0NvS;%w6DWQwQdC_0 zo$)$w0WEH3G69*=u2A9vU!wo+L9B3Yo-}Ik2R}s$Df8X0 zgVX!}bxJc8C^P=bI5G6=$5L8^Dw_+|n65|`t$|VTLN%`W9JC?eq;mhPl5%g&C0pP67Ne@=|cD-+-8M1%#&jCjvQJt7qY#wKsSLRHK&;0}wh zDoMIB0q;$}7?Gk@_KzwEfPA$5{O{YZmnR;>dq({0ya9Y*tQN=K%@d6ieX|$@XJe|_nEt{lb<3JV}Us&qVCG$C6-nOb2A}Yv0*4YL!{g% zJ5Qg#KK#Y3iA?QyS)xWAudE$!n5WxE+fK$N@q^-8+j~bpxjOU8;p};xa`Gs3EFzR3 z*oUm6rb`NTDY%Y-P!gOi@*qH}IMHTF8iQs+ZIY@wcvd)f;neL=5NWo^ylbZTM#Vxn zgQ(6ylFIm}dJ=F{!FLcv+nb8rD~--kZBul7ML?{Y5@@zQUf#gHm|{4dbiC8J8HWf- zX2n#1;1(|5f(tKN5hLY-#bTH=Fw6dIqet{+p#p2H9N^`NY~02_(_+yRUUe^RUydt; z9HXBuIAOUserD$31%+9h7{<)DHqLn1CAM`aEg6n=GtO=#Yc*T{w{$15*O}WW>-rmm zfx_wh2yraTh(|=B#GkGD7fJcPCw2ZkfHU*%Em!Y*Tpxey_K0QTy?fW;_`Bu@L|@+G zg(QfB;;6F7Z&Wcaa#a_O1hlu{mhf6x+pCIIkQ1=Xq zh^fyIrazpEOA@et`Or;?9j;$KdiHFGPvo|RtDYa3M1(<7H>k-m8eGAs+(HGvBog;u zs1vNW8K^Eg9lT{M#)#?-xA;>~C}ts)e{R;`{9X!$%4P}Lymtb$gcxA|pS`bbXyZuM z{fvIatWZ{%Aj#N{cY{N6Fvd3LVDJU9@oq?j5CU{8Bvujz)^UFOeV(f7o}M=$u$^T0 zu=k!A&Ght3b#-;U*LyJG&$eFGDwPk>7ty2pUq6l-(SvAjK6>!@!6Is$ei}UT7}B!CvXDGde}z=F@n(&VWe%njj+|zh2}H zhJB-E#J<`{*h@6y&YlNqX z+g}+c5K7gk;_wTx z!Xk?RE(MtjvT#B}r9fXZ`I==f_`d_PsP?K4Gjz9KrP5@E=_VE=a}xBEOhKVPfMUE$ zkoYW2)(z>AO$n^zhSa*w=x@CqxsKQ?uxsr5b=^M4Lr`_U1vK7W*EvNjbcRx8Zu(se zEf#k|st<0>mo$C*|&ClX2n@VSKB zlveK}HSsUyD5^MHiko%Z&A;O6%i|Ye_QwqXiKIMgXt`5}EKeGF`l57qHUqKLp)t7KH5br4O{3O1b|7Jo})Rqk^6`h4V9LDB)s(8A>-OJ&kHGC|QMfwieiu zV4h&6aa{VHA=vj7h%1&P``0l@InsUkl@F>)>a|D&Fm>B*i?xRRe_B}~JTNw|`-p8k0;Fq?|8a)W=P*F+nfI)w=R0crxrVaI%2|9TO2(ucSz#U(_r&z(=_AfFMl z!N%;YZvD>ZGM@V%=5*SANQTWBZko6;eHGve&Ax~)Qil+Gv+{I@21t=$G)cB- z;}dF}eUU6;ZtG+3%Z0tl`*`T3FDvgQUIGrIsy6!2_}~P7e|Z5y@dQ56l{)=A7LeFE zM+7grX)#$P8k}_UJc^k%&cP~dHe1D3q*R`*6q7>!2kuR*o^f`LMAKt9;w3mDgIFGS z5pqUO{lXEEYC>`Rgyp2A`~58#-x5rroY8GYB5()z^O z?pKRQBmYwVd+=&$XM63}N{-V(u1Uh3WmoN0Y~ltvx4B}Z1oNvAY+cxM;q(cA3=)4j z7m-zs4c=6b!)bOEZLa53 zeB_D~MsLBCfqDw+SY?|crG?<)D89CS`hct17$n#T9<7oVolB5fkYL21eDpO8WJBm^ zID@%0AqX@r$c2Ld9CXW@0oqb$EoT}==BIjN;XX&{Ef^ezSNf(b$uF>Uy|$n?V(H;3 zus}V3dGz|HvIfcWuKC*4n+c*xxrQo79B~D+=Wae3r(;O6w-8W zCF{FyBMu)rlBj|hzES&IQVPZETmcj_Peg?T#_QVCv*X}4q{22118H5n6+88No`Jc! zxxLDRXc+~3cgyz}`R0E=OZ|RYz9-dw=0@iSs1AyD4;K~}P`nDB%;h>?zK10TcDD#` zq7TuBFp{Kpo)<+Dn>veEvifhb6da!kSVhV(|(rA1ItTIfm6J2WuFaQV%fR778(9kIPN>|)P4 zE05|wK6v=kFaEFkJpZQeBzQdN7s%bwS|PRq8;t6GTz$&Z&j|_Sl`PGG9WqgbVgI6b zgv2Z4w$#@sU<``f*KWZ0=AUrAri3*SjRsc?45znMGqztOa)!EMvXec+dtm_&KeXQ4KkW0kl@pBswM=*0qJ8z9NlVu0u{^A37BKW5$9e@{zv}WB8 z=i*8`8SK`yWbnW~g1a;=&)5YN-cd+0?t{;ijMmW0mn&+yeqpulYF1 z!N|w!s2tKVB_#sA4jI1K2gd}kg)tn!WJT=YwN7wWo!At=ap)MgPddj_0Boa&8;%8{ zO~h}(FUJ@`*9S>@939GChI@l(c7;nx!6L~;VjaF)!|ym&Ht8~#(=JM^d{k99Yyl?;5gH=#T&l^z^EL?H z=?t36Qx)gyoFbk*Z57D&N6>fRoobz$7oNGi6+1uZNxj6zRReZ@DTw zlISe(dAkW7W(d~{o~xLXPuDP&phN7Ruu*^H-69HcvjiF*JX$OF<3U*n&A8wz_eAqx zl5pICj1D8pN|wll7_+s!e|Ua+1|^|CC^6iydkvp@$Ew@IL5=?Ojdk&NkDkM8FxpY> zwz0sZ(13K~=llF;gnvmu=IZl%_bTvnX*`L}FpJU$lx9XvFsTqgakmv&tvZ$ROoF$F zSm83AeySc<3HTS7>0ljYU7HBC>7~6v<1b3Y zGwl=!SOpcpqEC>Wi4rsaOxvWJnGf$NA&ga+knxF`$eBC-k&e}WWRB#Hf8<4R#|%LY z4o;|m8^7ZpnNvMadb#5tDX#@A)aT=l|4;IdGoONW6b1J*sw}gThq^52u=x2W&|*d4 znbMgg!F7rg98_7*8d94@ekxbp6}Plzv&eL(*-5-ckRFprsCRZQns+FQEE@vSU zLhOuT6C*&8M@>~Ch|GMg(+WItk)M(oa@&%CN&qAg{LoyEx~E;(?5LbPfvJUxV#J#q zcA1_S3qyLB^KK8Rr@AnmsqU2;I?eI~Ro`dgCJoAFY|OCw_B!J%Q^5D9{bf?FGFT7o zHOTuR>12>JHy!<;X$Jt+P`9jFd*|MEmr*5?6XriGql)e~GGZX-5=2i%1jrYQH`LSXbPsGM_e|+@SPu^QnEe0-ZOhjGvz^e@{Xc{*? z|K||#`V<#pr%za!G>m$>+#!R{ZY25{ zA+7HviXAXHaJi1wPG{irG&(~nWgk+iQDm@Ua676(pCB^c&B_V)fhV>`G$$OLG@R2Z zPD~MEc`Kw20JGg%$_=Ekul3p$O|^jlX)y}bFwbB8e3l)+69tOIgyggN#+M0Z?O|(b zLb+t{94S%ULW)x?SI5KiPCTL{npui=G_7tAX$fgHg0m3(PLNcY*|hk8yJ;G`yde}` zY}DBLes`&Y;qin2;3^*RUzfAkjSMG_=4jaFUN&j*Uas!r>`8W)+6DBQ_O1*cc|D;w z%DCc=^I>ZU+bhjB!;{w8XmEJtNkiHR!-j!D#I?j%`u!r(>A@kxdB9>mxktmy(mvCV z@-XzAgmc5ltwV{8u8GznC}Cuh(ISFCw5Wl;blNVcpDOQPt*mbCylFmLd%dys_g8D1 zOt!oIVr}6_QlIxUB1EY>HezgaU8EtbArd`veIH(=gOGlOTD^ z$!f=9jq?+ZB1wVhH`!iH8a)LSmt=!=<cd9ghpWKL0PaXNWmzC^nBxP$21f{5M3M4s>^-+SmwXJn zIA|+qwGt}uMven;I2Ed?t3L30VYWWMfb<&@g}w0ekKE3m!Y8m;(PXvI{4-j8lTFi+ zVe;Q&uL$7}E}KRoWyf#7pTG7`JCMVWU~1~Af*N8G$oETVpjwxv&i_LIFdqs1DVP=u zKNcv#HJ~>@kV8a$B@}d*y|%w+@nlLm;7uz5A^7L%TX1+_B0ic9sMMPz2GmCE3;&j+ z3rG`^Aq+7_#M8^)78fZt?XEb4BkX=N`hc-fvr($boxK)z{ziD z$>1EQJ}sbbu+*eeIZyBOP;hAeP@)&$un2Grsdvz_5-u+&up2t)J5UTlaSj z>e2FBuk3W-+Z)T0v+DCr}Ufy{4$Fehi{mtXrW&Xc)JDkD0ltK=CGI?qNz(P*$loX>_WUaTo%sd<`ix=(25gYY1W-N1@6_atMs&RHdxaQ|FEp9T{ z?FMKWPd$r~9%c!QiG||L5l8U$@Ng5=t#LNda$v@C*`Os&G+Jx7ZuICcjM0 z^yXlhxGe>veC{2YIIO+QyH5+KQkwo{x51yc_+b5JG-|@;{}OMGr$%YY$P#K*QfYl5 zej~ndtgXkI{nLzeU;xn*;+q8*HX2MtH50busp%%ax)J3J))Lar3H$2kXm`i}e=z6# z<1zn0IiAsYfD3)%bzZ>U2KV;0_pb7_weT)?`T@(@)d$DmRetHDT`1PpGy%;xWZ%>! z6h1#g2^M4uLF6Mu@GEQfKH)3#p)ne;&akjbBd5G|cXc68V8Tz%BEu^mif$|PVgF8E z7^OPqoFCe5`ctE{A2c~%tX2`q_?nq&>0A?_$;^`Lj=q^o$EU6{KW&AD71&jhB zE=P*hnH!91iHMrA%@0{*YiGs4RDN+mK%JzFU5h3Er8%+H)oyaO@RySU#Upi{zs`M-dt z_r%Pfv{9@_o-j(LN|bLKGC4Y2o<9OAvHJ{ZMpsi{QZF$p)F&rH{1MhS*LT-9cXn4c zSJw~)nNfpbXV{L#aa_^BXKOpF+v~4)S#1wB4y*;@#d8Y(xwpahtPM3?%W|}{zWHKf zE!y1L+0*f}>sjFd+Yr(=01`Njiw@Qa0y zy`|1Ufkd)Ld-FKlZXFpaUEt##Z^D$-%ZspbA;H-9r>Ho0&N_+ra#Sc)&W9G z`P;$h2r1m4jDvm{f1@-mMR`#PBS)7+MNmatJH=HmE=@)&9TyXNl6kQ&e>-*Z**%r# zc^ezwQ#aVyr24}63Yoo*?_{n&*m0PWsWB-vx$7or}2WE5x?Gp9_~ z(52_yKC`5x!q@kukddTILpHQ8M$s3ey*<>zO}q6)2pR9{bqes)SI!kLQbwV6A{E@r zyc4YftLR-%ood}a3J?2__($yJkVEEwR}lXywUTXpRb*0}jh-UYQq&fsaQpI-p(1B+ z5r;FnCZLT>6QF`p?`k6d?z9F;1TQ3w#q=#*$|End4H6i0hCAXpiKJ<6aJ6tvx~z@f ze1x7k7lCu@_&6lX!D)yh6^m%dE7{||EG*9B8c=#j)M+8rti6h<5Rbt}t~rHKdKoH7 zGpJ_)F3N_YOW`)IM4tUh(2d^>?8r_hgyTiw8nFkqNw;vF$_07hA)898RG{n#)b%Pv z>-O5|q`MSqbpTtF4 z8G6mXha_4#CF~R2pwN2by#2OI_aNj*b+k{%lB(UKtNyrk$t1s$d6!qx4$@xljL#3d z1MOkQXY3xqXABvNtd`G%`r~Nsv~`8Z*$4Hn>WkkIA_`eKA>zk7Q?2rGaSHk>$Q=Y> z@!x8X!|2%vZy@u~Txf5lT3f_&920v~j*7u9APaHd`&=AS^;}an@VBTMXmiV59hDF< znguEeZtgYO=Tv11e|21{!U$=#4+ldj`#b9V^Bj?qjyHxg87n!0wS}LQU=f2>a9L_I zxbt<|Ehc`3BRp~OLK65&!EyDxt0R^9tOnGf0oWOh-9s8*7H>U_>PS7+b@7+T&Wn7j z%upD_Mq3%@7ct#7o_K;r+Fj}zLFaDFLKSyjSq>z->$WFp1VgsRjW88a+9;BOigmMD z9g!EE3MiQqoLJcC5zdADFCcHa<>DzY>UZ-j_qW%O<5c_U#cPUY8DA=yh0OE6B=4o0I_5>k-} zd^Zh+EvHzYliW{?fp~LdE-(d+uoc5VLBnu#zNSa0C_B?j_FlTG+&o1-f*~m6X9qRn za%W%JU;thJyw!_Ft*cQ4{}@XTiik^O*}$cPJfZNWy28mu#&MvGaWhOhu74sQDI+GE z?^?s<>c+F?_V=63*KpQy2=5m?4I0*ComA?8-yYX=n%7MOY*K+nJua-EJtfY~{Hxa) zEn4kR9ew+qwj+|CY%#G^odM@exD&xf1ma29LVTfOFYwrl*i)$FLeDQA&|WTO(6(SU z_62fajG-3t@*P-Mz zx}NOC;;i2yE5rq>Z*aT#>nh2O$NC_Cf(JVKkc;O zk}vmI>wwHVs5ibB4qry{^XX865Dv`Jd-tvobg}NLy-;L`E52ZcSdlHBN6&Xd5#jj6 z4KL9a5Xjpn5I{~llC8j^Ld9vPJL*@(7x$#odUsVj0ms%k^nC%K%8HL%#QwAdAXoS2 zNQI_CbT`b$5et7Y0H|O^Lglo%uQ0`FT+%M>n6vH7vOY^dy2n_jb4}R>JF0~@kuKj( zlv{mB)06kF?Sg0JgAnP0dnrSYPNpxTH;EBWGuxkv9NxIrV2<)J6)oVvIt9V}ETc~V z&9o%-v&>6zGedOG$0Irr>)Y@kLMHoUEL-+u7Td}TSOUk(__@ZMkLSXTyEVBPOD(ZhyqD)s4VF^t$aXkaQXv7c|F2nvs(StYh)nBWA zYkbxm-o=nVe1WtMphmu_yx?3UEP6X=;8erK|Y5)q^;D zh=L2$BH%{sIoWAebS5bBtTor9h7k6|cfsOBHf9kjwwb=0bs*fjlAD@B7b(9G;A%xM zbu%j8qMLfX9_jZe5cln$1-+FH(4yiJThH74ojIz4x`4=7cZQTZb}KY_Ch+4BwR*nw z-}!{t_B}8Ux#OjFft|9{nS>h()Ay^bCR4c}c=!3T;U{Y%4DFItn4s>7_{J_fz}UKw zORRg4`;ck_|3bilCo!WIfkOq-9*mZKPZzyqf|ogx93Y0x3)EF}K2bTZ@ydU1z_W1V z<=Q*{Ce(a{&%FahJc)#-?y^H)Stb?IenoNLK!_HqF6H_(XVygWtQAs~KN&XzpJm zWR}us9`-a|RPwp$lFF=*;6v}rzH~({lj8cx^s+DNU9CZ~%Ow ztZ0rxcTdV>bfm5;m=7|2G{X$2Y9IsTMN>JHvsz;6q6@`^8JO5s8jitfwT38}0bOtW zSv1$Jcj{4j2{mSF?Ao$F())^|p&%zMI#5}hwNTYuk}qhnPw9yG$8#S~mT^GxiSngx zT5rJyT0Af<12h6rfgwp0xkkLhZg6g}E=j7}PVb1x0$GBRW*WVRiU7Qo`5orXi1X@}05Zl=#V)O?K zYOEVEtp|4Br{++LU+8fOL55~`;gf-Uz0MI>aWhAw;3#kf#Xxm_HiDm=$~OMQBXkvY zO4Lx0AQWIy&M&bidJ+?~4}LCqN_2xar)3GoUn*&#Jkj`rL|&aAF((?0Z){p`Q5ldV zUshF{MZmOJ?L%Syf#5b3vf}0^tCp?;Z7T){$D`4bj9t$RCb19t2qIUZF?7{gU|X|^Tw+ibTSef^hv zVr$hqwMvsFk_m(PwFk4Gg(q-JYh~Fr++B9VviY}>zha%9)Mc|!tze$2M&=*$ zs!2}K9g8_^#A^mK!5xS?gJQDL_Nknq1fi)ybMOogDJKI9heP<0+YXttgCw7i%Qn}e z*SP*#2Q1sGT~NJ{rBX4nINTPx<$R@a*;4pJJq}EQ28vPV=p41U`_YkPbJAUpNdtB` zr(V4&hysR%AXz^$g9P|LD+GX{NI?lGS6LVchJ>-5;XScdfHr?alKCyzKEoRDK8WFk zhJ{!ezi$yQnN0YsGl04w;!UT#1r7~OGq|$=Ro@AiO=OJf$+%|mLubm%OP32A+CvqYd{T#jjO1c*C!R3w>h=RI7W{>gbD~>+_AhxgURS{De%YdvTAI zFZLF{U=wsFmo|lGKgCA=a-Oh!7!FCf4G#vl9Fp0}#%6OzCJvHmQ~MAC0->2V{)QAC z8Dz)NqPm?sX6B$XX~+EVnWJ%?h?v95ZLe(q-QE4fmqhMp5p zxEM?46abI$}GimZd#xH|yGt&I&4*nRPOz@##Vrl64b8ufYun8^Ip zX(be<8D$py{H+;qxY2hoY_yhiErT1L%!H~{L3AmK6j)Ch$9;PHk9bB}i zk`to%KE#M(-vh&11t#g}DRx5@KJjG+9Cr6As=wl^2D)ri_gyJBv+Zw=N*W6A5VuZxo|+{{G1L8r2K8u&;jiKM=OFkw-TR!&Zw7!orEX~pgI>em{` zNT}H*LItwcrx@ZI4KGLZ#x6VN!KF%Q^Jjd>t7jM2Qauor414O1Io|P>q9!Co{LU^u zA?>rJ_;?iZG*kydTWgvh99;1hsxf`DUdWIQ)a0?`REabuKvUcqkCy85*qS4p+l;1$ zFiaXSEjYv^VTw^StOpsIlU8qY#5J7?0;OD%E^~|Z1YJX$M$H!NQ%)%k#8#nzlaQ-y zU)J?5A>cs}^oMbNFS@^o<@|yI?NBlzdhF|;;-6A41{5DVuP&Iz?u}3m<3W9KG3t9n3_h64TeM||Rogh_Q(&hHczo6U?tcTfd9-y1WY5REvLNP=DM)cSEgWT>U_zi17 zSS>DQPSok4T%{0r09`v{o25si*c+)*v{t0|#cESD-Pw7QuGo5UypN81P@45v4ZbiB z3O3*YPpR3sFt@MKruNL^>-BTb=X~ag6^T2xvIz1bz~(PMT4@;B)U-=gyNgQQBc-BagPlES;lrw`JX8RS?F} z6$&LY1Wc(Ls$dB~n;}#}1uf@f@O{cLWjN?G`u)SeSo+FG+($i}9r5 z0<0Byf&3TP%2~IWl#EY7LR;`CJB5UMD8Ww*3l6DX?NU!F6od_M^eTx5e;T0frp^T>ahJ&%*?qp35xTD?T1^)r&|REqv)KNW9&l2v%>!+W=kEX zKDJp2?RUHS+2N|xIOM8A_a`^wDR`@ZgvAuzuQqQN5@1N~jh&R3Ugcj9!O?JDCAO!| zzpSQt&%4vhT!HbFUs*jMb#mWMI3b5FwV>?PHl_ZBUBtIy~t&V(u z7^djGN+**J&utG*49|SbFWf6aPwO%P6RaYQ`%9Uq+2{q53PE>j$}I638l4T`0EHVC zs#uDfYFsw(Q_U;hw=fIUM?K`XID&ZvO5g!7)B>Jc$Mh_QM1rrqGo#$hi9M8jGWcrB zJq!-Gl_!CG(~{yOBrOTC%b1ZMg-GnR>W+GfjR{0xa~RiNL9Ij}%!hp_5av=9z~uWr zbljup%l@F#e}`@;v}@6FXsT7S_M4G*43xQ)l(63xI|Cu}P37h5@82}nR~|oVzS??* zOu@_1n}-hqjtk(r*2>i&rb17Wl$i3Ls&>fBZ&P>w_)%W>j~{7&rbu#A%@OAcy};%A z*2_DtokK)Q<7dyV)561xPbOn%&s1X*$pg^uCERsPuLKQ~S$lR~LTlmtT4Z((&p!f- z>B5w;B*fabQ2P>c2qX&Tmm7#dPA8Y-pOh9k)o9|K0rd8GJPmH1wI1AWI_zn;#ht5R z58ZwgJD^NP8)HR{15MF0!>tLkcj*CMVEJ9!_|0F1&i6Jislybgae@CRoyIJI2QZNZ;H;_AA> z1Rmm-)Q*n^U|r{4uPp%FFd3l+2>i84Kplz7zl!7cd5Db;3Q4W(%Qa&xJx5E!O^!tO6cI zr`sv-0z z+r+=vP>w{3f{W4s+kyzbUDkg-W!hOpg6MD{;I4P#b`EWuS_Z@x{=N+6ZHeaep47+? zOZFBP-%oPs*^W?`PPPRc-cbv=G%Q-%rSQU@q0)D|-8mbR)gwbQi&VUDjU9HFO;rgU zc9eIEGKJ!+EJzi0C?8sK63NnOF+s{ginLpRyz(XNo{WQ3CP4hI>155gPp6D9(>O(P zeBrLt+ELW#jN6U)!$9c7Z3|xk*o%j)<^9&h+o;<3+100SAY}-S-%{NvBdKh0OntpDT?+GoV)Y`qc>kk2Z>H z$O%x%L|y#Bqzeudq$3b?1?=zygc3)1eephKIEwh1I&KW+3HTt4L=1>Y3yvajO4NRE zJkt_faXP$LZ;jma!AG0_4F<`4FTRPmIb|v|CK+`h33}TZ!Ys5S8FmDpXbm|S4&E|g zo$;4#CTs--(}x3XkOS)P;la=c!8(R@&C=E7=Ms zMZC32fUG0`Z$nc*y&w_a;K|#5>Knd*7Uk}PQYE(oK`F+>g?2-wCWwf5f?Qh;FW&+A zQ{IPxaF;ey-Qe~*4R5b395*}Tr#sK0IVl0kGm2ec+J^@BY&8Cr9$WY{h+c-%`7J)U0(lT>I3pIEMCu8th2p<@Y z??v;6gL&!6i3%#nhyf`_vX5K^O7`N*QQ`+HYRH6aNz70f>to0{<^C`63HarNZsk)V zN+H3$ExEl889cZA8&zQ?cyl+*ZyDU#|N3>Zh$wzb4bgZpxzc%@Xr8LINsUP@;?|}o z@b}GiUz%$liOs-@bQ(!>d00r^R8$*6#?bUu<$4%Ui4PKPC%H&uy(UZ=Uc;r)kZI;{ zYo`&q6UR#tZpg>F>)cu94yR*u6qLZjiA@}Lye&G!sZ)Vwx4k5DS0C_(`L{Ob`H74~ zDL7>vcqf}E<#Uy(%mCyCtVSDR_HfjIr>sje|m-kV{Dyk9joD(lQxEm-#=| zAX)=@xpQ}p0HvmQv;eEN5iB!AW<8q z5u@Oo#XNWs!=+I(=`pVFUhjoM;lo#dai&&mP0OaROj%Vow~GC3A@%-wj%a1vjC*JKr*)ODr!B~vUm*WRqHHeYYA zJzswlt!}+~y}q%wEh_LR3{8~muGilg8mDBwv@`#67jn z#{m(0VsO@=g1mHY$1zhu8(%t!3<(MKk8z7{CTaWQ0*490lTj z;fn&7Pc2r(7iuztMa#^;s#v2%-AzZ5`No0Bu=w&j4lmZW7J}u+H7H#VI<>eDX5ZH3 zAbpmme{F8;Hdj`gyDKmLwz56vp^#d@y)-=RYu_GuK+Z?a4Qm$IbWz*U=4Hk?_X!Ne zFt)*-3tp8KZjFHY9lGNF1RfNIUJ5w8@|Tj|aSu2~b;bMP?0nF0F^5Ww6@nCm7`9xn zAv;?46nU?^2-d}bxG-!?H)0}>C#r+N?%6*UM-4XQj&exB7(cEX6dfX^YZ4n>BX^YG z=IDyToq2B@H&VlUJAA*OOU7RBaaw6 zxC%Ml+1*}$EhWw>@@G{0o6E67H$b5)IO5(J_Z;Jr!YC#Cq&neSn&jq99v|8#0X0-1k zw<_>con??5mh(f_C0BhwtKX?tadbRD_O(u5t8M4%#w}li=S=fJ?_nuK7tE_eD-W|v zF4q3{Db{RV8KJta$NnHd#F$3tV}YS?${&zd91niF5*RI`|XZ(|@+k6-P?a%6}Puyu>mj3PaN zL7>HPZpJ>@Df9rrH_K(I91Q2v=Af_J9lq8K{elIF$FcydTi%cfk2Kj9#qJ=JRQSzu zc>^_yH`MiR(n#8!rs0wuP0!e1pPiMiUw030gF}GK&62VC5DBHpegeEmuP&7-d92Cw z$OY|U&bpedxd=r)MWu_AP6wT$h|gg!z}YPE%r>7yCxP=UH1*EvjiBTRaqdeLNcg~; z1^>oq$J`%&yt#G@Gd#SPsG8;Y19r($Uec@7Ljrrhvs~eSOY&!#>p;36{wPcSp>OF# zM~dW%Wkuh71IBD^>v^d$&wQpw$aOlZBUf59-zeD|S87LJMc-yR(XKO(6MfTIJULF>U#n6~f1{IDbrJWH)yJUDMxS{kZSJU6UKU!PGLTX=I)i=muzOidk`y3&7R+X zQu^RF0Esc-(U{meMCLQ&jeEvoWiUVB5lI}%p5ga+c!kRkfABzX`vI@=+#H|al~nk{ zTK393>hpX1`p+JW^ymxNV0C@UgbNSP)=Uwpj073T{-5Vj-SIF^aJz+C>!wJ;I~|jITL)|ZX$_4P*-GA z5liLupQ0Mw741->1+`h&zd!tL5rsZqA+kbf#=s)%73J?hM(mUSZNogi;C08bx&Ee-U~}di-1aetDr2PJ$cDnRI#x2T z5lBYJOD4G|rTDO@2HcynXL4Vc^?nB#$goS6i!J$FKg~2()|8x`>;*bgcFY*DsTd+i z%}sKZ0dPEPlHiO2{qw_wfsdfFaOc05AO!XCO#tFuQ81-8+HQ;HUA*(b3z}y;z zf1#4CKWLv1kk?)Gw|xZLfEN%#|4pxZ3I?Qp@-1@Bw_!J>Z@NK9c%A29Pdk?_7C~LG z@YKb{Zj|>O(w&aGr=7tO+}Dj+!SWOH@iXz;P$Da~BY_VQ%Cgfl51h1p*Tmg-et^6W zbgmbU=>+^MYPvv2dDOXxxg~M8k5CYVNqMQ1BJ5EmS4$Krv*wlsCg=$`H$>IS0#SOV zbA(ZY6=4G3u>9?COt|2<2$cpM#Etc9+_TFI_u#VX8 zPYNvthJ5Z7TG&|y%a2eLDDFL0j#}%Lg3)^GG~_S zPq0^?m+Mas^_jVTNEAg(t5eq-E1sBEz`JG``%J?;#y-(#B4h8!x^eKu=7n6|+36jp z=eGS9Q?cF9sY3AxGt(#Hyz}L+jQa8LPXGA3>L1;93$Jmi5lGUZ^9dEBIB!h63>!eBHQM%E$MdCaW1(^NpKA} zV`-d*(|bQVZ4$5;W|QFXr6}9wtG7LU;wZ??ciH6GdsKBoln3Y*n{KFCm`iLLWR_1f%CJ2 z%zKup(K}$IJ})aC4)mG1@Ed9dmAX#iv4go6vDZP9iJY|!=6v>wG?)pEpppMOKg2sf zMDGH5=ZC1I^v)0Q&JU65x_5987O&CIeu3tDb>8_Qeg#cKo)>J^BB`n<^LqchTt{-K z&&+pxQth9CXA)bISX>cfl4vvyYm%$-WBkLdd6v;TX0V@1`KKmKelV39kc(sE-!g)N zVlKcP34yLCQ4I}_e<|3>^wIPHJ~ z$Yp5KZ6|qSIly1T(&!bCA0mn_GB`hCmIv1*ntS4d6sU|%M@*1VG zn+SH`8AIRLXEG%Um{V6VNVAlLU4wnXTb0W-ca0>dSbhEa`NqnN9poi&e`*2|iG|1X z)JUljh~SNm+WqDUQ)DnT3)AqquYwMu+OwA{e_Lxl+jzdZ*?d`M3KK+tAp=@-QrYy~JqDzEQSh8=QmY;7EX6f^}U& z4w>k+7D1P%spTWI8CmIUgkvUf2{1IvqfYVtH5_ZWu@YANvCQgBfRYud*kt>FKs`&x zrDp4B2{6hGzbv0P^(0;&_Rjln`-6-AGU{x}@BW~9j0-_JRwnt zopHNw1iKO0>O%#67vGG=hur~Rx!~08-Hm6>7aLnoS2hrY>f&;dQ}5Y^KAo9KG_hz^ z9DIhPKHCVs&Hp;l#C@IL^gd^RY%bj+KXXKWqGZ@<>&hn{)CkE)X1KBPkH0s!wws$< zKTxV-@Fh;&DFZPDm;jMxE<}(rDrX|A9%4cd2RQId^d{xz@R=mkLiY7Bf=Ey67NjW= zx9LGRKV7)Mgv0Yuay7xE40f(vym}8k_iAD%0AbuN?j$i6fIz1*sVA9r&@$}H^@hQM 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 2.13 +AC_PREREQ(2.13) + +m4_define([lt_current], [0]) +m4_define([lt_revision], [12]) +m4_define([lt_age], [0]) + +AC_INIT([PortAudioCpp], [12]) +AC_CONFIG_SRCDIR([include/portaudiocpp/PortAudioCpp.hxx]) +AM_INIT_AUTOMAKE +AM_MAINTAINER_MODE + +###### Top-level directory of pacpp +###### This makes it easy to shuffle the build directories +###### Also edit AC_CONFIG_SRCDIR above (wouldn't accept this variable)! +PACPP_ROOT="\$(top_srcdir)" +PORTAUDIO_ROOT="../.." + +# Various other variables and flags +DEFAULT_INCLUDES="-I$PACPP_ROOT/include -I$PACPP_ROOT/$PORTAUDIO_ROOT/include" +CFLAGS=${CFLAGS-"-g -O2 -Wall -ansi -pedantic"} +CXXFLAGS=${CXXFLAGS-"${CFLAGS}"} + +LT_VERSION_INFO="lt_current:lt_revision:lt_age" + +# Checks for programs + +AC_PROG_CC +AC_PROG_CXX +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL + +# Transfer these variables to the Makefile +AC_SUBST(DEFAULT_INCLUDES) +AC_SUBST(PORTAUDIO_ROOT) +AC_SUBST(CXXFLAGS) +AC_SUBST(LT_VERSION_INFO) + +AC_CONFIG_FILES([ + Makefile + lib/Makefile + include/Makefile + bin/Makefile + doc/Makefile + portaudiocpp.pc + ]) +AC_OUTPUT diff --git a/bindings/cpp/doc/Makefile.am b/bindings/cpp/doc/Makefile.am new file mode 100644 index 0000000..7eb81ba --- /dev/null +++ b/bindings/cpp/doc/Makefile.am @@ -0,0 +1,5 @@ +PACPP_ROOT = . +#INCLUDES = -I$(srcdir)/$(PACPP_ROOT)/include -I$(top_srcdir)/include + +docs: + doxygen $(srcdir)/config.doxy.linux diff --git a/bindings/cpp/doc/Makefile.in b/bindings/cpp/doc/Makefile.in new file mode 100644 index 0000000..e9481ad --- /dev/null +++ b/bindings/cpp/doc/Makefile.in @@ -0,0 +1,326 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = doc +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +PACPP_ROOT = . +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-info-am + +#INCLUDES = -I$(srcdir)/$(PACPP_ROOT)/include -I$(top_srcdir)/include + +docs: + doxygen $(srcdir)/config.doxy.linux +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bindings/cpp/doc/README b/bindings/cpp/doc/README new file mode 100644 index 0000000..5e22972 --- /dev/null +++ b/bindings/cpp/doc/README @@ -0,0 +1,34 @@ +GNU/Linux: +---------- + +1) Download and install a recent version of Doxygen (preferably version 1.3.3 or +later). See http://www.doxygen.org/. +2) Download and install a recent version of GraphViz. See +http://www.research.att.com/sw/tools/graphviz/. +3) Run ``doxygen config.doxy.linux'' in this directory or load and generate the file +config.doxy.linux from the Doxywizard application. Or alternatively ``make docs'' can +be run from the build/gnu folder. + +The generated html documentation will be placed in /doc/api_reference/. To open +the main page of the documentation, open the file /doc/api_reference/index.html in +an html browser. + + +Windows: +-------- + +1) Download and install a recent Doxygen (preferably version 1.3.4 or later). See +http://www.doxygen.org/. +2) Download and install a recent version of GraphViz. See +http://www.research.att.com/sw/tools/graphviz/. +3) If needed, edit the config.doxy file in an ascii text editor so that +``DOT_PATH'' variable points to the folder where GraphViz is installed. +4) Run ``doxygen config.doxy'' in this directory or load and generate the file +config.doxy from the Doxywizard application. + +The generated html documentation will be placed in /doc/api_reference/. To open +the main page of the documentation, open the file /doc/api_reference/index.html in +an html browser. + + + diff --git a/bindings/cpp/doc/config.doxy b/bindings/cpp/doc/config.doxy new file mode 100644 index 0000000..0bfe9d3 --- /dev/null +++ b/bindings/cpp/doc/config.doxy @@ -0,0 +1,211 @@ +# Doxyfile 1.3.6 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = PortAudioCpp +PROJECT_NUMBER = 2.0 +OUTPUT_DIRECTORY = ./ +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +SHORT_NAMES = YES +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../source \ + ../include +FILE_PATTERNS = *.hxx \ + *.cxx +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 2 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = api_reference +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = YES +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = "c:/Program Files/ATT/Graphviz/bin/" +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/bindings/cpp/doc/config.doxy.linux b/bindings/cpp/doc/config.doxy.linux new file mode 100644 index 0000000..38079f6 --- /dev/null +++ b/bindings/cpp/doc/config.doxy.linux @@ -0,0 +1,210 @@ +# Doxyfile 1.3.3 + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = PortAudioCpp +PROJECT_NUMBER = 2.0 +OUTPUT_DIRECTORY = ./ +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +SHORT_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 4 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SHOW_USED_FILES = YES +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../source \ + ../include +FILE_PATTERNS = *.hxx \ + *.cxx +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 2 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = api_reference +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = YES +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = "/usr/bin/dot" +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = diff --git a/bindings/cpp/example/devs.cxx b/bindings/cpp/example/devs.cxx new file mode 100644 index 0000000..31a560f --- /dev/null +++ b/bindings/cpp/example/devs.cxx @@ -0,0 +1,177 @@ +#include +#include "portaudiocpp/PortAudioCpp.hxx" + +#ifdef WIN32 +#include "portaudiocpp/AsioDeviceAdapter.hxx" +#endif + +// --------------------------------------------------------------------------------------- + +void printSupportedStandardSampleRates( + const portaudio::DirectionSpecificStreamParameters &inputParameters, + const portaudio::DirectionSpecificStreamParameters &outputParameters) +{ + static double STANDARD_SAMPLE_RATES[] = { + 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, + 44100.0, 48000.0, 88200.0, 96000.0, -1 }; // negative terminated list + + int printCount = 0; + + for (int i = 0; STANDARD_SAMPLE_RATES[i] > 0; ++i) + { + portaudio::StreamParameters tmp = portaudio::StreamParameters(inputParameters, outputParameters, STANDARD_SAMPLE_RATES[i], 0, paNoFlag); + + if (tmp.isSupported()) + { + if (printCount == 0) + { + std::cout << " " << STANDARD_SAMPLE_RATES[i]; // 8.2 + printCount = 1; + } + else if (printCount == 4) + { + std::cout << "," << std::endl; + std::cout << " " << STANDARD_SAMPLE_RATES[i]; // 8.2 + printCount = 1; + } + else + { + std::cout << ", " << STANDARD_SAMPLE_RATES[i]; // 8.2 + ++printCount; + } + } + } + + if (printCount == 0) + std::cout << "None" << std::endl; + else + std::cout << std::endl; +} + +// --------------------------------------------------------------------------------------- + +int main(int, char*[]); +int main(int, char*[]) +{ + try + { + portaudio::AutoSystem autoSys; + + portaudio::System &sys = portaudio::System::instance(); + + std::cout << "PortAudio version number = " << sys.version() << std::endl; + std::cout << "PortAudio version text = '" << sys.versionText() << "'" << std::endl; + + int numDevices = sys.deviceCount(); + std::cout << "Number of devices = " << numDevices << std::endl; + + for (portaudio::System::DeviceIterator i = sys.devicesBegin(); i != sys.devicesEnd(); ++i) + { + std::cout << "--------------------------------------- device #" << (*i).index() << std::endl; + + // Mark global and API specific default devices: + bool defaultDisplayed = false; + + if ((*i).isSystemDefaultInputDevice()) + { + std::cout << "[ Default Input"; + defaultDisplayed = true; + } + else if ((*i).isHostApiDefaultInputDevice()) + { + std::cout << "[ Default " << (*i).hostApi().name() << " Input"; + defaultDisplayed = true; + } + + if ((*i).isSystemDefaultOutputDevice()) + { + std::cout << (defaultDisplayed ? "," : "["); + std::cout << " Default Output"; + defaultDisplayed = true; + } + else if ((*i).isHostApiDefaultOutputDevice()) + { + std::cout << (defaultDisplayed ? "," : "["); + std::cout << " Default " << (*i).hostApi().name() << " Output"; + defaultDisplayed = true; + } + + if (defaultDisplayed) + std::cout << " ]" << std::endl; + + // Print device info: + std::cout << "Name = " << (*i).name() << std::endl; + std::cout << "Host API = " << (*i).hostApi().name() << std::endl; + std::cout << "Max inputs = " << (*i).maxInputChannels() << ", Max outputs = " << (*i).maxOutputChannels() << std::endl; + + std::cout << "Default low input latency = " << (*i).defaultLowInputLatency() << std::endl; // 8.3 + std::cout << "Default low output latency = " << (*i).defaultLowOutputLatency() << std::endl; // 8.3 + std::cout << "Default high input latency = " << (*i).defaultHighInputLatency() << std::endl; // 8.3 + std::cout << "Default high output latency = " << (*i).defaultHighOutputLatency() << std::endl; // 8.3 + +#ifdef WIN32 + // ASIO specific latency information: + if ((*i).hostApi().typeId() == paASIO) + { + portaudio::AsioDeviceAdapter asioDevice((*i)); + + std::cout << "ASIO minimum buffer size = " << asioDevice.minBufferSize() << std::endl; + std::cout << "ASIO maximum buffer size = " << asioDevice.maxBufferSize() << std::endl; + std::cout << "ASIO preferred buffer size = " << asioDevice.preferredBufferSize() << std::endl; + + if (asioDevice.granularity() == -1) + std::cout << "ASIO buffer granularity = power of 2" << std::endl; + else + std::cout << "ASIO buffer granularity = " << asioDevice.granularity() << std::endl; + } +#endif // WIN32 + + std::cout << "Default sample rate = " << (*i).defaultSampleRate() << std::endl; // 8.2 + + // Poll for standard sample rates: + portaudio::DirectionSpecificStreamParameters inputParameters((*i), (*i).maxInputChannels(), portaudio::INT16, true, 0.0, NULL); + portaudio::DirectionSpecificStreamParameters outputParameters((*i), (*i).maxOutputChannels(), portaudio::INT16, true, 0.0, NULL); + + if (inputParameters.numChannels() > 0) + { + std::cout << "Supported standard sample rates" << std::endl; + std::cout << " for half-duplex 16 bit " << inputParameters.numChannels() << " channel input = " << std::endl; + printSupportedStandardSampleRates(inputParameters, portaudio::DirectionSpecificStreamParameters::null()); + } + + if (outputParameters.numChannels() > 0) + { + std::cout << "Supported standard sample rates" << std::endl; + std::cout << " for half-duplex 16 bit " << outputParameters.numChannels() << " channel output = " << std::endl; + printSupportedStandardSampleRates(portaudio::DirectionSpecificStreamParameters::null(), outputParameters); + } + + if (inputParameters.numChannels() > 0 && outputParameters.numChannels() > 0) + { + std::cout << "Supported standard sample rates" << std::endl; + std::cout << " for full-duplex 16 bit " << inputParameters.numChannels() << " channel input, " << outputParameters.numChannels() << " channel output = " << std::endl; + printSupportedStandardSampleRates(inputParameters, outputParameters); + } + } + + std::cout << "----------------------------------------------" << std::endl; + } + catch (const portaudio::PaException &e) + { + std::cout << "A PortAudio error occured: " << e.paErrorText() << std::endl; + } + catch (const portaudio::PaCppException &e) + { + std::cout << "A PortAudioCpp error occured: " << e.what() << std::endl; + } + catch (const std::exception &e) + { + std::cout << "A generic exception occured: " << e.what() << std::endl; + } + catch (...) + { + std::cout << "An unknown exception occured." << std::endl; + } + + return 0; +} diff --git a/bindings/cpp/example/sine.cxx b/bindings/cpp/example/sine.cxx new file mode 100644 index 0000000..577a247 --- /dev/null +++ b/bindings/cpp/example/sine.cxx @@ -0,0 +1,137 @@ +// --------------------------------------------------------------------------------------- + +#include +#include +#include +#include +#include "portaudiocpp/PortAudioCpp.hxx" + +// --------------------------------------------------------------------------------------- + +// Some constants: +const int NUM_SECONDS = 5; +const double SAMPLE_RATE = 44100.0; +const int FRAMES_PER_BUFFER = 64; +const int TABLE_SIZE = 200; + +// --------------------------------------------------------------------------------------- + +// SineGenerator class: +class SineGenerator +{ +public: + SineGenerator(int tableSize) : tableSize_(tableSize), leftPhase_(0), rightPhase_(0) + { + const double PI = 3.14159265; + table_ = new float[tableSize]; + for (int i = 0; i < tableSize; ++i) + { + table_[i] = 0.125f * (float)sin(((double)i/(double)tableSize)*PI*2.); + } + } + + ~SineGenerator() + { + delete[] table_; + } + + int generate(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) + { + assert(outputBuffer != NULL); + + float **out = static_cast(outputBuffer); + + for (unsigned int i = 0; i < framesPerBuffer; ++i) + { + out[0][i] = table_[leftPhase_]; + out[1][i] = table_[rightPhase_]; + + leftPhase_ += 1; + if (leftPhase_ >= tableSize_) + leftPhase_ -= tableSize_; + + rightPhase_ += 3; + if (rightPhase_ >= tableSize_) + rightPhase_ -= tableSize_; + } + + return paContinue; + } + +private: + float *table_; + int tableSize_; + int leftPhase_; + int rightPhase_; +}; + +// --------------------------------------------------------------------------------------- + +// main: +int main(int, char *[]); +int main(int, char *[]) +{ + try + { + // Create a SineGenerator object: + SineGenerator sineGenerator(TABLE_SIZE); + + std::cout << "Setting up PortAudio..." << std::endl; + + // Set up the System: + portaudio::AutoSystem autoSys; + portaudio::System &sys = portaudio::System::instance(); + + // Set up the parameters required to open a (Callback)Stream: + portaudio::DirectionSpecificStreamParameters outParams(sys.defaultOutputDevice(), 2, portaudio::FLOAT32, false, sys.defaultOutputDevice().defaultLowOutputLatency(), NULL); + portaudio::StreamParameters params(portaudio::DirectionSpecificStreamParameters::null(), outParams, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff); + + std::cout << "Opening stereo output stream..." << std::endl; + + // Create (and open) a new Stream, using the SineGenerator::generate function as a callback: + portaudio::MemFunCallbackStream stream(params, sineGenerator, &SineGenerator::generate); + + std::cout << "Starting playback for " << NUM_SECONDS << " seconds." << std::endl; + + // Start the Stream (audio playback starts): + stream.start(); + + // Wait for 5 seconds: + sys.sleep(NUM_SECONDS * 1000); + + std::cout << "Closing stream..." < + +#include "portaudio.h" + +#include "portaudiocpp/SampleDataFormat.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class System; + class HostApi; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + ////// + /// @brief Class which represents a PortAudio device in the System. + /// + /// A single physical device in the system may have multiple PortAudio + /// Device representations using different HostApi 's though. A Device + /// can be half-duplex or full-duplex. A half-duplex Device can be used + /// to create a half-duplex Stream. A full-duplex Device can be used to + /// create a full-duplex Stream. If supported by the HostApi, two + /// half-duplex Devices can even be used to create a full-duplex Stream. + /// + /// Note that Device objects are very light-weight and can be passed around + /// by-value. + ////// + class Device + { + public: + // query info: name, max in channels, max out channels, + // default low/hight input/output latency, default sample rate + PaDeviceIndex index() const; + const char *name() const; + int maxInputChannels() const; + int maxOutputChannels() const; + PaTime defaultLowInputLatency() const; + PaTime defaultHighInputLatency() const; + PaTime defaultLowOutputLatency() const; + PaTime defaultHighOutputLatency() const; + double defaultSampleRate() const; + + bool isInputOnlyDevice() const; // extended + bool isOutputOnlyDevice() const; // extended + bool isFullDuplexDevice() const; // extended + bool isSystemDefaultInputDevice() const; // extended + bool isSystemDefaultOutputDevice() const; // extended + bool isHostApiDefaultInputDevice() const; // extended + bool isHostApiDefaultOutputDevice() const; // extended + + bool operator==(const Device &rhs); + bool operator!=(const Device &rhs); + + // host api reference + HostApi &hostApi(); + const HostApi &hostApi() const; + + private: + PaDeviceIndex index_; + const PaDeviceInfo *info_; + + private: + friend class System; + + explicit Device(PaDeviceIndex index); + ~Device(); + + Device(const Device &); // non-copyable + Device &operator=(const Device &); // non-copyable + }; + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_DEVICE_HXX + diff --git a/bindings/cpp/include/portaudiocpp/DirectionSpecificStreamParameters.hxx b/bindings/cpp/include/portaudiocpp/DirectionSpecificStreamParameters.hxx new file mode 100644 index 0000000..dd5ae0b --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/DirectionSpecificStreamParameters.hxx @@ -0,0 +1,77 @@ +#ifndef INCLUDED_PORTAUDIO_SINGLEDIRECTIONSTREAMPARAMETERS_HXX +#define INCLUDED_PORTAUDIO_SINGLEDIRECTIONSTREAMPARAMETERS_HXX + +// --------------------------------------------------------------------------------------- + +#include + +#include "portaudio.h" + +#include "portaudiocpp/System.hxx" +#include "portaudiocpp/SampleDataFormat.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class Device; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + ////// + /// @brief All parameters for one direction (either in or out) of a Stream. Together with + /// parameters common to both directions, two DirectionSpecificStreamParameters can make up + /// a StreamParameters object which contains all parameters for a Stream. + ////// + class DirectionSpecificStreamParameters + { + public: + static DirectionSpecificStreamParameters null(); + + DirectionSpecificStreamParameters(); + DirectionSpecificStreamParameters(const Device &device, int numChannels, SampleDataFormat format, + bool interleaved, PaTime suggestedLatency, void *hostApiSpecificStreamInfo); + + // Set up methods: + void setDevice(const Device &device); + void setNumChannels(int numChannels); + + void setSampleFormat(SampleDataFormat format, bool interleaved = true); + void setHostApiSpecificSampleFormat(PaSampleFormat format, bool interleaved = true); + + void setSuggestedLatency(PaTime latency); + + void setHostApiSpecificStreamInfo(void *streamInfo); + + // Accessor methods: + PaStreamParameters *paStreamParameters(); + const PaStreamParameters *paStreamParameters() const; + + Device &device() const; + int numChannels() const; + + SampleDataFormat sampleFormat() const; + bool isSampleFormatInterleaved() const; + bool isSampleFormatHostApiSpecific() const; + PaSampleFormat hostApiSpecificSampleFormat() const; + + PaTime suggestedLatency() const; + + void *hostApiSpecificStreamInfo() const; + + private: + PaStreamParameters paStreamParameters_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_SINGLEDIRECTIONSTREAMPARAMETERS_HXX diff --git a/bindings/cpp/include/portaudiocpp/Exception.hxx b/bindings/cpp/include/portaudiocpp/Exception.hxx new file mode 100644 index 0000000..a70c2f1 --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/Exception.hxx @@ -0,0 +1,108 @@ +#ifndef INCLUDED_PORTAUDIO_EXCEPTION_HXX +#define INCLUDED_PORTAUDIO_EXCEPTION_HXX + +// --------------------------------------------------------------------------------------- + +#include + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + + ////// + /// @brief Base class for all exceptions PortAudioCpp can throw. + /// + /// Class is derived from std::exception. + ////// + class Exception : public std::exception + { + public: + virtual ~Exception() throw() {} + + virtual const char *what() const throw() = 0; + }; + + // ----------------------------------------------------------------------------------- + + ////// + /// @brief Wrapper for PortAudio error codes to C++ exceptions. + /// + /// It wraps up PortAudio's error handling mechanism using + /// C++ exceptions and is derived from std::exception for + /// easy exception handling and to ease integration with + /// other code. + /// + /// To know what exceptions each function may throw, look up + /// the errors that can occure in the PortAudio documentation + /// for the equivalent functions. + /// + /// Some functions are likely to throw an exception (such as + /// Stream::open(), etc) and these should always be called in + /// try{} catch{} blocks and the thrown exceptions should be + /// handled properly (ie. the application shouldn't just abort, + /// but merely display a warning dialog to the user or something). + /// However nearly all functions in PortAudioCpp are capable + /// of throwing exceptions. When a function like Stream::isStopped() + /// throws an exception, it's such an exceptional state that it's + /// not likely that it can be recovered. PaExceptions such as these + /// can ``safely'' be left to be handled by some outer catch-all-like + /// mechanism for unrecoverable errors. + ////// + class PaException : public Exception + { + public: + explicit PaException(PaError error); + + const char *what() const throw(); + + PaError paError() const; + const char *paErrorText() const; + + bool isHostApiError() const; // extended + long lastHostApiError() const; + const char *lastHostApiErrorText() const; + + bool operator==(const PaException &rhs) const; + bool operator!=(const PaException &rhs) const; + + private: + PaError error_; + }; + + // ----------------------------------------------------------------------------------- + + ////// + /// @brief Exceptions specific to PortAudioCpp (ie. exceptions which do not have an + /// equivalent PortAudio error code). + ////// + class PaCppException : public Exception + { + public: + enum ExceptionSpecifier + { + UNABLE_TO_ADAPT_DEVICE + }; + + PaCppException(ExceptionSpecifier specifier); + + const char *what() const throw(); + + ExceptionSpecifier specifier() const; + + bool operator==(const PaCppException &rhs) const; + bool operator!=(const PaCppException &rhs) const; + + private: + ExceptionSpecifier specifier_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_EXCEPTION_HXX + diff --git a/bindings/cpp/include/portaudiocpp/HostApi.hxx b/bindings/cpp/include/portaudiocpp/HostApi.hxx new file mode 100644 index 0000000..899fc42 --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/HostApi.hxx @@ -0,0 +1,76 @@ +#ifndef INCLUDED_PORTAUDIO_HOSTAPI_HXX +#define INCLUDED_PORTAUDIO_HOSTAPI_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/System.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class Device; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief HostApi represents a host API (usually type of driver) in the System. + /// + /// A single System can support multiple HostApi's each one typically having + /// a set of Devices using that HostApi (usually driver type). All Devices in + /// the HostApi can be enumerated and the default input/output Device for this + /// HostApi can be retreived. + ////// + class HostApi + { + public: + typedef System::DeviceIterator DeviceIterator; + + // query info: id, name, numDevices + PaHostApiTypeId typeId() const; + PaHostApiIndex index() const; + const char *name() const; + int deviceCount() const; + + // iterate devices + DeviceIterator devicesBegin(); + DeviceIterator devicesEnd(); + + // default devices + Device &defaultInputDevice() const; + Device &defaultOutputDevice() const; + + // comparison operators + bool operator==(const HostApi &rhs) const; + bool operator!=(const HostApi &rhs) const; + + private: + const PaHostApiInfo *info_; + Device **devices_; + + private: + friend class System; + + explicit HostApi(PaHostApiIndex index); + ~HostApi(); + + HostApi(const HostApi &); // non-copyable + HostApi &operator=(const HostApi &); // non-copyable + }; + + +} + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_HOSTAPI_HXX + diff --git a/bindings/cpp/include/portaudiocpp/InterfaceCallbackStream.hxx b/bindings/cpp/include/portaudiocpp/InterfaceCallbackStream.hxx new file mode 100644 index 0000000..e496dd2 --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/InterfaceCallbackStream.hxx @@ -0,0 +1,49 @@ +#ifndef INCLUDED_PORTAUDIO_INTERFACECALLBACKSTREAM_HXX +#define INCLUDED_PORTAUDIO_INTERFACECALLBACKSTREAM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/CallbackStream.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s) +namespace portaudio +{ + class StreamParameters; + class CallbackInterface; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief Callback stream using an instance of an object that's derived from the CallbackInterface + /// interface. + ////// + class InterfaceCallbackStream : public CallbackStream + { + public: + InterfaceCallbackStream(); + InterfaceCallbackStream(const StreamParameters ¶meters, CallbackInterface &instance); + ~InterfaceCallbackStream(); + + void open(const StreamParameters ¶meters, CallbackInterface &instance); + + private: + InterfaceCallbackStream(const InterfaceCallbackStream &); // non-copyable + InterfaceCallbackStream &operator=(const InterfaceCallbackStream &); // non-copyable + }; + + +} // portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_INTERFACECALLBACKSTREAM_HXX diff --git a/bindings/cpp/include/portaudiocpp/MemFunCallbackStream.hxx b/bindings/cpp/include/portaudiocpp/MemFunCallbackStream.hxx new file mode 100644 index 0000000..a9e50ca --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/MemFunCallbackStream.hxx @@ -0,0 +1,107 @@ +#ifndef INCLUDED_PORTAUDIO_MEMFUNCALLBACKSTREAM_HXX +#define INCLUDED_PORTAUDIO_MEMFUNCALLBACKSTREAM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/CallbackStream.hxx" +#include "portaudiocpp/CallbackInterface.hxx" +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/InterfaceCallbackStream.hxx" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + + + ////// + /// @brief Callback stream using a class's member function as a callback. Template argument T is the type of the + /// class of which a member function is going to be used. + /// + /// Example usage: + /// @verbatim MemFunCallback stream = MemFunCallbackStream(parameters, *this, &MyClass::myCallbackFunction); @endverbatim + ////// + template + class MemFunCallbackStream : public CallbackStream + { + public: + typedef int (T::*CallbackFunPtr)(const void *, void *, unsigned long, const PaStreamCallbackTimeInfo *, + PaStreamCallbackFlags); + + // ------------------------------------------------------------------------------- + + MemFunCallbackStream() + { + } + + MemFunCallbackStream(const StreamParameters ¶meters, T &instance, CallbackFunPtr memFun) : adapter_(instance, memFun) + { + open(parameters); + } + + ~MemFunCallbackStream() + { + close(); + } + + void open(const StreamParameters ¶meters, T &instance, CallbackFunPtr memFun) + { + // XXX: need to check if already open? + + adapter_.init(instance, memFun); + open(parameters); + } + + private: + MemFunCallbackStream(const MemFunCallbackStream &); // non-copyable + MemFunCallbackStream &operator=(const MemFunCallbackStream &); // non-copyable + + ////// + /// @brief Inner class which adapts a member function callback to a CallbackInterface compliant + /// class (so it can be adapted using the paCallbackAdapter function). + ////// + class MemFunToCallbackInterfaceAdapter : public CallbackInterface + { + public: + MemFunToCallbackInterfaceAdapter() {} + MemFunToCallbackInterfaceAdapter(T &instance, CallbackFunPtr memFun) : instance_(&instance), memFun_(memFun) {} + + void init(T &instance, CallbackFunPtr memFun) + { + instance_ = &instance; + memFun_ = memFun; + } + + int paCallbackFun(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) + { + return (instance_->*memFun_)(inputBuffer, outputBuffer, numFrames, timeInfo, statusFlags); + } + + private: + T *instance_; + CallbackFunPtr memFun_; + }; + + MemFunToCallbackInterfaceAdapter adapter_; + + void open(const StreamParameters ¶meters) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), &impl::callbackInterfaceToPaCallbackAdapter, + static_cast(&adapter_)); + + if (err != paNoError) + throw PaException(err); + } + }; + + +} // portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_MEMFUNCALLBACKSTREAM_HXX diff --git a/bindings/cpp/include/portaudiocpp/PortAudioCpp.hxx b/bindings/cpp/include/portaudiocpp/PortAudioCpp.hxx new file mode 100644 index 0000000..f11e7fb --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/PortAudioCpp.hxx @@ -0,0 +1,109 @@ +#ifndef INCLUDED_PORTAUDIO_PORTAUDIOCPP_HXX +#define INCLUDED_PORTAUDIO_PORTAUDIOCPP_HXX + +// --------------------------------------------------------------------------------------- + +////// +/// @mainpage PortAudioCpp +/// +///

    PortAudioCpp - A Native C++ Binding of PortAudio V19

    +///

    PortAudio

    +///

    +/// PortAudio is a portable and mature C API for accessing audio hardware. It offers both callback-based and blocking +/// style input and output, deals with sample data format conversions, dithering and much more. There are a large number +/// of implementations available for various platforms including Windows MME, Windows DirectX, Windows and MacOS (Classic) +/// ASIO, MacOS Classic SoundManager, MacOS X CoreAudio, OSS (Linux), Linux ALSA, JACK (MacOS X and Linux) and SGI Irix +/// AL. Note that, currently not all of these implementations are equally complete or up-to-date (as PortAudio V19 is +/// still in development). Because PortAudio has a C API, it can easily be called from a variety of other programming +/// languages. +///

    +///

    PortAudioCpp

    +///

    +/// Although, it is possible to use PortAudio's C API from within a C++ program, this is usually a little awkward +/// as procedural and object-oriented paradigms need to be mixed. PortAudioCpp aims to resolve this by encapsulating +/// PortAudio's C API to form an equivalent object-oriented C++ API. It provides a more natural integration of PortAudio +/// into C++ programs as well as a more structured interface. PortAudio's concepts were preserved as much as possible and +/// no additional features were added except for some `convenience methods'. +///

    +///

    +/// PortAudioCpp's main features are: +///

      +///
    • Structured object model.
    • +///
    • C++ exception handling instead of C-style error return codes.
    • +///
    • Handling of callbacks using free functions (C and C++), static functions, member functions or instances of classes +/// derived from a given interface.
    • +///
    • STL compliant iterators to host APIs and devices.
    • +///
    • Some additional convenience functions to more easily set up and use PortAudio.
    • +///
    +///

    +///

    +/// PortAudioCpp requires a recent version of the PortAudio V19 source code. This can be obtained from CVS or as a snapshot +/// from the website. The examples also require the ASIO 2 SDK which can be obtained from the Steinberg website. Alternatively, the +/// examples can easily be modified to compile without needing ASIO. +///

    +///

    +/// Supported platforms: +///

      +///
    • Microsoft Visual C++ 6.0, 7.0 (.NET 2002) and 7.1 (.NET 2003).
    • +///
    • GNU G++ 2.95 and G++ 3.3.
    • +///
    +/// Other platforms should be easily supported as PortAudioCpp is platform-independent and (reasonably) C++ standard compliant. +///

    +///

    +/// This documentation mainly provides information specific to PortAudioCpp. For a more complete explaination of all of the +/// concepts used, please consult the PortAudio documentation. +///

    +///

    +/// PortAudioCpp was developed by Merlijn Blaauw with many great suggestions and help from Ross Bencina. Ludwig Schwardt provided +/// GNU/Linux build files and checked G++ compatibility. PortAudioCpp may be used under the same licensing, conditions and +/// warranty as PortAudio. See the PortAudio license for more details. +///

    +///

    Links

    +///

    +/// Official PortAudio site.
    +///

    +////// + +// --------------------------------------------------------------------------------------- + +////// +/// @namespace portaudio +/// +/// To avoid name collision, everything in PortAudioCpp is in the portaudio +/// namespace. If this name is too long it's usually pretty safe to use an +/// alias like ``namespace pa = portaudio;''. +////// + +// --------------------------------------------------------------------------------------- + +////// +/// @file PortAudioCpp.hxx +/// An include-all header file (for lazy programmers and using pre-compiled headers). +////// + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/AutoSystem.hxx" +#include "portaudiocpp/BlockingStream.hxx" +#include "portaudiocpp/CallbackInterface.hxx" +#include "portaudiocpp/CallbackStream.hxx" +#include "portaudiocpp/CFunCallbackStream.hxx" +#include "portaudiocpp/CppFunCallbackStream.hxx" +#include "portaudiocpp/Device.hxx" +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/HostApi.hxx" +#include "portaudiocpp/InterfaceCallbackStream.hxx" +#include "portaudiocpp/MemFunCallbackStream.hxx" +#include "portaudiocpp/SampleDataFormat.hxx" +#include "portaudiocpp/DirectionSpecificStreamParameters.hxx" +#include "portaudiocpp/Stream.hxx" +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/System.hxx" +#include "portaudiocpp/SystemDeviceIterator.hxx" +#include "portaudiocpp/SystemHostApiIterator.hxx" + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_PORTAUDIOCPP_HXX diff --git a/bindings/cpp/include/portaudiocpp/SampleDataFormat.hxx b/bindings/cpp/include/portaudiocpp/SampleDataFormat.hxx new file mode 100644 index 0000000..a7e25b2 --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/SampleDataFormat.hxx @@ -0,0 +1,35 @@ +#ifndef INCLUDED_PORTAUDIO_SAMPLEDATAFORMAT_HXX +#define INCLUDED_PORTAUDIO_SAMPLEDATAFORMAT_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + + + ////// + /// @brief PortAudio sample data formats. + /// + /// Small helper enum to wrap the PortAudio defines. + ////// + enum SampleDataFormat + { + INVALID_FORMAT = 0, + FLOAT32 = paFloat32, + INT32 = paInt32, + INT24 = paInt24, + INT16 = paInt16, + INT8 = paInt8, + UINT8 = paUInt8 + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_SAMPLEDATAFORMAT_HXX diff --git a/bindings/cpp/include/portaudiocpp/Stream.hxx b/bindings/cpp/include/portaudiocpp/Stream.hxx new file mode 100644 index 0000000..8a255ec --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/Stream.hxx @@ -0,0 +1,82 @@ +#ifndef INCLUDED_PORTAUDIO_STREAM_HXX +#define INCLUDED_PORTAUDIO_STREAM_HXX + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class StreamParameters; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief A Stream represents an active or inactive input and/or output data + /// stream in the System. + /// + /// Concrete Stream classes should ensure themselves being in a closed state at + /// destruction (i.e. by calling their own close() method in their deconstructor). + /// Following good C++ programming practices, care must be taken to ensure no + /// exceptions are thrown by the deconstructor of these classes. As a consequence, + /// clients need to explicitly call close() to ensure the stream closed successfully. + /// + /// The Stream object can be used to manipulate the Stream's state. Also, time-constant + /// and time-varying information about the Stream can be retreived. + ////// + class Stream + { + public: + // Opening/closing: + virtual ~Stream(); + + virtual void close(); + bool isOpen() const; + + // Additional set up: + void setStreamFinishedCallback(PaStreamFinishedCallback *callback); + + // State management: + void start(); + void stop(); + void abort(); + + bool isStopped() const; + bool isActive() const; + + // Stream info (time-constant, but might become time-variant soon): + PaTime inputLatency() const; + PaTime outputLatency() const; + double sampleRate() const; + + // Stream info (time-varying): + PaTime time() const; + + // Accessors for PortAudio PaStream, useful for interfacing + // with PortAudio add-ons (such as PortMixer) for instance: + const PaStream *paStream() const; + PaStream *paStream(); + + protected: + Stream(); // abstract class + + PaStream *stream_; + + private: + Stream(const Stream &); // non-copyable + Stream &operator=(const Stream &); // non-copyable + }; + + +} // namespace portaudio + + +#endif // INCLUDED_PORTAUDIO_STREAM_HXX + diff --git a/bindings/cpp/include/portaudiocpp/StreamParameters.hxx b/bindings/cpp/include/portaudiocpp/StreamParameters.hxx new file mode 100644 index 0000000..2b6aa2e --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/StreamParameters.hxx @@ -0,0 +1,77 @@ +#ifndef INCLUDED_PORTAUDIO_STREAMPARAMETERS_HXX +#define INCLUDED_PORTAUDIO_STREAMPARAMETERS_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/DirectionSpecificStreamParameters.hxx" + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + ////// + /// @brief The entire set of parameters needed to configure and open + /// a Stream. + /// + /// It contains parameters of input, output and shared parameters. + /// Using the isSupported() method, the StreamParameters can be + /// checked if opening a Stream using this StreamParameters would + /// succeed or not. Accessors are provided to higher-level parameters + /// aswell as the lower-level parameters which are mainly intended for + /// internal use. + ////// + class StreamParameters + { + public: + StreamParameters(); + StreamParameters(const DirectionSpecificStreamParameters &inputParameters, + const DirectionSpecificStreamParameters &outputParameters, double sampleRate, + unsigned long framesPerBuffer, PaStreamFlags flags); + + // Set up for direction-specific: + void setInputParameters(const DirectionSpecificStreamParameters ¶meters); + void setOutputParameters(const DirectionSpecificStreamParameters ¶meters); + + // Set up for common parameters: + void setSampleRate(double sampleRate); + void setFramesPerBuffer(unsigned long framesPerBuffer); + void setFlag(PaStreamFlags flag); + void unsetFlag(PaStreamFlags flag); + void clearFlags(); + + // Validation: + bool isSupported() const; + + // Accessors (direction-specific): + DirectionSpecificStreamParameters &inputParameters(); + const DirectionSpecificStreamParameters &inputParameters() const; + DirectionSpecificStreamParameters &outputParameters(); + const DirectionSpecificStreamParameters &outputParameters() const; + + // Accessors (common): + double sampleRate() const; + unsigned long framesPerBuffer() const; + PaStreamFlags flags() const; + bool isFlagSet(PaStreamFlags flag) const; + + private: + // Half-duplex specific parameters: + DirectionSpecificStreamParameters inputParameters_; + DirectionSpecificStreamParameters outputParameters_; + + // Common parameters: + double sampleRate_; + unsigned long framesPerBuffer_; + PaStreamFlags flags_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_STREAMPARAMETERS_HXX diff --git a/bindings/cpp/include/portaudiocpp/System.hxx b/bindings/cpp/include/portaudiocpp/System.hxx new file mode 100644 index 0000000..f5fb713 --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/System.hxx @@ -0,0 +1,107 @@ +#ifndef INCLUDED_PORTAUDIO_SYSTEM_HXX +#define INCLUDED_PORTAUDIO_SYSTEM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class Device; + class Stream; + class HostApi; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief System singleton which represents the PortAudio system. + /// + /// The System is used to initialize/terminate PortAudio and provide + /// a single acccess point to the PortAudio System (instance()). + /// It can be used to iterate through all HostApi 's in the System as + /// well as all devices in the System. It also provides some utility + /// functionality of PortAudio. + /// + /// Terminating the System will also abort and close the open streams. + /// The Stream objects will need to be deallocated by the client though + /// (it's usually a good idea to have them cleaned up automatically). + ////// + class System + { + public: + class HostApiIterator; // forward declaration + class DeviceIterator; // forward declaration + + // ------------------------------------------------------------------------------- + + static int version(); + static const char *versionText(); + + static void initialize(); + static void terminate(); + + static System &instance(); + static bool exists(); + + // ------------------------------------------------------------------------------- + + // host apis: + HostApiIterator hostApisBegin(); + HostApiIterator hostApisEnd(); + + HostApi &defaultHostApi(); + + HostApi &hostApiByTypeId(PaHostApiTypeId type); + HostApi &hostApiByIndex(PaHostApiIndex index); + + int hostApiCount(); + + // ------------------------------------------------------------------------------- + + // devices: + DeviceIterator devicesBegin(); + DeviceIterator devicesEnd(); + + Device &defaultInputDevice(); + Device &defaultOutputDevice(); + + Device &deviceByIndex(PaDeviceIndex index); + + int deviceCount(); + + static Device &nullDevice(); + + // ------------------------------------------------------------------------------- + + // misc: + void sleep(long msec); + int sizeOfSample(PaSampleFormat format); + + private: + System(); + ~System(); + + static System *instance_; + static int initCount_; + + static HostApi **hostApis_; + static Device **devices_; + + static Device *nullDevice_; + }; + + +} // namespace portaudio + + +#endif // INCLUDED_PORTAUDIO_SYSTEM_HXX + diff --git a/bindings/cpp/include/portaudiocpp/SystemDeviceIterator.hxx b/bindings/cpp/include/portaudiocpp/SystemDeviceIterator.hxx new file mode 100644 index 0000000..613fc3d --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/SystemDeviceIterator.hxx @@ -0,0 +1,66 @@ +#ifndef INCLUDED_PORTAUDIO_SYSTEMDEVICEITERATOR_HXX +#define INCLUDED_PORTAUDIO_SYSTEMDEVICEITERATOR_HXX + +// --------------------------------------------------------------------------------------- + +#include +#include + +#include "portaudiocpp/System.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class Device; + class HostApi; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief Iterator class for iterating through all Devices in a System. + /// + /// Devices will be iterated by iterating all Devices in each + /// HostApi in the System. Compliant with the STL bidirectional + /// iterator concept. + ////// + class System::DeviceIterator + { + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef Device value_type; + typedef ptrdiff_t difference_type; + typedef Device * pointer; + typedef Device & reference; + + Device &operator*() const; + Device *operator->() const; + + DeviceIterator &operator++(); + DeviceIterator operator++(int); + DeviceIterator &operator--(); + DeviceIterator operator--(int); + + bool operator==(const DeviceIterator &rhs); + bool operator!=(const DeviceIterator &rhs); + + private: + friend class System; + friend class HostApi; + Device **ptr_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_SYSTEMDEVICEITERATOR_HXX + diff --git a/bindings/cpp/include/portaudiocpp/SystemHostApiIterator.hxx b/bindings/cpp/include/portaudiocpp/SystemHostApiIterator.hxx new file mode 100644 index 0000000..b9b13b8 --- /dev/null +++ b/bindings/cpp/include/portaudiocpp/SystemHostApiIterator.hxx @@ -0,0 +1,61 @@ +#ifndef INCLUDED_PORTAUDIO_SYSTEMHOSTAPIITERATOR_HXX +#define INCLUDED_PORTAUDIO_SYSTEMHOSTAPIITERATOR_HXX + +// --------------------------------------------------------------------------------------- + +#include +#include + +#include "portaudiocpp/System.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class HostApi; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief Iterator class for iterating through all HostApis in a System. + /// + /// Compliant with the STL bidirectional iterator concept. + ////// + class System::HostApiIterator + { + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef Device value_type; + typedef ptrdiff_t difference_type; + typedef HostApi * pointer; + typedef HostApi & reference; + + HostApi &operator*() const; + HostApi *operator->() const; + + HostApiIterator &operator++(); + HostApiIterator operator++(int); + HostApiIterator &operator--(); + HostApiIterator operator--(int); + + bool operator==(const HostApiIterator &rhs); + bool operator!=(const HostApiIterator &rhs); + + private: + friend class System; + HostApi **ptr_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_SYSTEMHOSTAPIITERATOR_HXX diff --git a/bindings/cpp/lib/Makefile.am b/bindings/cpp/lib/Makefile.am new file mode 100644 index 0000000..a27f7c5 --- /dev/null +++ b/bindings/cpp/lib/Makefile.am @@ -0,0 +1,26 @@ +SRCDIR = $(top_srcdir)/source/portaudiocpp + +lib_LTLIBRARIES = libportaudiocpp.la + +LDADD = libportaudiocpp.la + +libportaudiocpp_la_LDFLAGS = -version-info $(LT_VERSION_INFO) -no-undefined + +libportaudiocpp_la_LIBADD = $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +libportaudiocpp_la_SOURCES = \ + $(SRCDIR)/BlockingStream.cxx \ + $(SRCDIR)/CallbackInterface.cxx \ + $(SRCDIR)/CallbackStream.cxx \ + $(SRCDIR)/CFunCallbackStream.cxx \ + $(SRCDIR)/CppFunCallbackStream.cxx \ + $(SRCDIR)/Device.cxx \ + $(SRCDIR)/DirectionSpecificStreamParameters.cxx \ + $(SRCDIR)/Exception.cxx \ + $(SRCDIR)/HostApi.cxx \ + $(SRCDIR)/InterfaceCallbackStream.cxx \ + $(SRCDIR)/MemFunCallbackStream.cxx \ + $(SRCDIR)/Stream.cxx \ + $(SRCDIR)/StreamParameters.cxx \ + $(SRCDIR)/System.cxx \ + $(SRCDIR)/SystemDeviceIterator.cxx \ + $(SRCDIR)/SystemHostApiIterator.cxx diff --git a/bindings/cpp/lib/Makefile.in b/bindings/cpp/lib/Makefile.in new file mode 100644 index 0000000..11be8c1 --- /dev/null +++ b/bindings/cpp/lib/Makefile.in @@ -0,0 +1,615 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libportaudiocpp_la_DEPENDENCIES = \ + $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +am_libportaudiocpp_la_OBJECTS = BlockingStream.lo CallbackInterface.lo \ + CallbackStream.lo CFunCallbackStream.lo \ + CppFunCallbackStream.lo Device.lo \ + DirectionSpecificStreamParameters.lo Exception.lo HostApi.lo \ + InterfaceCallbackStream.lo MemFunCallbackStream.lo Stream.lo \ + StreamParameters.lo System.lo SystemDeviceIterator.lo \ + SystemHostApiIterator.lo +libportaudiocpp_la_OBJECTS = $(am_libportaudiocpp_la_OBJECTS) +depcomp = $(SHELL) $(top_srcdir)/../../depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libportaudiocpp_la_SOURCES) +DIST_SOURCES = $(libportaudiocpp_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SRCDIR = $(top_srcdir)/source/portaudiocpp +lib_LTLIBRARIES = libportaudiocpp.la +LDADD = libportaudiocpp.la +libportaudiocpp_la_LDFLAGS = -version-info $(LT_VERSION_INFO) -no-undefined +libportaudiocpp_la_LIBADD = $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +libportaudiocpp_la_SOURCES = \ + $(SRCDIR)/BlockingStream.cxx \ + $(SRCDIR)/CallbackInterface.cxx \ + $(SRCDIR)/CallbackStream.cxx \ + $(SRCDIR)/CFunCallbackStream.cxx \ + $(SRCDIR)/CppFunCallbackStream.cxx \ + $(SRCDIR)/Device.cxx \ + $(SRCDIR)/DirectionSpecificStreamParameters.cxx \ + $(SRCDIR)/Exception.cxx \ + $(SRCDIR)/HostApi.cxx \ + $(SRCDIR)/InterfaceCallbackStream.cxx \ + $(SRCDIR)/MemFunCallbackStream.cxx \ + $(SRCDIR)/Stream.cxx \ + $(SRCDIR)/StreamParameters.cxx \ + $(SRCDIR)/System.cxx \ + $(SRCDIR)/SystemDeviceIterator.cxx \ + $(SRCDIR)/SystemHostApiIterator.cxx + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cxx .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libportaudiocpp.la: $(libportaudiocpp_la_OBJECTS) $(libportaudiocpp_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libportaudiocpp_la_LDFLAGS) $(libportaudiocpp_la_OBJECTS) $(libportaudiocpp_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BlockingStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CFunCallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CallbackInterface.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CppFunCallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Device.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DirectionSpecificStreamParameters.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Exception.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HostApi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InterfaceCallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemFunCallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Stream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StreamParameters.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/System.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemDeviceIterator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemHostApiIterator.Plo@am__quote@ + +.cxx.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cxx.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cxx.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +BlockingStream.lo: $(SRCDIR)/BlockingStream.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT BlockingStream.lo -MD -MP -MF "$(DEPDIR)/BlockingStream.Tpo" -c -o BlockingStream.lo `test -f '$(SRCDIR)/BlockingStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/BlockingStream.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/BlockingStream.Tpo" "$(DEPDIR)/BlockingStream.Plo"; else rm -f "$(DEPDIR)/BlockingStream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/BlockingStream.cxx' object='BlockingStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o BlockingStream.lo `test -f '$(SRCDIR)/BlockingStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/BlockingStream.cxx + +CallbackInterface.lo: $(SRCDIR)/CallbackInterface.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CallbackInterface.lo -MD -MP -MF "$(DEPDIR)/CallbackInterface.Tpo" -c -o CallbackInterface.lo `test -f '$(SRCDIR)/CallbackInterface.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CallbackInterface.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/CallbackInterface.Tpo" "$(DEPDIR)/CallbackInterface.Plo"; else rm -f "$(DEPDIR)/CallbackInterface.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/CallbackInterface.cxx' object='CallbackInterface.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CallbackInterface.lo `test -f '$(SRCDIR)/CallbackInterface.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CallbackInterface.cxx + +CallbackStream.lo: $(SRCDIR)/CallbackStream.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CallbackStream.lo -MD -MP -MF "$(DEPDIR)/CallbackStream.Tpo" -c -o CallbackStream.lo `test -f '$(SRCDIR)/CallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CallbackStream.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/CallbackStream.Tpo" "$(DEPDIR)/CallbackStream.Plo"; else rm -f "$(DEPDIR)/CallbackStream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/CallbackStream.cxx' object='CallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CallbackStream.lo `test -f '$(SRCDIR)/CallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CallbackStream.cxx + +CFunCallbackStream.lo: $(SRCDIR)/CFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CFunCallbackStream.lo -MD -MP -MF "$(DEPDIR)/CFunCallbackStream.Tpo" -c -o CFunCallbackStream.lo `test -f '$(SRCDIR)/CFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CFunCallbackStream.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/CFunCallbackStream.Tpo" "$(DEPDIR)/CFunCallbackStream.Plo"; else rm -f "$(DEPDIR)/CFunCallbackStream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/CFunCallbackStream.cxx' object='CFunCallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CFunCallbackStream.lo `test -f '$(SRCDIR)/CFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CFunCallbackStream.cxx + +CppFunCallbackStream.lo: $(SRCDIR)/CppFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CppFunCallbackStream.lo -MD -MP -MF "$(DEPDIR)/CppFunCallbackStream.Tpo" -c -o CppFunCallbackStream.lo `test -f '$(SRCDIR)/CppFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CppFunCallbackStream.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/CppFunCallbackStream.Tpo" "$(DEPDIR)/CppFunCallbackStream.Plo"; else rm -f "$(DEPDIR)/CppFunCallbackStream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/CppFunCallbackStream.cxx' object='CppFunCallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CppFunCallbackStream.lo `test -f '$(SRCDIR)/CppFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CppFunCallbackStream.cxx + +Device.lo: $(SRCDIR)/Device.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Device.lo -MD -MP -MF "$(DEPDIR)/Device.Tpo" -c -o Device.lo `test -f '$(SRCDIR)/Device.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Device.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Device.Tpo" "$(DEPDIR)/Device.Plo"; else rm -f "$(DEPDIR)/Device.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/Device.cxx' object='Device.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Device.lo `test -f '$(SRCDIR)/Device.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Device.cxx + +DirectionSpecificStreamParameters.lo: $(SRCDIR)/DirectionSpecificStreamParameters.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT DirectionSpecificStreamParameters.lo -MD -MP -MF "$(DEPDIR)/DirectionSpecificStreamParameters.Tpo" -c -o DirectionSpecificStreamParameters.lo `test -f '$(SRCDIR)/DirectionSpecificStreamParameters.cxx' || echo '$(srcdir)/'`$(SRCDIR)/DirectionSpecificStreamParameters.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/DirectionSpecificStreamParameters.Tpo" "$(DEPDIR)/DirectionSpecificStreamParameters.Plo"; else rm -f "$(DEPDIR)/DirectionSpecificStreamParameters.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/DirectionSpecificStreamParameters.cxx' object='DirectionSpecificStreamParameters.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o DirectionSpecificStreamParameters.lo `test -f '$(SRCDIR)/DirectionSpecificStreamParameters.cxx' || echo '$(srcdir)/'`$(SRCDIR)/DirectionSpecificStreamParameters.cxx + +Exception.lo: $(SRCDIR)/Exception.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Exception.lo -MD -MP -MF "$(DEPDIR)/Exception.Tpo" -c -o Exception.lo `test -f '$(SRCDIR)/Exception.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Exception.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Exception.Tpo" "$(DEPDIR)/Exception.Plo"; else rm -f "$(DEPDIR)/Exception.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/Exception.cxx' object='Exception.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Exception.lo `test -f '$(SRCDIR)/Exception.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Exception.cxx + +HostApi.lo: $(SRCDIR)/HostApi.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT HostApi.lo -MD -MP -MF "$(DEPDIR)/HostApi.Tpo" -c -o HostApi.lo `test -f '$(SRCDIR)/HostApi.cxx' || echo '$(srcdir)/'`$(SRCDIR)/HostApi.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/HostApi.Tpo" "$(DEPDIR)/HostApi.Plo"; else rm -f "$(DEPDIR)/HostApi.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/HostApi.cxx' object='HostApi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o HostApi.lo `test -f '$(SRCDIR)/HostApi.cxx' || echo '$(srcdir)/'`$(SRCDIR)/HostApi.cxx + +InterfaceCallbackStream.lo: $(SRCDIR)/InterfaceCallbackStream.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT InterfaceCallbackStream.lo -MD -MP -MF "$(DEPDIR)/InterfaceCallbackStream.Tpo" -c -o InterfaceCallbackStream.lo `test -f '$(SRCDIR)/InterfaceCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/InterfaceCallbackStream.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/InterfaceCallbackStream.Tpo" "$(DEPDIR)/InterfaceCallbackStream.Plo"; else rm -f "$(DEPDIR)/InterfaceCallbackStream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/InterfaceCallbackStream.cxx' object='InterfaceCallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o InterfaceCallbackStream.lo `test -f '$(SRCDIR)/InterfaceCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/InterfaceCallbackStream.cxx + +MemFunCallbackStream.lo: $(SRCDIR)/MemFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT MemFunCallbackStream.lo -MD -MP -MF "$(DEPDIR)/MemFunCallbackStream.Tpo" -c -o MemFunCallbackStream.lo `test -f '$(SRCDIR)/MemFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/MemFunCallbackStream.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/MemFunCallbackStream.Tpo" "$(DEPDIR)/MemFunCallbackStream.Plo"; else rm -f "$(DEPDIR)/MemFunCallbackStream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/MemFunCallbackStream.cxx' object='MemFunCallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o MemFunCallbackStream.lo `test -f '$(SRCDIR)/MemFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/MemFunCallbackStream.cxx + +Stream.lo: $(SRCDIR)/Stream.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Stream.lo -MD -MP -MF "$(DEPDIR)/Stream.Tpo" -c -o Stream.lo `test -f '$(SRCDIR)/Stream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Stream.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/Stream.Tpo" "$(DEPDIR)/Stream.Plo"; else rm -f "$(DEPDIR)/Stream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/Stream.cxx' object='Stream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Stream.lo `test -f '$(SRCDIR)/Stream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Stream.cxx + +StreamParameters.lo: $(SRCDIR)/StreamParameters.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT StreamParameters.lo -MD -MP -MF "$(DEPDIR)/StreamParameters.Tpo" -c -o StreamParameters.lo `test -f '$(SRCDIR)/StreamParameters.cxx' || echo '$(srcdir)/'`$(SRCDIR)/StreamParameters.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/StreamParameters.Tpo" "$(DEPDIR)/StreamParameters.Plo"; else rm -f "$(DEPDIR)/StreamParameters.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/StreamParameters.cxx' object='StreamParameters.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o StreamParameters.lo `test -f '$(SRCDIR)/StreamParameters.cxx' || echo '$(srcdir)/'`$(SRCDIR)/StreamParameters.cxx + +System.lo: $(SRCDIR)/System.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT System.lo -MD -MP -MF "$(DEPDIR)/System.Tpo" -c -o System.lo `test -f '$(SRCDIR)/System.cxx' || echo '$(srcdir)/'`$(SRCDIR)/System.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/System.Tpo" "$(DEPDIR)/System.Plo"; else rm -f "$(DEPDIR)/System.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/System.cxx' object='System.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o System.lo `test -f '$(SRCDIR)/System.cxx' || echo '$(srcdir)/'`$(SRCDIR)/System.cxx + +SystemDeviceIterator.lo: $(SRCDIR)/SystemDeviceIterator.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SystemDeviceIterator.lo -MD -MP -MF "$(DEPDIR)/SystemDeviceIterator.Tpo" -c -o SystemDeviceIterator.lo `test -f '$(SRCDIR)/SystemDeviceIterator.cxx' || echo '$(srcdir)/'`$(SRCDIR)/SystemDeviceIterator.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/SystemDeviceIterator.Tpo" "$(DEPDIR)/SystemDeviceIterator.Plo"; else rm -f "$(DEPDIR)/SystemDeviceIterator.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/SystemDeviceIterator.cxx' object='SystemDeviceIterator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o SystemDeviceIterator.lo `test -f '$(SRCDIR)/SystemDeviceIterator.cxx' || echo '$(srcdir)/'`$(SRCDIR)/SystemDeviceIterator.cxx + +SystemHostApiIterator.lo: $(SRCDIR)/SystemHostApiIterator.cxx +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SystemHostApiIterator.lo -MD -MP -MF "$(DEPDIR)/SystemHostApiIterator.Tpo" -c -o SystemHostApiIterator.lo `test -f '$(SRCDIR)/SystemHostApiIterator.cxx' || echo '$(srcdir)/'`$(SRCDIR)/SystemHostApiIterator.cxx; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/SystemHostApiIterator.Tpo" "$(DEPDIR)/SystemHostApiIterator.Plo"; else rm -f "$(DEPDIR)/SystemHostApiIterator.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(SRCDIR)/SystemHostApiIterator.cxx' object='SystemHostApiIterator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o SystemHostApiIterator.lo `test -f '$(SRCDIR)/SystemHostApiIterator.cxx' || echo '$(srcdir)/'`$(SRCDIR)/SystemHostApiIterator.cxx + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bindings/cpp/portaudiocpp.pc.in b/bindings/cpp/portaudiocpp.pc.in new file mode 100644 index 0000000..8b126d1 --- /dev/null +++ b/bindings/cpp/portaudiocpp.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: PortAudioCpp +Description: Portable audio I/O C++ bindings +Version: 12 +Requires: portaudio-2.0 + +Libs: -L${libdir} -lportaudiocpp +Cflags: -I${includedir} diff --git a/bindings/cpp/source/portaudiocpp/AsioDeviceAdapter.cxx b/bindings/cpp/source/portaudiocpp/AsioDeviceAdapter.cxx new file mode 100644 index 0000000..c4ee25f --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/AsioDeviceAdapter.cxx @@ -0,0 +1,83 @@ +#include "portaudiocpp/AsioDeviceAdapter.hxx" + +#include "portaudio.h" +#include "pa_asio.h" + +#include "portaudiocpp/Device.hxx" +#include "portaudiocpp/HostApi.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + AsioDeviceAdapter::AsioDeviceAdapter(Device &device) + { + if (device.hostApi().typeId() != paASIO) + throw PaCppException(PaCppException::UNABLE_TO_ADAPT_DEVICE); + + device_ = &device; + + PaError err = PaAsio_GetAvailableLatencyValues(device_->index(), &minBufferSize_, &maxBufferSize_, + &preferredBufferSize_, &granularity_); + + if (err != paNoError) + throw PaException(err); + + } + + Device &AsioDeviceAdapter::device() + { + return *device_; + } + + long AsioDeviceAdapter::minBufferSize() const + { + return minBufferSize_; + } + + long AsioDeviceAdapter::maxBufferSize() const + { + return maxBufferSize_; + } + + long AsioDeviceAdapter::preferredBufferSize() const + { + return preferredBufferSize_; + } + + long AsioDeviceAdapter::granularity() const + { + return granularity_; + } + + void AsioDeviceAdapter::showControlPanel(void *systemSpecific) + { + PaError err = PaAsio_ShowControlPanel(device_->index(), systemSpecific); + + if (err != paNoError) + throw PaException(err); + } + + const char *AsioDeviceAdapter::inputChannelName(int channelIndex) const + { + const char *channelName; + PaError err = PaAsio_GetInputChannelName(device_->index(), channelIndex, &channelName); + + if (err != paNoError) + throw PaException(err); + + return channelName; + } + + const char *AsioDeviceAdapter::outputChannelName(int channelIndex) const + { + const char *channelName; + PaError err = PaAsio_GetOutputChannelName(device_->index(), channelIndex, &channelName); + + if (err != paNoError) + throw PaException(err); + + return channelName; + } +} + + diff --git a/bindings/cpp/source/portaudiocpp/BlockingStream.cxx b/bindings/cpp/source/portaudiocpp/BlockingStream.cxx new file mode 100644 index 0000000..c21535f --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/BlockingStream.cxx @@ -0,0 +1,100 @@ +#include "portaudiocpp/BlockingStream.hxx" + +#include "portaudio.h" + +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + + // -------------------------------------------------------------------------------------- + + BlockingStream::BlockingStream() + { + } + + BlockingStream::BlockingStream(const StreamParameters ¶meters) + { + open(parameters); + } + + BlockingStream::~BlockingStream() + { + try + { + close(); + } + catch (...) + { + // ignore all errors + } + } + + // -------------------------------------------------------------------------------------- + + void BlockingStream::open(const StreamParameters ¶meters) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), NULL, NULL); + + if (err != paNoError) + { + throw PaException(err); + } + } + + // -------------------------------------------------------------------------------------- + + void BlockingStream::read(void *buffer, unsigned long numFrames) + { + PaError err = Pa_ReadStream(stream_, buffer, numFrames); + + if (err != paNoError) + { + throw PaException(err); + } + } + + void BlockingStream::write(const void *buffer, unsigned long numFrames) + { + PaError err = Pa_WriteStream(stream_, buffer, numFrames); + + if (err != paNoError) + { + throw PaException(err); + } + } + + // -------------------------------------------------------------------------------------- + + signed long BlockingStream::availableReadSize() const + { + signed long avail = Pa_GetStreamReadAvailable(stream_); + + if (avail < 0) + { + throw PaException(avail); + } + + return avail; + } + + signed long BlockingStream::availableWriteSize() const + { + signed long avail = Pa_GetStreamWriteAvailable(stream_); + + if (avail < 0) + { + throw PaException(avail); + } + + return avail; + } + + // -------------------------------------------------------------------------------------- + +} // portaudio + + + diff --git a/bindings/cpp/source/portaudiocpp/CFunCallbackStream.cxx b/bindings/cpp/source/portaudiocpp/CFunCallbackStream.cxx new file mode 100644 index 0000000..fd2fb53 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/CFunCallbackStream.cxx @@ -0,0 +1,41 @@ +#include "portaudiocpp/CFunCallbackStream.hxx" + +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + CFunCallbackStream::CFunCallbackStream() + { + } + + CFunCallbackStream::CFunCallbackStream(const StreamParameters ¶meters, PaStreamCallback *funPtr, void *userData) + { + open(parameters, funPtr, userData); + } + + CFunCallbackStream::~CFunCallbackStream() + { + try + { + close(); + } + catch (...) + { + // ignore all errors + } + } + + // ---------------------------------------------------------------------------------== + + void CFunCallbackStream::open(const StreamParameters ¶meters, PaStreamCallback *funPtr, void *userData) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), funPtr, userData); + + if (err != paNoError) + { + throw PaException(err); + } + } +} diff --git a/bindings/cpp/source/portaudiocpp/CallbackInterface.cxx b/bindings/cpp/source/portaudiocpp/CallbackInterface.cxx new file mode 100644 index 0000000..7e34312 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/CallbackInterface.cxx @@ -0,0 +1,25 @@ +#include "portaudiocpp/CallbackInterface.hxx" + +namespace portaudio +{ + + namespace impl + { + + ////// + /// Adapts any CallbackInterface object to a C-callable function (ie this function). A + /// pointer to the object should be passed as ``userData'' when setting up the callback. + ////// + int callbackInterfaceToPaCallbackAdapter(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) + { + CallbackInterface *cb = static_cast(userData); + return cb->paCallbackFun(inputBuffer, outputBuffer, numFrames, timeInfo, statusFlags); + } + + + } // namespace impl + +} // namespace portaudio + + diff --git a/bindings/cpp/source/portaudiocpp/CallbackStream.cxx b/bindings/cpp/source/portaudiocpp/CallbackStream.cxx new file mode 100644 index 0000000..4204dbb --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/CallbackStream.cxx @@ -0,0 +1,20 @@ +#include "portaudiocpp/CallbackStream.hxx" + +namespace portaudio +{ + CallbackStream::CallbackStream() + { + } + + CallbackStream::~CallbackStream() + { + } + + // ----------------------------------------------------------------------------------- + + double CallbackStream::cpuLoad() const + { + return Pa_GetStreamCpuLoad(stream_); + } + +} // namespace portaudio diff --git a/bindings/cpp/source/portaudiocpp/CppFunCallbackStream.cxx b/bindings/cpp/source/portaudiocpp/CppFunCallbackStream.cxx new file mode 100644 index 0000000..9538139 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/CppFunCallbackStream.cxx @@ -0,0 +1,81 @@ +#include "portaudiocpp/CppFunCallbackStream.hxx" + +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + namespace impl + { + ////// + /// Adapts any a C++ callback to a C-callable function (ie this function). A + /// pointer to a struct with the C++ function pointer and the actual user data should be + /// passed as the ``userData'' parameter when setting up the callback. + ////// + int cppCallbackToPaCallbackAdapter(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) + { + FunCallbackStream::CppToCCallbackData *data = static_cast(userData); + return data->funPtr(inputBuffer, outputBuffer, numFrames, timeInfo, statusFlags, data->userData); + } + } + + // ----------------------------------------------------------------------------------- + + FunCallbackStream::CppToCCallbackData::CppToCCallbackData() + { + } + + FunCallbackStream::CppToCCallbackData::CppToCCallbackData(CallbackFunPtr funPtr, void *userData) : funPtr(funPtr), userData(userData) + { + } + + void FunCallbackStream::CppToCCallbackData::init(CallbackFunPtr funPtr, void *userData) + { + this->funPtr = funPtr; + this->userData = userData; + } + + // ----------------------------------------------------------------------------------- + + FunCallbackStream::FunCallbackStream() + { + } + + FunCallbackStream::FunCallbackStream(const StreamParameters ¶meters, CallbackFunPtr funPtr, void *userData) : adapterData_(funPtr, userData) + { + open(parameters); + } + + FunCallbackStream::~FunCallbackStream() + { + try + { + close(); + } + catch (...) + { + // ignore all errors + } + } + + void FunCallbackStream::open(const StreamParameters ¶meters, CallbackFunPtr funPtr, void *userData) + { + adapterData_.init(funPtr, userData); + open(parameters); + } + + void FunCallbackStream::open(const StreamParameters ¶meters) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), &impl::cppCallbackToPaCallbackAdapter, + static_cast(&adapterData_)); + + if (err != paNoError) + { + throw PaException(err); + } + } + + // ----------------------------------------------------------------------------------- +} diff --git a/bindings/cpp/source/portaudiocpp/Device.cxx b/bindings/cpp/source/portaudiocpp/Device.cxx new file mode 100644 index 0000000..cd7eb7c --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/Device.cxx @@ -0,0 +1,168 @@ +#include "portaudiocpp/Device.hxx" + +#include + +#include "portaudiocpp/HostApi.hxx" +#include "portaudiocpp/System.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + + // ------------------------------------------------------------------------------- + + Device::Device(PaDeviceIndex index) : index_(index) + { + if (index == paNoDevice) + info_ = NULL; + else + info_ = Pa_GetDeviceInfo(index); + } + + Device::~Device() + { + } + + PaDeviceIndex Device::index() const + { + return index_; + } + + const char *Device::name() const + { + if (info_ == NULL) + return ""; + + return info_->name; + } + + int Device::maxInputChannels() const + { + if (info_ == NULL) + return 0; + + return info_->maxInputChannels; + } + + int Device::maxOutputChannels() const + { + if (info_ == NULL) + return 0; + + return info_->maxOutputChannels; + } + + PaTime Device::defaultLowInputLatency() const + { + if (info_ == NULL) + return static_cast(0.0); + + return info_->defaultLowInputLatency; + } + + PaTime Device::defaultHighInputLatency() const + { + if (info_ == NULL) + return static_cast(0.0); + + return info_->defaultHighInputLatency; + } + + PaTime Device::defaultLowOutputLatency() const + { + if (info_ == NULL) + return static_cast(0.0); + + return info_->defaultLowOutputLatency; + } + + PaTime Device::defaultHighOutputLatency() const + { + if (info_ == NULL) + return static_cast(0.0); + + return info_->defaultHighOutputLatency; + } + + double Device::defaultSampleRate() const + { + if (info_ == NULL) + return 0.0; + + return info_->defaultSampleRate; + } + + // ------------------------------------------------------------------------------- + + bool Device::isInputOnlyDevice() const + { + return (maxOutputChannels() == 0); + } + + bool Device::isOutputOnlyDevice() const + { + return (maxInputChannels() == 0); + } + + bool Device::isFullDuplexDevice() const + { + return (maxInputChannels() > 0 && maxOutputChannels() > 0); + } + + bool Device::isSystemDefaultInputDevice() const + { + return (System::instance().defaultInputDevice() == *this); + } + + bool Device::isSystemDefaultOutputDevice() const + { + return (System::instance().defaultOutputDevice() == *this); + } + + bool Device::isHostApiDefaultInputDevice() const + { + return (hostApi().defaultInputDevice() == *this); + } + + bool Device::isHostApiDefaultOutputDevice() const + { + return (hostApi().defaultOutputDevice() == *this); + } + + // ------------------------------------------------------------------------------- + + bool Device::operator==(const Device &rhs) + { + return (index_ == rhs.index_); + } + + bool Device::operator!=(const Device &rhs) + { + return !(*this == rhs); + } + + // ------------------------------------------------------------------------------- + + HostApi &Device::hostApi() + { + // NOTE: will cause an exception when called for the null device + if (info_ == NULL) + throw PaException(paInternalError); + + return System::instance().hostApiByIndex(info_->hostApi); + } + + const HostApi &Device::hostApi() const + { + // NOTE; will cause an exception when called for the null device + if (info_ == NULL) + throw PaException(paInternalError); + + return System::instance().hostApiByIndex(info_->hostApi); + } + + // ------------------------------------------------------------------------------- + +} // namespace portaudio + + diff --git a/bindings/cpp/source/portaudiocpp/DirectionSpecificStreamParameters.cxx b/bindings/cpp/source/portaudiocpp/DirectionSpecificStreamParameters.cxx new file mode 100644 index 0000000..d3c307c --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/DirectionSpecificStreamParameters.cxx @@ -0,0 +1,163 @@ +#include "portaudiocpp/DirectionSpecificStreamParameters.hxx" + +#include "portaudiocpp/Device.hxx" + +namespace portaudio +{ + + // ----------------------------------------------------------------------------------- + + ////// + /// Returns a `nil' DirectionSpecificStreamParameters object. This can be used to + /// specify that one direction of a Stream is not required (i.e. when creating + /// a half-duplex Stream). All fields of the null DirectionSpecificStreamParameters + /// object are invalid except for the device and the number of channel, which are set + /// to paNoDevice and 0 respectively. + ////// + DirectionSpecificStreamParameters DirectionSpecificStreamParameters::null() + { + DirectionSpecificStreamParameters tmp; + tmp.paStreamParameters_.device = paNoDevice; + tmp.paStreamParameters_.channelCount = 0; + return tmp; + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Default constructor -- all parameters will be uninitialized. + ////// + DirectionSpecificStreamParameters::DirectionSpecificStreamParameters() + { + } + + ////// + /// Constructor which sets all required fields. + ////// + DirectionSpecificStreamParameters::DirectionSpecificStreamParameters(const Device &device, int numChannels, + SampleDataFormat format, bool interleaved, PaTime suggestedLatency, void *hostApiSpecificStreamInfo) + { + setDevice(device); + setNumChannels(numChannels); + setSampleFormat(format, interleaved); + setSuggestedLatency(suggestedLatency); + setHostApiSpecificStreamInfo(hostApiSpecificStreamInfo); + } + + // ----------------------------------------------------------------------------------- + + void DirectionSpecificStreamParameters::setDevice(const Device &device) + { + paStreamParameters_.device = device.index(); + } + + void DirectionSpecificStreamParameters::setNumChannels(int numChannels) + { + paStreamParameters_.channelCount = numChannels; + } + + void DirectionSpecificStreamParameters::setSampleFormat(SampleDataFormat format, bool interleaved) + { + paStreamParameters_.sampleFormat = static_cast(format); + + if (!interleaved) + paStreamParameters_.sampleFormat |= paNonInterleaved; + } + + void DirectionSpecificStreamParameters::setHostApiSpecificSampleFormat(PaSampleFormat format, bool interleaved) + { + paStreamParameters_.sampleFormat = format; + + paStreamParameters_.sampleFormat |= paCustomFormat; + + if (!interleaved) + paStreamParameters_.sampleFormat |= paNonInterleaved; + } + + void DirectionSpecificStreamParameters::setSuggestedLatency(PaTime latency) + { + paStreamParameters_.suggestedLatency = latency; + } + + void DirectionSpecificStreamParameters::setHostApiSpecificStreamInfo(void *streamInfo) + { + paStreamParameters_.hostApiSpecificStreamInfo = streamInfo; + } + + // ----------------------------------------------------------------------------------- + + PaStreamParameters *DirectionSpecificStreamParameters::paStreamParameters() + { + if (paStreamParameters_.channelCount > 0 && paStreamParameters_.device != paNoDevice) + return &paStreamParameters_; + else + return NULL; + } + + const PaStreamParameters *DirectionSpecificStreamParameters::paStreamParameters() const + { + if (paStreamParameters_.channelCount > 0 && paStreamParameters_.device != paNoDevice) + return &paStreamParameters_; + else + return NULL; + } + + Device &DirectionSpecificStreamParameters::device() const + { + return System::instance().deviceByIndex(paStreamParameters_.device); + } + + int DirectionSpecificStreamParameters::numChannels() const + { + return paStreamParameters_.channelCount; + } + + ////// + /// Returns the (non host api-specific) sample format, without including + /// the paNonInterleaved flag. If the sample format is host api-spefific, + /// INVALID_FORMAT (0) will be returned. + ////// + SampleDataFormat DirectionSpecificStreamParameters::sampleFormat() const + { + if (isSampleFormatHostApiSpecific()) + return INVALID_FORMAT; + else + return static_cast(paStreamParameters_.sampleFormat & ~paNonInterleaved); + } + + bool DirectionSpecificStreamParameters::isSampleFormatInterleaved() const + { + return ((paStreamParameters_.sampleFormat & paNonInterleaved) == 0); + } + + bool DirectionSpecificStreamParameters::isSampleFormatHostApiSpecific() const + { + return ((paStreamParameters_.sampleFormat & paCustomFormat) == 0); + } + + ////// + /// Returns the host api-specific sample format, without including any + /// paCustomFormat or paNonInterleaved flags. Will return 0 if the sample format is + /// not host api-specific. + ////// + PaSampleFormat DirectionSpecificStreamParameters::hostApiSpecificSampleFormat() const + { + if (isSampleFormatHostApiSpecific()) + return paStreamParameters_.sampleFormat & ~paCustomFormat & ~paNonInterleaved; + else + return 0; + } + + PaTime DirectionSpecificStreamParameters::suggestedLatency() const + { + return paStreamParameters_.suggestedLatency; + } + + void *DirectionSpecificStreamParameters::hostApiSpecificStreamInfo() const + { + return paStreamParameters_.hostApiSpecificStreamInfo; + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio diff --git a/bindings/cpp/source/portaudiocpp/Exception.cxx b/bindings/cpp/source/portaudiocpp/Exception.cxx new file mode 100644 index 0000000..2e7e701 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/Exception.cxx @@ -0,0 +1,123 @@ +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + // PaException: + // ----------------------------------------------------------------------------------- + + ////// + /// Wraps a PortAudio error into a PortAudioCpp PaException. + ////// + PaException::PaException(PaError error) : error_(error) + { + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Alias for paErrorText(), to have std::exception compliance. + ////// + const char *PaException::what() const throw() + { + return paErrorText(); + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Returns the PortAudio error code (PaError). + ////// + PaError PaException::paError() const + { + return error_; + } + + ////// + /// Returns the error as a (zero-terminated) text string. + ////// + const char *PaException::paErrorText() const + { + return Pa_GetErrorText(error_); + } + + ////// + /// Returns true is the error is a HostApi error. + ////// + bool PaException::isHostApiError() const + { + return (error_ == paUnanticipatedHostError); + } + + ////// + /// Returns the last HostApi error (which is the current one if + /// isHostApiError() returns true) as an error code. + ////// + long PaException::lastHostApiError() const + { + return Pa_GetLastHostErrorInfo()->errorCode; + } + + ////// + /// Returns the last HostApi error (which is the current one if + /// isHostApiError() returns true) as a (zero-terminated) text + /// string, if it's available. + ////// + const char *PaException::lastHostApiErrorText() const + { + return Pa_GetLastHostErrorInfo()->errorText; + } + + // ----------------------------------------------------------------------------------- + + bool PaException::operator==(const PaException &rhs) const + { + return (error_ == rhs.error_); + } + + bool PaException::operator!=(const PaException &rhs) const + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- + // PaCppException: + // ----------------------------------------------------------------------------------- + + PaCppException::PaCppException(ExceptionSpecifier specifier) : specifier_(specifier) + { + } + + const char *PaCppException::what() const throw() + { + switch (specifier_) + { + case UNABLE_TO_ADAPT_DEVICE: + { + return "Unable to adapt the given device to the specified host api specific device extension"; + } + } + + return "Unknown exception"; + } + + PaCppException::ExceptionSpecifier PaCppException::specifier() const + { + return specifier_; + } + + bool PaCppException::operator==(const PaCppException &rhs) const + { + return (specifier_ == rhs.specifier_); + } + + bool PaCppException::operator!=(const PaCppException &rhs) const + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio + + diff --git a/bindings/cpp/source/portaudiocpp/HostApi.cxx b/bindings/cpp/source/portaudiocpp/HostApi.cxx new file mode 100644 index 0000000..c6ae019 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/HostApi.cxx @@ -0,0 +1,121 @@ +#include "portaudiocpp/HostApi.hxx" + +#include "portaudiocpp/System.hxx" +#include "portaudiocpp/Device.hxx" +#include "portaudiocpp/SystemDeviceIterator.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + + // ----------------------------------------------------------------------------------- + + HostApi::HostApi(PaHostApiIndex index) : devices_(NULL) + { + try + { + info_ = Pa_GetHostApiInfo(index); + + // Create and populate devices array: + int numDevices = deviceCount(); + + devices_ = new Device*[numDevices]; + + for (int i = 0; i < numDevices; ++i) + { + PaDeviceIndex deviceIndex = Pa_HostApiDeviceIndexToDeviceIndex(index, i); + + if (deviceIndex < 0) + { + throw PaException(deviceIndex); + } + + devices_[i] = &System::instance().deviceByIndex(deviceIndex); + } + } + catch (const std::exception &e) + { + // Delete any (partially) constructed objects (deconstructor isn't called): + delete[] devices_; // devices_ is either NULL or valid + + // Re-throw exception: + throw e; + } + } + + HostApi::~HostApi() + { + // Destroy devices array: + delete[] devices_; + } + + // ----------------------------------------------------------------------------------- + + PaHostApiTypeId HostApi::typeId() const + { + return info_->type; + } + + PaHostApiIndex HostApi::index() const + { + PaHostApiIndex index = Pa_HostApiTypeIdToHostApiIndex(typeId()); + + if (index < 0) + throw PaException(index); + + return index; + } + + const char *HostApi::name() const + { + return info_->name; + } + + int HostApi::deviceCount() const + { + return info_->deviceCount; + } + + // ----------------------------------------------------------------------------------- + + HostApi::DeviceIterator HostApi::devicesBegin() + { + DeviceIterator tmp; + tmp.ptr_ = &devices_[0]; // begin (first element) + return tmp; + } + + HostApi::DeviceIterator HostApi::devicesEnd() + { + DeviceIterator tmp; + tmp.ptr_ = &devices_[deviceCount()]; // end (one past last element) + return tmp; + } + + // ----------------------------------------------------------------------------------- + + Device &HostApi::defaultInputDevice() const + { + return System::instance().deviceByIndex(info_->defaultInputDevice); + } + + Device &HostApi::defaultOutputDevice() const + { + return System::instance().deviceByIndex(info_->defaultOutputDevice); + } + + // ----------------------------------------------------------------------------------- + + bool HostApi::operator==(const HostApi &rhs) const + { + return (typeId() == rhs.typeId()); + } + + bool HostApi::operator!=(const HostApi &rhs) const + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio diff --git a/bindings/cpp/source/portaudiocpp/InterfaceCallbackStream.cxx b/bindings/cpp/source/portaudiocpp/InterfaceCallbackStream.cxx new file mode 100644 index 0000000..09e02de --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/InterfaceCallbackStream.cxx @@ -0,0 +1,45 @@ +#include "portaudiocpp/InterfaceCallbackStream.hxx" + +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/CallbackInterface.hxx" + +namespace portaudio +{ + + // ---------------------------------------------------------------------------------== + + InterfaceCallbackStream::InterfaceCallbackStream() + { + } + + InterfaceCallbackStream::InterfaceCallbackStream(const StreamParameters ¶meters, CallbackInterface &instance) + { + open(parameters, instance); + } + + InterfaceCallbackStream::~InterfaceCallbackStream() + { + try + { + close(); + } + catch (...) + { + // ignore all errors + } + } + + // ---------------------------------------------------------------------------------== + + void InterfaceCallbackStream::open(const StreamParameters ¶meters, CallbackInterface &instance) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), &impl::callbackInterfaceToPaCallbackAdapter, static_cast(&instance)); + + if (err != paNoError) + { + throw PaException(err); + } + } +} diff --git a/bindings/cpp/source/portaudiocpp/MemFunCallbackStream.cxx b/bindings/cpp/source/portaudiocpp/MemFunCallbackStream.cxx new file mode 100644 index 0000000..113fe5a --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/MemFunCallbackStream.cxx @@ -0,0 +1,4 @@ +#include "portaudiocpp/MemFunCallbackStream.hxx" + +// (... template class ...) + diff --git a/bindings/cpp/source/portaudiocpp/Stream.cxx b/bindings/cpp/source/portaudiocpp/Stream.cxx new file mode 100644 index 0000000..3b21f09 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/Stream.cxx @@ -0,0 +1,195 @@ +#include "portaudiocpp/Stream.hxx" + +#include + +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/System.hxx" + +namespace portaudio +{ + + // ----------------------------------------------------------------------------------- + + Stream::Stream() : stream_(NULL) + { + } + + Stream::~Stream() + { + // (can't call close here, + // the derived class should atleast call + // close() in it's deconstructor) + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Closes the Stream if it's open, else does nothing. + ////// + void Stream::close() + { + if (isOpen() && System::exists()) + { + PaError err = Pa_CloseStream(stream_); + stream_ = NULL; + + if (err != paNoError) + throw PaException(err); + } + } + + ////// + /// Returns true if the Stream is open. + ////// + bool Stream::isOpen() const + { + return (stream_ != NULL); + } + + // ----------------------------------------------------------------------------------- + + void Stream::setStreamFinishedCallback(PaStreamFinishedCallback *callback) + { + PaError err = Pa_SetStreamFinishedCallback(stream_, callback); + + if (err != paNoError) + throw PaException(err); + } + + // ----------------------------------------------------------------------------------- + + void Stream::start() + { + PaError err = Pa_StartStream(stream_); + + if (err != paNoError) + throw PaException(err); + } + + void Stream::stop() + { + PaError err = Pa_StopStream(stream_); + + if (err != paNoError) + throw PaException(err); + } + + void Stream::abort() + { + PaError err = Pa_AbortStream(stream_); + + if (err != paNoError) + throw PaException(err); + } + + bool Stream::isStopped() const + { + PaError ret = Pa_IsStreamStopped(stream_); + + if (ret < 0) + throw PaException(ret); + + return (ret == 1); + } + + bool Stream::isActive() const + { + PaError ret = Pa_IsStreamActive(stream_); + + if (ret < 0) + throw PaException(ret); + + return (ret == 1); + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Returns the best known input latency for the Stream. This value may differ from the + /// suggested input latency set in the StreamParameters. Includes all sources of + /// latency known to PortAudio such as internal buffering, and Host API reported latency. + /// Doesn't include any estimates of unknown latency. + ////// + PaTime Stream::inputLatency() const + { + const PaStreamInfo *info = Pa_GetStreamInfo(stream_); + if (info == NULL) + { + throw PaException(paInternalError); + return PaTime(0.0); + } + + return info->inputLatency; + } + + ////// + /// Returns the best known output latency for the Stream. This value may differ from the + /// suggested output latency set in the StreamParameters. Includes all sources of + /// latency known to PortAudio such as internal buffering, and Host API reported latency. + /// Doesn't include any estimates of unknown latency. + ////// + PaTime Stream::outputLatency() const + { + const PaStreamInfo *info = Pa_GetStreamInfo(stream_); + if (info == NULL) + { + throw PaException(paInternalError); + return PaTime(0.0); + } + + return info->outputLatency; + } + + ////// + /// Returns the sample rate of the Stream. Usually this will be the + /// best known estimate of the used sample rate. For instance when opening a + /// Stream setting 44100.0 Hz in the StreamParameters, the actual sample + /// rate might be something like 44103.2 Hz (due to imperfections in the + /// sound card hardware). + ////// + double Stream::sampleRate() const + { + const PaStreamInfo *info = Pa_GetStreamInfo(stream_); + if (info == NULL) + { + throw PaException(paInternalError); + return 0.0; + } + + return info->sampleRate; + } + + // ----------------------------------------------------------------------------------- + + PaTime Stream::time() const + { + return Pa_GetStreamTime(stream_); + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Accessor (const) for PortAudio PaStream pointer, useful for interfacing with + /// PortAudio add-ons such as PortMixer for instance. Normally accessing this + /// pointer should not be needed as PortAudioCpp aims to provide all of PortAudio's + /// functionality. + ////// + const PaStream *Stream::paStream() const + { + return stream_; + } + + ////// + /// Accessor (non-const) for PortAudio PaStream pointer, useful for interfacing with + /// PortAudio add-ons such as PortMixer for instance. Normally accessing this + /// pointer should not be needed as PortAudioCpp aims to provide all of PortAudio's + /// functionality. + ////// + PaStream *Stream::paStream() + { + return stream_; + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio diff --git a/bindings/cpp/source/portaudiocpp/StreamParameters.cxx b/bindings/cpp/source/portaudiocpp/StreamParameters.cxx new file mode 100644 index 0000000..670873b --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/StreamParameters.cxx @@ -0,0 +1,165 @@ +#include "portaudiocpp/StreamParameters.hxx" + +#include + +#include "portaudiocpp/Device.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + ////// + /// Default constructor; does nothing. + ////// + StreamParameters::StreamParameters() + { + } + + ////// + /// Sets up the all parameters needed to open either a half-duplex or full-duplex Stream. + /// + /// @param inputParameters The parameters for the input direction of the to-be opened + /// Stream or DirectionSpecificStreamParameters::null() for an output-only Stream. + /// @param outputParameters The parameters for the output direction of the to-be opened + /// Stream or DirectionSpecificStreamParameters::null() for an input-only Stream. + /// @param sampleRate The to-be opened Stream's sample rate in Hz. + /// @param framesPerBuffer The number of frames per buffer for a CallbackStream, or + /// the preferred buffer granularity for a BlockingStream. + /// @param flags The flags for the to-be opened Stream; default paNoFlag. + ////// + StreamParameters::StreamParameters(const DirectionSpecificStreamParameters &inputParameters, + const DirectionSpecificStreamParameters &outputParameters, double sampleRate, unsigned long framesPerBuffer, + PaStreamFlags flags) : inputParameters_(inputParameters), outputParameters_(outputParameters), + sampleRate_(sampleRate), framesPerBuffer_(framesPerBuffer), flags_(flags) + { + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Sets the requested sample rate. If this sample rate isn't supported by the hardware, the + /// Stream will fail to open. The real-life sample rate used might differ slightly due to + /// imperfections in the sound card hardware; use Stream::sampleRate() to retreive the + /// best known estimate for this value. + ////// + void StreamParameters::setSampleRate(double sampleRate) + { + sampleRate_ = sampleRate; + } + + ////// + /// Either the number of frames per buffer for a CallbackStream, or + /// the preferred buffer granularity for a BlockingStream. See PortAudio + /// documentation. + ////// + void StreamParameters::setFramesPerBuffer(unsigned long framesPerBuffer) + { + framesPerBuffer_ = framesPerBuffer; + } + + ////// + /// Sets the specified flag or does nothing when the flag is already set. Doesn't + /// `unset' any previously existing flags (use clearFlags() for that). + ////// + void StreamParameters::setFlag(PaStreamFlags flag) + { + flags_ |= flag; + } + + ////// + /// Unsets the specified flag or does nothing if the flag isn't set. Doesn't affect + /// any other flags. + ////// + void StreamParameters::unsetFlag(PaStreamFlags flag) + { + flags_ &= ~flag; + } + + ////// + /// Clears or `unsets' all set flags. + ////// + void StreamParameters::clearFlags() + { + flags_ = paNoFlag; + } + + // ----------------------------------------------------------------------------------- + + void StreamParameters::setInputParameters(const DirectionSpecificStreamParameters ¶meters) + { + inputParameters_ = parameters; + } + + void StreamParameters::setOutputParameters(const DirectionSpecificStreamParameters ¶meters) + { + outputParameters_ = parameters; + } + + // ----------------------------------------------------------------------------------- + + bool StreamParameters::isSupported() const + { + return (Pa_IsFormatSupported(inputParameters_.paStreamParameters(), + outputParameters_.paStreamParameters(), sampleRate_) == paFormatIsSupported); + } + + // ----------------------------------------------------------------------------------- + + double StreamParameters::sampleRate() const + { + return sampleRate_; + } + + unsigned long StreamParameters::framesPerBuffer() const + { + return framesPerBuffer_; + } + + ////// + /// Returns all currently set flags as a binary combined + /// integer value (PaStreamFlags). Use isFlagSet() to + /// avoid dealing with the bitmasks. + ////// + PaStreamFlags StreamParameters::flags() const + { + return flags_; + } + + ////// + /// Returns true if the specified flag is currently set + /// or false if it isn't. + ////// + bool StreamParameters::isFlagSet(PaStreamFlags flag) const + { + return ((flags_ & flag) != 0); + } + + // ----------------------------------------------------------------------------------- + + DirectionSpecificStreamParameters &StreamParameters::inputParameters() + { + return inputParameters_; + } + + const DirectionSpecificStreamParameters &StreamParameters::inputParameters() const + { + return inputParameters_; + } + + DirectionSpecificStreamParameters &StreamParameters::outputParameters() + { + return outputParameters_; + } + + const DirectionSpecificStreamParameters &StreamParameters::outputParameters() const + { + return outputParameters_; + } + + // ----------------------------------------------------------------------------------- +} // namespace portaudio + + + + + diff --git a/bindings/cpp/source/portaudiocpp/System.cxx b/bindings/cpp/source/portaudiocpp/System.cxx new file mode 100644 index 0000000..692c7a1 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/System.cxx @@ -0,0 +1,308 @@ +#include "portaudiocpp/System.hxx" + +#include +#include + +#include "portaudiocpp/HostApi.hxx" +#include "portaudiocpp/Device.hxx" +#include "portaudiocpp/Stream.hxx" +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/SystemHostApiIterator.hxx" +#include "portaudiocpp/SystemDeviceIterator.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + // Static members: + System *System::instance_ = NULL; + int System::initCount_ = 0; + HostApi **System::hostApis_ = NULL; + Device **System::devices_ = NULL; + Device *System::nullDevice_ = NULL; + + // ----------------------------------------------------------------------------------- + + int System::version() + { + return Pa_GetVersion(); + } + + const char *System::versionText() + { + return Pa_GetVersionText(); + } + + void System::initialize() + { + ++initCount_; + + if (initCount_ == 1) + { + // Create singleton: + assert(instance_ == NULL); + instance_ = new System(); + + // Initialize the PortAudio system: + { + PaError err = Pa_Initialize(); + + if (err != paNoError) + throw PaException(err); + } + + // Create and populate device array: + { + int numDevices = instance().deviceCount(); + + devices_ = new Device*[numDevices]; + + for (int i = 0; i < numDevices; ++i) + devices_[i] = new Device(i); + } + + // Create and populate host api array: + { + int numHostApis = instance().hostApiCount(); + + hostApis_ = new HostApi*[numHostApis]; + + for (int i = 0; i < numHostApis; ++i) + hostApis_[i] = new HostApi(i); + } + + // Create null device: + nullDevice_ = new Device(paNoDevice); + } + } + + void System::terminate() + { + PaError err = paNoError; + + if (initCount_ == 1) + { + // Destroy null device: + delete nullDevice_; + + // Destroy host api array: + { + if (hostApis_ != NULL) + { + int numHostApis = instance().hostApiCount(); + + for (int i = 0; i < numHostApis; ++i) + delete hostApis_[i]; + + delete[] hostApis_; + hostApis_ = NULL; + } + } + + // Destroy device array: + { + if (devices_ != NULL) + { + int numDevices = instance().deviceCount(); + + for (int i = 0; i < numDevices; ++i) + delete devices_[i]; + + delete[] devices_; + devices_ = NULL; + } + } + + // Terminate the PortAudio system: + assert(instance_ != NULL); + err = Pa_Terminate(); + + // Destroy singleton: + delete instance_; + instance_ = NULL; + } + + if (initCount_ > 0) + --initCount_; + + if (err != paNoError) + throw PaException(err); + } + + + System &System::instance() + { + assert(exists()); + + return *instance_; + } + + bool System::exists() + { + return (instance_ != NULL); + } + + // ----------------------------------------------------------------------------------- + + System::HostApiIterator System::hostApisBegin() + { + System::HostApiIterator tmp; + tmp.ptr_ = &hostApis_[0]; // begin (first element) + return tmp; + } + + System::HostApiIterator System::hostApisEnd() + { + int count = hostApiCount(); + + System::HostApiIterator tmp; + tmp.ptr_ = &hostApis_[count]; // end (one past last element) + return tmp; + } + + HostApi &System::defaultHostApi() + { + PaHostApiIndex defaultHostApi = Pa_GetDefaultHostApi(); + + if (defaultHostApi < 0) + throw PaException(defaultHostApi); + + return *hostApis_[defaultHostApi]; + } + + HostApi &System::hostApiByTypeId(PaHostApiTypeId type) + { + PaHostApiIndex index = Pa_HostApiTypeIdToHostApiIndex(type); + + if (index < 0) + throw PaException(index); + + return *hostApis_[index]; + } + + HostApi &System::hostApiByIndex(PaHostApiIndex index) + { + if (index < 0 || index >= hostApiCount()) + throw PaException(paInternalError); + + return *hostApis_[index]; + } + + int System::hostApiCount() + { + PaHostApiIndex count = Pa_GetHostApiCount(); + + if (count < 0) + throw PaException(count); + + return count; + } + + // ----------------------------------------------------------------------------------- + + System::DeviceIterator System::devicesBegin() + { + DeviceIterator tmp; + tmp.ptr_ = &devices_[0]; + + return tmp; + } + + System::DeviceIterator System::devicesEnd() + { + int count = deviceCount(); + + DeviceIterator tmp; + tmp.ptr_ = &devices_[count]; + + return tmp; + } + + ////// + /// Returns the System's default input Device, or the null Device if none + /// was available. + ////// + Device &System::defaultInputDevice() + { + PaDeviceIndex index = Pa_GetDefaultInputDevice(); + return deviceByIndex(index); + } + + ////// + /// Returns the System's default output Device, or the null Device if none + /// was available. + ////// + Device &System::defaultOutputDevice() + { + PaDeviceIndex index = Pa_GetDefaultOutputDevice(); + return deviceByIndex(index); + } + + ////// + /// Returns the Device for the given index. + /// Will throw a paInternalError equivalent PaException if the given index + /// is out of range. + ////// + Device &System::deviceByIndex(PaDeviceIndex index) + { + if (index < -1 || index >= deviceCount()) + { + throw PaException(paInternalError); + } + + if (index == -1) + return System::instance().nullDevice(); + + return *devices_[index]; + } + + int System::deviceCount() + { + PaDeviceIndex count = Pa_GetDeviceCount(); + + if (count < 0) + throw PaException(count); + + return count; + } + + Device &System::nullDevice() + { + return *nullDevice_; + } + + // ----------------------------------------------------------------------------------- + + void System::sleep(long msec) + { + Pa_Sleep(msec); + } + + int System::sizeOfSample(PaSampleFormat format) + { + PaError err = Pa_GetSampleSize(format); + if (err < 0) + { + throw PaException(err); + return 0; + } + + return err; + } + + // ----------------------------------------------------------------------------------- + + System::System() + { + // (left blank intentionally) + } + + System::~System() + { + // (left blank intentionally) + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio + diff --git a/bindings/cpp/source/portaudiocpp/SystemDeviceIterator.cxx b/bindings/cpp/source/portaudiocpp/SystemDeviceIterator.cxx new file mode 100644 index 0000000..c3c00f7 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/SystemDeviceIterator.cxx @@ -0,0 +1,60 @@ +#include "portaudiocpp/SystemDeviceIterator.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + Device &System::DeviceIterator::operator*() const + { + return **ptr_; + } + + Device *System::DeviceIterator::operator->() const + { + return &**this; + } + + // ----------------------------------------------------------------------------------- + + System::DeviceIterator &System::DeviceIterator::operator++() + { + ++ptr_; + return *this; + } + + System::DeviceIterator System::DeviceIterator::operator++(int) + { + System::DeviceIterator prev = *this; + ++*this; + return prev; + } + + System::DeviceIterator &System::DeviceIterator::operator--() + { + --ptr_; + return *this; + } + + System::DeviceIterator System::DeviceIterator::operator--(int) + { + System::DeviceIterator prev = *this; + --*this; + return prev; + } + + // ----------------------------------------------------------------------------------- + + bool System::DeviceIterator::operator==(const System::DeviceIterator &rhs) + { + return (ptr_ == rhs.ptr_); + } + + bool System::DeviceIterator::operator!=(const System::DeviceIterator &rhs) + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- +} // namespace portaudio + + diff --git a/bindings/cpp/source/portaudiocpp/SystemHostApiIterator.cxx b/bindings/cpp/source/portaudiocpp/SystemHostApiIterator.cxx new file mode 100644 index 0000000..f34ca40 --- /dev/null +++ b/bindings/cpp/source/portaudiocpp/SystemHostApiIterator.cxx @@ -0,0 +1,59 @@ +#include "portaudiocpp/SystemHostApiIterator.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + HostApi &System::HostApiIterator::operator*() const + { + return **ptr_; + } + + HostApi *System::HostApiIterator::operator->() const + { + return &**this; + } + + // ----------------------------------------------------------------------------------- + + System::HostApiIterator &System::HostApiIterator::operator++() + { + ++ptr_; + return *this; + } + + System::HostApiIterator System::HostApiIterator::operator++(int) + { + System::HostApiIterator prev = *this; + ++*this; + return prev; + } + + System::HostApiIterator &System::HostApiIterator::operator--() + { + --ptr_; + return *this; + } + + System::HostApiIterator System::HostApiIterator::operator--(int) + { + System::HostApiIterator prev = *this; + --*this; + return prev; + } + + // ----------------------------------------------------------------------------------- + + bool System::HostApiIterator::operator==(const System::HostApiIterator &rhs) + { + return (ptr_ == rhs.ptr_); + } + + bool System::HostApiIterator::operator!=(const System::HostApiIterator &rhs) + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- +} // namespace portaudio + diff --git a/build/dev-cpp/Makefile-dll b/build/dev-cpp/Makefile-dll new file mode 100644 index 0000000..856af63 --- /dev/null +++ b/build/dev-cpp/Makefile-dll @@ -0,0 +1,78 @@ +# Project: portaudio-dll +# Makefile created by Dev-C++ 4.9.8.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = +OBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES) +LINKOBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES) +LIBS = -L"C:/Dev-CPP/lib" -fmessage-length=0 --no-export-all-symbols --add-stdcall-alias ../../../asiosdk2/asiosdk2.a -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lwinmm -O3 -s +INCS = -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common" +CXXINCS = -I"C:/Dev-CPP/include/c++" -I"C:/Dev-CPP/include/c++/mingw32" -I"C:/Dev-CPP/include/c++/backward" -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common" +BIN = portaudio-dll.dll +CXXFLAGS = $(CXXINCS)-O3 -fmessage-length=0 -Wall +CFLAGS = $(INCS)-DBUILDING_DLL=1 -O3 -fmessage-length=0 -Wall + +.PHONY: all all-before all-after clean clean-custom + +all: all-before portaudio-dll.dll all-after + + +clean: clean-custom + rm -f $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=libportaudio-dll.def +STATICLIB=libportaudio-dll.a + +$(BIN): $(LINKOBJ) + $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + +./pa_skeleton.o: ../../pa_common/pa_skeleton.c + $(CPP) -c ../../pa_common/pa_skeleton.c -o ./pa_skeleton.o $(CXXFLAGS) + +./pa_stream.o: ../../pa_common/pa_stream.c + $(CPP) -c ../../pa_common/pa_stream.c -o ./pa_stream.o $(CXXFLAGS) + +./pa_trace.o: ../../pa_common/pa_trace.c + $(CPP) -c ../../pa_common/pa_trace.c -o ./pa_trace.o $(CXXFLAGS) + +./pa_allocation.o: ../../pa_common/pa_allocation.c + $(CPP) -c ../../pa_common/pa_allocation.c -o ./pa_allocation.o $(CXXFLAGS) + +./pa_converters.o: ../../pa_common/pa_converters.c + $(CPP) -c ../../pa_common/pa_converters.c -o ./pa_converters.o $(CXXFLAGS) + +./pa_cpuload.o: ../../pa_common/pa_cpuload.c + $(CPP) -c ../../pa_common/pa_cpuload.c -o ./pa_cpuload.o $(CXXFLAGS) + +./pa_dither.o: ../../pa_common/pa_dither.c + $(CPP) -c ../../pa_common/pa_dither.c -o ./pa_dither.o $(CXXFLAGS) + +./pa_front.o: ../../pa_common/pa_front.c + $(CPP) -c ../../pa_common/pa_front.c -o ./pa_front.o $(CXXFLAGS) + +./pa_process.o: ../../pa_common/pa_process.c + $(CPP) -c ../../pa_common/pa_process.c -o ./pa_process.o $(CXXFLAGS) + +./pa_asio.o: ../../pa_asio/pa_asio.cpp + $(CPP) -c ../../pa_asio/pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS) + +./pa_win_util.o: ../pa_win_util.c + $(CPP) -c ../pa_win_util.c -o ./pa_win_util.o $(CXXFLAGS) + +./pa_win_hostapis.o: ../pa_win_hostapis.c + $(CPP) -c ../pa_win_hostapis.c -o ./pa_win_hostapis.o $(CXXFLAGS) + +./pa_win_ds.o: ../../pa_win_ds/pa_win_ds.c + $(CPP) -c ../../pa_win_ds/pa_win_ds.c -o ./pa_win_ds.o $(CXXFLAGS) + +./dsound_wrapper.o: ../../pa_win_ds/dsound_wrapper.c + $(CPP) -c ../../pa_win_ds/dsound_wrapper.c -o ./dsound_wrapper.o $(CXXFLAGS) + +./pa_win_wmme.o: ../../pa_win_wmme/pa_win_wmme.c + $(CPP) -c ../../pa_win_wmme/pa_win_wmme.c -o ./pa_win_wmme.o $(CXXFLAGS) + +./iasiothiscallresolver.o: ../../pa_asio/iasiothiscallresolver.cpp + $(CPP) -c ../../pa_asio/iasiothiscallresolver.cpp -o ./iasiothiscallresolver.o $(CXXFLAGS) diff --git a/build/dev-cpp/Makefile-static b/build/dev-cpp/Makefile-static new file mode 100644 index 0000000..2a1647d --- /dev/null +++ b/build/dev-cpp/Makefile-static @@ -0,0 +1,75 @@ +# Project: portaudio-static +# Makefile created by Dev-C++ 4.9.8.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = +OBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES) +LINKOBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES) +LIBS = -L"C:/Dev-CPP/lib" -fmessage-length=0 -O3 -s +INCS = -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common" +CXXINCS = -I"C:/Dev-CPP/include/c++" -I"C:/Dev-CPP/include/c++/mingw32" -I"C:/Dev-CPP/include/c++/backward" -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common" +BIN = portaudio-static.a +CXXFLAGS = $(CXXINCS)-O3 -fmessage-length=0 -Wall +CFLAGS = $(INCS)-O3 -fmessage-length=0 -Wall + +.PHONY: all all-before all-after clean clean-custom + +all: all-before portaudio-static.a all-after + + +clean: clean-custom + rm -f $(OBJ) $(BIN) + +$(BIN): $(LINKOBJ) + ar r $(BIN) $(LINKOBJ) + ranlib $(BIN) + +./pa_skeleton.o: ../../pa_common/pa_skeleton.c + $(CPP) -c ../../pa_common/pa_skeleton.c -o ./pa_skeleton.o $(CXXFLAGS) + +./pa_stream.o: ../../pa_common/pa_stream.c + $(CPP) -c ../../pa_common/pa_stream.c -o ./pa_stream.o $(CXXFLAGS) + +./pa_trace.o: ../../pa_common/pa_trace.c + $(CPP) -c ../../pa_common/pa_trace.c -o ./pa_trace.o $(CXXFLAGS) + +./pa_allocation.o: ../../pa_common/pa_allocation.c + $(CPP) -c ../../pa_common/pa_allocation.c -o ./pa_allocation.o $(CXXFLAGS) + +./pa_converters.o: ../../pa_common/pa_converters.c + $(CPP) -c ../../pa_common/pa_converters.c -o ./pa_converters.o $(CXXFLAGS) + +./pa_cpuload.o: ../../pa_common/pa_cpuload.c + $(CPP) -c ../../pa_common/pa_cpuload.c -o ./pa_cpuload.o $(CXXFLAGS) + +./pa_dither.o: ../../pa_common/pa_dither.c + $(CPP) -c ../../pa_common/pa_dither.c -o ./pa_dither.o $(CXXFLAGS) + +./pa_front.o: ../../pa_common/pa_front.c + $(CPP) -c ../../pa_common/pa_front.c -o ./pa_front.o $(CXXFLAGS) + +./pa_process.o: ../../pa_common/pa_process.c + $(CPP) -c ../../pa_common/pa_process.c -o ./pa_process.o $(CXXFLAGS) + +./pa_asio.o: ../../pa_asio/pa_asio.cpp + $(CPP) -c ../../pa_asio/pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS) + +./pa_win_util.o: ../pa_win_util.c + $(CPP) -c ../pa_win_util.c -o ./pa_win_util.o $(CXXFLAGS) + +./pa_win_hostapis.o: ../pa_win_hostapis.c + $(CPP) -c ../pa_win_hostapis.c -o ./pa_win_hostapis.o $(CXXFLAGS) + +./pa_win_ds.o: ../../pa_win_ds/pa_win_ds.c + $(CPP) -c ../../pa_win_ds/pa_win_ds.c -o ./pa_win_ds.o $(CXXFLAGS) + +./dsound_wrapper.o: ../../pa_win_ds/dsound_wrapper.c + $(CPP) -c ../../pa_win_ds/dsound_wrapper.c -o ./dsound_wrapper.o $(CXXFLAGS) + +./pa_win_wmme.o: ../../pa_win_wmme/pa_win_wmme.c + $(CPP) -c ../../pa_win_wmme/pa_win_wmme.c -o ./pa_win_wmme.o $(CXXFLAGS) + +./iasiothiscallresolver.o: ../../pa_asio/iasiothiscallresolver.cpp + $(CPP) -c ../../pa_asio/iasiothiscallresolver.cpp -o ./iasiothiscallresolver.o $(CXXFLAGS) diff --git a/build/dev-cpp/portaudio-dll.dev b/build/dev-cpp/portaudio-dll.dev new file mode 100644 index 0000000..086e109 --- /dev/null +++ b/build/dev-cpp/portaudio-dll.dev @@ -0,0 +1,209 @@ +[Project] +FileName=portaudio-dll.dev +Name=portaudio-dll +UnitCount=16 +Type=3 +Ver=1 +ObjFiles= +Includes=..\..\..\asiosdk2;..\..\..\asiosdk2\common;..\..\..\asiosdk2\host;..\..\..\asiosdk2\host\pc;..\..\pa_common +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-DBUILDING_DLL=1_@@_-O3_@@_ +CppCompiler=-O3_@@_ +Linker=--no-export-all-symbols --add-stdcall-alias_@@_../../../asiosdk2/asiosdk2.a_@@_-lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lwinmm_@@_-O3 -s_@@_ +IsCpp=1 +Icon= +ExeOutput=. +ObjectOutput=. +OverrideOutput=0 +OverrideOutputName=portaudio.a +HostApplication= +Folders= +CommandLine= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000 +UseCustomMakefile=0 +CustomMakefile= + +[Unit1] +FileName=..\..\pa_common\pa_skeleton.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_skeleton.c -o ./pa_skeleton.o $(CFLAGS) + +[Unit2] +FileName=..\..\pa_common\pa_stream.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_stream.c -o ./pa_stream.o $(CFLAGS) + +[Unit3] +FileName=..\..\pa_common\pa_trace.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_trace.c -o ./pa_trace.o $(CFLAGS) + +[Unit4] +FileName=..\..\pa_common\pa_allocation.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_allocation.c -o ./pa_allocation.o $(CFLAGS) + +[Unit5] +FileName=..\..\pa_common\pa_converters.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_converters.c -o ./pa_converters.o $(CFLAGS) + +[Unit6] +FileName=..\..\pa_common\pa_cpuload.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_cpuload.c -o ./pa_cpuload.o $(CFLAGS) + +[Unit7] +FileName=..\..\pa_common\pa_dither.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_dither.c -o ./pa_dither.o $(CFLAGS) + +[Unit8] +FileName=..\..\pa_common\pa_front.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_front.c -o ./pa_front.o $(CFLAGS) + +[Unit9] +FileName=..\..\pa_common\pa_process.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_process.c -o ./pa_process.o $(CFLAGS) + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit10] +FileName=..\..\pa_asio\pa_asio.cpp +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CPP) -c pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS) + +[Unit11] +FileName=..\pa_win_util.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_win_util.c -o ./pa_win_util.o $(CFLAGS) + +[Unit12] +FileName=..\pa_win_hostapis.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_win_hostapis.c -o ./pa_win_hostapis.o $(CFLAGS) + +[Unit13] +FileName=..\..\pa_win_ds\pa_win_ds.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_win_ds.c -o ./pa_win_ds.o $(CFLAGS) + +[Unit14] +FileName=..\..\pa_win_ds\dsound_wrapper.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c dsound_wrapper.c -o ./dsound_wrapper.o $(CFLAGS) + +[Unit15] +FileName=..\..\pa_win_wmme\pa_win_wmme.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_win_wmme.c -o ./pa_win_wmme.o $(CFLAGS) + +[Unit16] +FileName=..\..\pa_asio\iasiothiscallresolver.cpp +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/build/dev-cpp/portaudio-static.dev b/build/dev-cpp/portaudio-static.dev new file mode 100644 index 0000000..2aae584 --- /dev/null +++ b/build/dev-cpp/portaudio-static.dev @@ -0,0 +1,209 @@ +[Project] +FileName=portaudio-static.dev +Name=portaudio-static +UnitCount=16 +Type=2 +Ver=1 +ObjFiles= +Includes=..\..\..\asiosdk2;..\..\..\asiosdk2\common;..\..\..\asiosdk2\host;..\..\..\asiosdk2\host\pc;..\..\pa_common +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler=-O3_@@_ +CppCompiler=-O3_@@_ +Linker=-O3 -s_@@_ +IsCpp=1 +Icon= +ExeOutput=. +ObjectOutput=. +OverrideOutput=0 +OverrideOutputName=portaudio.a +HostApplication= +Folders= +CommandLine= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000 +UseCustomMakefile=0 +CustomMakefile= + +[Unit1] +FileName=..\..\pa_common\pa_skeleton.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_skeleton.c -o ./pa_skeleton.o $(CFLAGS) + +[Unit2] +FileName=..\..\pa_common\pa_stream.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_stream.c -o ./pa_stream.o $(CFLAGS) + +[Unit3] +FileName=..\..\pa_common\pa_trace.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_trace.c -o ./pa_trace.o $(CFLAGS) + +[Unit4] +FileName=..\..\pa_common\pa_allocation.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_allocation.c -o ./pa_allocation.o $(CFLAGS) + +[Unit5] +FileName=..\..\pa_common\pa_converters.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_converters.c -o ./pa_converters.o $(CFLAGS) + +[Unit6] +FileName=..\..\pa_common\pa_cpuload.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_cpuload.c -o ./pa_cpuload.o $(CFLAGS) + +[Unit7] +FileName=..\..\pa_common\pa_dither.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_dither.c -o ./pa_dither.o $(CFLAGS) + +[Unit8] +FileName=..\..\pa_common\pa_front.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_front.c -o ./pa_front.o $(CFLAGS) + +[Unit9] +FileName=..\..\pa_common\pa_process.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_process.c -o ./pa_process.o $(CFLAGS) + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit10] +FileName=..\..\pa_asio\pa_asio.cpp +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CPP) -c pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS) + +[Unit11] +FileName=..\..\pa_win\pa_win_util.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_win_util.c -o ./pa_win_util.o $(CFLAGS) + +[Unit12] +FileName=..\..\pa_win\pa_win_hostapis.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_win_hostapis.c -o ./pa_win_hostapis.o $(CFLAGS) + +[Unit13] +FileName=..\..\pa_win_ds\pa_win_ds.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_win_ds.c -o ./pa_win_ds.o $(CFLAGS) + +[Unit14] +FileName=..\..\pa_win_ds\dsound_wrapper.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c dsound_wrapper.c -o ./dsound_wrapper.o $(CFLAGS) + +[Unit15] +FileName=..\..\pa_win_wmme\pa_win_wmme.c +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd=$(CC) -c pa_win_wmme.c -o ./pa_win_wmme.o $(CFLAGS) + +[Unit16] +FileName=..\..\pa_asio\iasiothiscallresolver.cpp +CompileCpp=1 +Folder=portaudio +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/build/dev-cpp/readme.txt b/build/dev-cpp/readme.txt new file mode 100644 index 0000000..07108a7 --- /dev/null +++ b/build/dev-cpp/readme.txt @@ -0,0 +1,23 @@ +From: "Peter L Jones" +Sent: Wednesday, September 17, 2003 5:18 AM +Subject: Dev-C++ project files + +I attach two project files intended for portaudio/pa_win/dev-cpp (i.e. in +parallel with the msvc directory), if you want them. One is for a static +library build and one for a DLL. I've used the static library (in building +a single monolithic DLL) but I can't guarantee the DLL version will build a +working library (I think it's mostly there, though!). + +I also attach the resulting makefiles, which may be of use to other MinGW +users. + +They're rooted in the directory given above and drop their object and +library files in the same place. They assume the asiosdk2 files are in the +same directory as portaudio/ in a sub-directory called asiosdk2/. Oh! The +DLL is built against a static asiosdk2.a library... maybe not the best way +to do it... I ought to figure out how to link against a "home made" dll in +Dev-C++, I guess ;-) + +Cheers, + +-- Peter diff --git a/build/msvc/portaudio.def b/build/msvc/portaudio.def new file mode 100644 index 0000000..08929d6 --- /dev/null +++ b/build/msvc/portaudio.def @@ -0,0 +1,43 @@ +EXPORTS + +; +Pa_GetVersion @1 +Pa_GetVersionText @2 +Pa_GetErrorText @3 +Pa_Initialize @4 +Pa_Terminate @5 +Pa_GetHostApiCount @6 +Pa_GetDefaultHostApi @7 +Pa_GetHostApiInfo @8 +Pa_HostApiTypeIdToHostApiIndex @9 +Pa_HostApiDeviceIndexToDeviceIndex @10 +Pa_GetLastHostErrorInfo @11 +Pa_GetDeviceCount @12 +Pa_GetDefaultInputDevice @13 +Pa_GetDefaultOutputDevice @14 +Pa_GetDeviceInfo @15 +Pa_IsFormatSupported @16 +Pa_OpenStream @17 +Pa_OpenDefaultStream @18 +Pa_CloseStream @19 +Pa_SetStreamFinishedCallback @20 +Pa_StartStream @21 +Pa_StopStream @22 +Pa_AbortStream @23 +Pa_IsStreamStopped @24 +Pa_IsStreamActive @25 +Pa_GetStreamInfo @26 +Pa_GetStreamTime @27 +Pa_GetStreamCpuLoad @28 +Pa_ReadStream @29 +Pa_WriteStream @30 +Pa_GetStreamReadAvailable @31 +Pa_GetStreamWriteAvailable @32 +Pa_GetSampleSize @33 +Pa_Sleep @34 +PaAsio_GetAvailableLatencyValues @50 +PaAsio_ShowControlPanel @51 +PaUtil_InitializeX86PlainConverters @52 +PaAsio_GetInputChannelName @53 +PaAsio_GetOutputChannelName @54 +PaUtil_SetDebugPrintFunction @55 \ No newline at end of file diff --git a/build/msvc/portaudio.dsp b/build/msvc/portaudio.dsp new file mode 100644 index 0000000..bb2ce45 --- /dev/null +++ b/build/msvc/portaudio.dsp @@ -0,0 +1,269 @@ +# Microsoft Developer Studio Project File - Name="portaudio" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=portaudio - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "portaudio.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "portaudio.mak" CFG="portaudio - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "portaudio - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "portaudio - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "portaudio - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_x86" +# PROP BASE Intermediate_Dir "Release_x86" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_x86" +# PROP Intermediate_Dir "Release_x86" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\src\common" /I "..\..\include" /I ".\\" /I "..\..\src\os\win" /D "WIN32" /D "NDEBUG" /D "_USRDLL" /D "PA_ENABLE_DEBUG_OUTPUT" /D "_CRT_SECURE_NO_DEPRECATE" /D "PAWIN_USE_WDMKS_DEVICE_INFO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /dll /machine:I386 /out:"./Release_x86/portaudio_x86.dll" + +!ELSEIF "$(CFG)" == "portaudio - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_x86" +# PROP BASE Intermediate_Dir "Debug_x86" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_x86" +# PROP Intermediate_Dir "Debug_x86" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\src\common" /I "..\..\include" /I ".\\" /I "..\..\src\os\win" /D "WIN32" /D "_DEBUG" /D "_USRDLL" /D "PA_ENABLE_DEBUG_OUTPUT" /D "_CRT_SECURE_NO_DEPRECATE" /D "PAWIN_USE_WDMKS_DEVICE_INFO" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /dll /debug /machine:I386 /out:"./Debug_x86/portaudio_x86.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "portaudio - Win32 Release" +# Name "portaudio - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\src\common\pa_allocation.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_converters.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_cpuload.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_debugprint.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_dither.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_front.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_process.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_ringbuffer.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_skeleton.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\common\pa_stream.c +# End Source File +# End Group +# Begin Group "hostapi" + +# PROP Default_Filter "" +# Begin Group "ASIO" + +# PROP Default_Filter "" +# Begin Group "ASIOSDK" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\src\hostapi\asio\ASIOSDK\common\asio.cpp +# ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" +# End Source File +# Begin Source File + +SOURCE=..\..\src\hostapi\asio\ASIOSDK\host\ASIOConvertSamples.cpp +# ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" +# End Source File +# Begin Source File + +SOURCE=..\..\src\hostapi\asio\ASIOSDK\host\asiodrivers.cpp +# ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" +# End Source File +# Begin Source File + +SOURCE=..\..\src\hostapi\asio\ASIOSDK\host\pc\asiolist.cpp +# ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" +# End Source File +# Begin Source File + +SOURCE=..\..\src\hostapi\asio\ASIOSDK\common\combase.cpp +# ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" +# End Source File +# Begin Source File + +SOURCE=..\..\src\hostapi\asio\ASIOSDK\common\debugmessage.cpp +# ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" +# End Source File +# Begin Source File + +SOURCE=..\..\src\hostapi\asio\ASIOSDK\common\register.cpp +# ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\src\hostapi\asio\pa_asio.cpp +# ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" +# End Source File +# End Group +# Begin Group "dsound" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\src\hostapi\dsound\pa_win_ds.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\hostapi\dsound\pa_win_ds_dynlink.c +# End Source File +# End Group +# Begin Group "wmme" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\src\hostapi\wmme\pa_win_wmme.c +# End Source File +# End Group +# Begin Group "wasapi" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\src\hostapi\wasapi\pa_win_wasapi.cpp +# End Source File +# End Group +# Begin Group "wdm-ks" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\src\hostapi\wdmks\pa_win_wdmks.c +# End Source File +# End Group +# End Group +# Begin Group "os" + +# PROP Default_Filter "" +# Begin Group "win" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\src\os\win\pa_win_hostapis.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\os\win\pa_win_util.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\os\win\pa_win_waveformat.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\os\win\pa_win_wdmks_utils.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\os\win\pa_x86_plain_converters.c +# End Source File +# End Group +# End Group +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\portaudio.def +# End Source File +# End Group +# End Target +# End Project diff --git a/build/msvc/portaudio.dsw b/build/msvc/portaudio.dsw new file mode 100644 index 0000000..6af88f4 --- /dev/null +++ b/build/msvc/portaudio.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "portaudio"=".\portaudio.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/build/msvc/portaudio.sln b/build/msvc/portaudio.sln new file mode 100644 index 0000000..d4cc5dc --- /dev/null +++ b/build/msvc/portaudio.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portaudio", "portaudio.vcproj", "{0A18A071-125E-442F-AFF7-A3F68ABECF99}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.ActiveCfg = Debug|Win32 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.Build.0 = Debug|Win32 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.ActiveCfg = Debug|x64 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.Build.0 = Debug|x64 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.ActiveCfg = Release|Win32 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.Build.0 = Release|Win32 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.ActiveCfg = Release|x64 + {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/msvc/portaudio.vcproj b/build/msvc/portaudio.vcproj new file mode 100644 index 0000000..759f934 --- /dev/null +++ b/build/msvc/portaudio.vcproj @@ -0,0 +1,1512 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/msvc/readme.txt b/build/msvc/readme.txt new file mode 100644 index 0000000..5364797 --- /dev/null +++ b/build/msvc/readme.txt @@ -0,0 +1,80 @@ +Hello + + This is a small list of steps in order to build portaudio +(Currently v19-devel) into a VC6 DLL and lib file. +This DLL contains all 3 current win32 PA APIS (MM/DS/ASIO) + +1)Copy the source dirs that comes with the ASIO SDK inside src\hostapi\asio\ASIOSDK + so you should now have example: + + portaudio19svn\src\hostapi\asio\ASIOSDK\common + portaudio19svn\src\hostapi\asio\ASIOSDK\host + portaudio19svn\src\hostapi\asio\ASIOSDK\host\sample + portaudio19svn\src\hostapi\asio\ASIOSDK\host\pc + portaudio19svn\src\hostapi\asio\ASIOSDK\host\mac (not needed) + + You dont need "driver" + +2) + *If you have Visual Studio 6.0*, please make sure you have it updated with the latest (and final) + microsoft libraries for it, namely: + + Service pack 5: + Latest known URL: + http://msdn2.microsoft.com/en-us/vstudio/aa718363.aspx + Yes there EXISTS a service pack 6 , but the processor pack (below) isnt compatible with it. + + Processor Pack(only works with above SP5) + Latest known URL: + http://msdn2.microsoft.com/en-us/vstudio/Aa718349.aspx + This isnt absolutely required for portaudio, but if you plan on using SSE intrinsics and similar things. + Up to you to decide upon Service pack 5 or 6 depending on your need for intrinsics. + + Platform SDK (Feb 2003) : + Latest known URL: + http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm + (This will allow your code base to be x64 friendly, with correct defines + for LONG_PTR and such) + NOTE A) Yes you have to use IE activex scripts to install that - wont work in Firefox, you + may have to temporarily change tyour default browser(aint life unfair) + NOTE B) Dont forget to hit "Register PSDK Directories with Visual Studio". + you can make sure its right in VC6 if you open tools/options/directories/include files and you see SDK 2003 as the FIRST entry + (it must be the same for libs) + + DirectX 9.0 SDK Update - (Summer 2003) + Latest known URL: + http://www.microsoft.com/downloads/details.aspx?familyid=9216652f-51e0-402e-b7b5-feb68d00f298&displaylang=en + Again register the links in VC6, and check inside vc6 if headers are in second place right after SDk 2003 + + *If you have 7.0(VC.NET/2001) or 7.1(VC.2003) * + then I suggest you open portaudio.dsp (and convert if needed) + + *If you have Visual Studio 2005*, I suggest you open the portaudio.sln file + which contains 4 configurations. Win32/x64 in both Release and Debug variants + + hit compile and hope for the best. + +3)Now in any project, in which you require portaudio, + you can just link with portaudio_x86.lib, (or _x64) and of course include the + relevant headers + (portaudio.h, and/or pa_asio.h , pa_x86_plain_converters.h) See (*) + +4) Your new exe should now use portaudio_xXX.dll. + + +Have fun! + +(*): you may want to add/remove some DLL entry points. +Right now those 6 entries are _not_ from portaudio.h + +(from portaudio.def) +(...) +PaAsio_GetAvailableLatencyValues @50 +PaAsio_ShowControlPanel @51 +PaUtil_InitializeX86PlainConverters @52 +PaAsio_GetInputChannelName @53 +PaAsio_GetOutputChannelName @54 +PaUtil_SetLogPrintFunction @55 + +----- +David Viens, davidv@plogue.com \ No newline at end of file diff --git a/build/scons/SConscript_common b/build/scons/SConscript_common new file mode 100644 index 0000000..eaf4e3c --- /dev/null +++ b/build/scons/SConscript_common @@ -0,0 +1,30 @@ +import os.path, sys + +class ConfigurationError(Exception): + def __init__(self, reason): + Exception.__init__(self, "Configuration failed: %s" % reason) + +env = Environment() + +# sunos, aix, hpux, irix, sunos appear to be platforms known by SCons, assuming they're POSIX compliant +Posix = ("linux", "darwin", "sunos", "aix", "hpux", "irix", "sunos", "netbsd") +Windows = ("win32", "cygwin") + +if env["PLATFORM"] == "posix": + if sys.platform[:5] == "linux": + Platform = "linux" + elif sys.platform[:6] == "netbsd": + Platform = "netbsd" + else: + raise ConfigurationError("Unknown platform %s" % sys.platform) +else: + if not env["PLATFORM"] in ("win32", "cygwin") + Posix: + raise ConfigurationError("Unknown platform %s" % env["PLATFORM"]) + Platform = env["PLATFORM"] + +# Inspired by the versioning scheme followed by Qt, it seems sensible enough. There are three components: major, minor +# and micro. Major changes with each subtraction from the API (backward-incompatible, i.e. V19 vs. V18), minor changes +# with each addition to the API (backward-compatible), micro changes with each revision of the source code. +ApiVer = "2.0.0" + +Export("Platform", "Posix", "ConfigurationError", "ApiVer") diff --git a/build/scons/SConscript_opts b/build/scons/SConscript_opts new file mode 100644 index 0000000..6a4b0a9 --- /dev/null +++ b/build/scons/SConscript_opts @@ -0,0 +1,91 @@ +import os.path, sys + +def _PackageOption(pkgName, default=1): + """ Allow user to choose whether a package should be used if available. This results in a commandline option use, + where Pkgname is the name of the package with a capitalized first letter. + @param pkgName: Name of package. + @param default: The default value for this option ("yes"/"no"). + """ + return BoolOption("use%s" % pkgName[0].upper() + pkgName[1:], "use %s if available" % (pkgName), default) + +def _BoolOption(opt, explanation, default=1): + """ Allow user to enable/disable a certain option. This results in a commandline option enable