aboutsummaryrefslogtreecommitdiff
path: root/pd/portaudio
diff options
context:
space:
mode:
authorGuenter Geiger <ggeiger@users.sourceforge.net>2002-07-29 17:06:19 +0000
committerGuenter Geiger <ggeiger@users.sourceforge.net>2002-07-29 17:06:19 +0000
commit57045df5fe3ec557e57dc7434ac1a07b5521bffc (patch)
tree7174058b41b73c808107c7090d9a4e93ee202341 /pd/portaudio
parentda38b3424229e59f956252c3d89895e43e84e278 (diff)
This commit was generated by cvs2svn to compensate for changes in r58,
which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=59
Diffstat (limited to 'pd/portaudio')
-rw-r--r--pd/portaudio/LICENSE.txt65
-rw-r--r--pd/portaudio/MSP-README.txt3
-rw-r--r--pd/portaudio/README.txt81
-rw-r--r--pd/portaudio/pa_asio/pa_asio.cpp2998
-rw-r--r--pd/portaudio/pa_common/pa_convert.c402
-rw-r--r--pd/portaudio/pa_common/pa_host.h185
-rw-r--r--pd/portaudio/pa_common/pa_lib.c806
-rw-r--r--pd/portaudio/pa_common/pa_trace.c83
-rw-r--r--pd/portaudio/pa_common/pa_trace.h67
-rw-r--r--pd/portaudio/pa_common/portaudio.h463
-rw-r--r--pd/portaudio/pa_mac_core/notes.txt34
-rw-r--r--pd/portaudio/pa_mac_core/pa_mac_core.c1261
-rw-r--r--pd/portaudio/pablio/README.txt39
-rw-r--r--pd/portaudio/pablio/pablio.c307
-rw-r--r--pd/portaudio/pablio/pablio.def35
-rw-r--r--pd/portaudio/pablio/pablio.h108
-rw-r--r--pd/portaudio/pablio/pablio_pd.c335
-rw-r--r--pd/portaudio/pablio/pablio_pd.h110
-rw-r--r--pd/portaudio/pablio/ringbuffer.c199
-rw-r--r--pd/portaudio/pablio/ringbuffer.h101
-rw-r--r--pd/portaudio/pablio/ringbuffer_pd.c214
-rw-r--r--pd/portaudio/pablio/test_rw.c99
-rw-r--r--pd/portaudio/pablio/test_rw_echo.c123
-rw-r--r--pd/portaudio/pablio/test_w_saw.c108
-rw-r--r--pd/portaudio/pablio/test_w_saw8.c106
-rw-r--r--pd/portaudio/pablio/test_w_saw_pd.c108
-rw-r--r--pd/portaudio/portmidi-macosx/Makefile24
-rw-r--r--pd/portaudio/portmidi-macosx/README12
-rw-r--r--pd/portaudio/portmidi-macosx/pmdarwin.c36
-rw-r--r--pd/portaudio/portmidi-macosx/pminternal.h100
-rw-r--r--pd/portaudio/portmidi-macosx/pmmacosx.c336
-rw-r--r--pd/portaudio/portmidi-macosx/pmmacosx.h4
-rw-r--r--pd/portaudio/portmidi-macosx/pmtestbin0 -> 24685 bytes
-rw-r--r--pd/portaudio/portmidi-macosx/pmtest.c136
-rw-r--r--pd/portaudio/portmidi-macosx/pmutil.c86
-rw-r--r--pd/portaudio/portmidi-macosx/pmutil.h44
-rw-r--r--pd/portaudio/portmidi-macosx/portmidi.c358
-rw-r--r--pd/portaudio/portmidi-macosx/portmidi.h338
-rw-r--r--pd/portaudio/portmidi-macosx/porttime.h30
-rw-r--r--pd/portaudio/portmidi-macosx/ptdarwin.c58
40 files changed, 10002 insertions, 0 deletions
diff --git a/pd/portaudio/LICENSE.txt b/pd/portaudio/LICENSE.txt
new file mode 100644
index 00000000..105da3f7
--- /dev/null
+++ b/pd/portaudio/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/
+ * <platform> Implementation
+ * Copyright (c) 1999-2000 <author(s)>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */ \ No newline at end of file
diff --git a/pd/portaudio/MSP-README.txt b/pd/portaudio/MSP-README.txt
new file mode 100644
index 00000000..e29de09f
--- /dev/null
+++ b/pd/portaudio/MSP-README.txt
@@ -0,0 +1,3 @@
+This is not the full distribution, just what's needed to get Pd running
+on Mac OSX and ASIO (Windows.) I changed some code in pablio.c as marked.
+-MSP
diff --git a/pd/portaudio/README.txt b/pd/portaudio/README.txt
new file mode 100644
index 00000000..d1e5d7d6
--- /dev/null
+++ b/pd/portaudio/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
diff --git a/pd/portaudio/pa_asio/pa_asio.cpp b/pd/portaudio/pa_asio/pa_asio.cpp
new file mode 100644
index 00000000..baed8ed4
--- /dev/null
+++ b/pd/portaudio/pa_asio/pa_asio.cpp
@@ -0,0 +1,2998 @@
+/*
+ * $Id: pa_asio.cpp,v 1.7 2002/04/30 12:33:04 stephane Exp $
+ * Portable Audio I/O Library for ASIO Drivers
+ *
+ * Author: Stephane Letz
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 2000-2001 Stephane Letz, 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
+
+ 08-03-01 First version : Stephane Letz
+ 08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk
+ 08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz
+ 08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz
+ 08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil
+ 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
+ 10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that
+ 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
+ 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 <Devices.h> and <Timer.h> : 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 :
+
+ - Check Pa_StopSteam and Pa_AbortStream
+ - Optimization for Input only or Ouput only (really necessary ??)
+*/
+
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+#include "asiosys.h"
+#include "asio.h"
+#include "asiodrivers.h"
+
+
+#if MAC
+#include <Devices.h>
+#include <Timer.h>
+#include <Math64.h>
+#else
+#include <math.h>
+#include <windows.h>
+#include <mmsystem.h>
+#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;
+
+
+//----------------------------------------------------------
+#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
+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 );
+
+static void Pa_ASIO_Convert_Inter_Input(
+ ASIOBufferInfo* nativeBuffer,
+ void* inputBuffer,
+ long NumInputChannels,
+ long NumOuputChannels,
+ long framePerBuffer,
+ long hostFrameOffset,
+ long userFrameOffset,
+ ASIOSampleType nativeFormat,
+ PaSampleFormat paFormat,
+ PaStreamFlags flags,
+ long index);
+
+static void Pa_ASIO_Convert_Inter_Output(
+ ASIOBufferInfo* nativeBuffer,
+ void* outputBuffer,
+ long NumInputChannels,
+ long NumOuputChannels,
+ long framePerBuffer,
+ long hostFrameOffset,
+ long userFrameOffset,
+ ASIOSampleType nativeFormat,
+ PaSampleFormat paFormat,
+ PaStreamFlags flags,
+ long index);
+
+static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
+ ASIOSampleType nativeFormat,
+ long NumInputChannels,
+ long NumOuputChannels,
+ long index,
+ long hostFrameOffset,
+ long 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();
+
+// Some external references
+extern AsioDrivers* asioDrivers ;
+bool loadAsioDriver(char *name);
+unsigned long get_sys_reference_time();
+
+
+/************************************************************************************/
+/****************** 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)<MIN_INT16)?MIN_INT16:(((v)>MAX_INT16)?MAX_INT16:(v)))
+#define ClipChar(v) (((v)<MIN_INT8)?MIN_INT8:(((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
+
+
+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);}
+
+// 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 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);
+ /* check memory */
+ if(!names[i]) return paInsufficientMemory;
+ }
+
+ /* MUST BE CHECKED : to force fragments loading on Mac */
+ Pa_ASIO_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 ( !Pa_ASIO_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[sNumDevices].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));
+ /* check memory */
+ if (!sampleRates) {
+ ASIOExit();
+ return paInsufficientMemory;
+ }
+ 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 */
+ 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:
+static 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
+
+
+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;
+ 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<<DITHER_BITS)-1))
+inline static long Pa_TriangularDither( void )
+{
+ static unsigned long previous = 0;
+ static unsigned long randSeed1 = 22222;
+ static unsigned long randSeed2 = 5555555;
+ long current, highPass;
+/* Generate two random numbers. */
+ randSeed1 = (randSeed1 * 196314165) + 907633515;
+ randSeed2 = (randSeed2 * 196314165) + 907633515;
+/* Generate triangular distribution about 0. */
+ current = (((long)randSeed1)>>(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
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+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;
+
+ for( j=0; j<NumInputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapShort(temp);
+ *userBufPtr = (1.0f / MAX_INT16_FP) * temp;
+ userBufPtr += NumInputChannels;
+ }
+ }
+
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+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;
+
+ for( j=0; j<NumInputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (1.0f / MAX_INT32_FP) * temp;
+ userBufPtr += NumInputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+// MUST BE TESTED
+static void Input_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+{
+ unsigned long temp;
+ int i,j;
+
+ for( j=0; j<NumInputChannels; j++ ) {
+ unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (float)temp;
+ userBufPtr += NumInputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Input_Int16_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+{
+ long temp;
+ int i,j;
+
+ for( j=0; j<NumInputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapShort(temp);
+ *userBufPtr = temp<<16;
+ userBufPtr += NumInputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Input_Int32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+{
+ long temp;
+ int i,j;
+
+ for( j=0; j<NumInputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = temp;
+ userBufPtr += NumInputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+// MUST BE TESTED
+static void Input_Float32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+{
+ unsigned long temp;
+ int i,j;
+
+ for( j=0; j<NumInputChannels; j++ ) {
+ unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (long)((float)temp * MAX_INT32_FP); // Is temp a value between -1.0 and 1.0 ??
+ userBufPtr += NumInputChannels;
+ }
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Input_Int16_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+{
+ long temp;
+ int i,j;
+
+ for( j=0; j<NumInputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapShort(temp);
+ *userBufPtr = (short)temp;
+ userBufPtr += NumInputChannels;
+ }
+ }
+}
+
+ //-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Input_Int32_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<NumInputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (short)(temp>>16);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+ else
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ temp = (temp >> 1) + Pa_TriangularDither();
+ temp = temp >> 15;
+ temp = (short) ClipShort(temp);
+ *userBufPtr = (short)temp;
+ userBufPtr += NumInputChannels;
+ }
+ }
+
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+// 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)
+{
+ unsigned long temp;
+ int i,j;
+
+ if( flags & paDitherOff )
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (short)((float)temp * MAX_INT16_FP); // Is temp a value between -1.0 and 1.0 ??
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+ else
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ float dither = Pa_TriangularDither()*DITHER_SCALE;
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ temp = (short)(((float)temp * MAX_INT16_FP) + dither);
+ temp = ClipShort(temp);
+ *userBufPtr = (short)temp;
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Input_Int16_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<NumInputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapShort(temp);
+ *userBufPtr = (char)(temp>>8);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+ else
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapShort(temp);
+ temp += Pa_TriangularDither() >> 8;
+ temp = ClipShort(temp);
+ *userBufPtr = (char)(temp>>8);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static 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<NumInputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (char)(temp>>24);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+ else
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ temp = temp>>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
+
+static void Input_Float32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+{
+ unsigned long temp;
+ int i,j;
+
+ if( flags & paDitherOff )
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (char)((float)temp*MAX_INT8_FP); // Is temp a value between -1.0 and 1.0 ??
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+ else
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ float dither = Pa_TriangularDither()*DITHER_SCALE;
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ temp = (char)(((float)temp * MAX_INT8_FP) + dither);
+ temp = ClipChar(temp);
+ *userBufPtr = (char)temp;
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Input_Int16_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<NumInputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapShort(temp);
+ *userBufPtr = (unsigned char)((temp>>8) + 0x80);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+ else
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapShort(temp);
+ temp += Pa_TriangularDither() >> 8;
+ temp = ClipShort(temp);
+ *userBufPtr = (unsigned char)((temp>>8) + 0x80);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static 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<NumInputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (unsigned char)((temp>>24) + 0x80);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+ else
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ temp = temp>>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
+
+static void Input_Float32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+{
+ unsigned long temp;
+ int i,j;
+
+ if( flags & paDitherOff )
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ *userBufPtr = (unsigned char)(((float)temp*MAX_INT8_FP) + 0x80);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+ else
+ {
+ for( j=0; j<NumInputChannels; j++ ) {
+ unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ float dither = Pa_TriangularDither()*DITHER_SCALE;
+ temp = asioBufPtr[i];
+ if (swap) temp = SwapLong(temp);
+ temp = (char)(((float)temp * MAX_INT8_FP) + dither);
+ temp = ClipChar(temp);
+ *userBufPtr = (unsigned char)(temp + 0x80);
+ userBufPtr += NumInputChannels;
+ }
+ }
+ }
+}
+
+
+// OUPUT
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Output_Float32_Int16 (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;
+
+ if( flags & paDitherOff )
+ {
+ if( flags & paClipOff ) /* NOTHING */
+ {
+ for( j=0; j<NumOuputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = (short) (*userBufPtr * MAX_INT16_FP);
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = (short)temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+ }
+ else /* CLIP */
+ {
+ for( j=0; j<NumOuputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ temp = (long) (*userBufPtr * MAX_INT16_FP);
+ temp = ClipShort(temp);
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = (short)temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( j=0; j<NumOuputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ float dither = Pa_TriangularDither()*DITHER_SCALE;
+ temp = (long) ((*userBufPtr * MAX_INT16_FP) + dither);
+ temp = ClipShort(temp);
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = (short)temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Output_Float32_Int32 (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;
+
+ if( flags & paClipOff )
+ {
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = (long) (*userBufPtr * MAX_INT32_FP);
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+ }
+ else // CLIP *
+ {
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ float temp1 = *userBufPtr;
+ temp1 = ClipFloat(temp1);
+ temp = (long) (temp1*MAX_INT32_FP);
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+ }
+
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+// MUST BE TESTED
+
+ 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;
+
+ if( flags & paClipOff )
+ {
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = (long) *userBufPtr;
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = (float)temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+
+ }
+ else /* CLIP */
+ {
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ float temp1 = *userBufPtr;
+ temp1 = ClipFloat(temp1); // Is is necessary??
+ temp = (long) temp1;
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = (float)temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+ }
+
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Output_Int32_Int16(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;
+
+ if( flags & paDitherOff )
+ {
+ 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<framePerBuffer; i++ )
+ {
+ temp = (short) ((*userBufPtr) >> 16);
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = (short)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<framePerBuffer; i++ )
+ {
+ temp = (*userBufPtr >> 1) + Pa_TriangularDither();
+ temp = temp >> 15;
+ temp = (short) ClipShort(temp);
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = (short)temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+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;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = *userBufPtr;
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+// 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)
+{
+ long temp;
+ int i,j;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = *userBufPtr;
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT32_FP);
+ userBufPtr += NumOuputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+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;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = *userBufPtr;
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = (short)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)
+{
+ long temp;
+ int i,j;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = (*userBufPtr)<<16;
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+// 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)
+{
+ long temp;
+ int i,j;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = *userBufPtr;
+ asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT16_FP);
+ userBufPtr += NumOuputChannels;
+ }
+ }
+}
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+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;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = (short)(*userBufPtr)<<8;
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = (short)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)
+{
+ long temp;
+ int i,j;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = (short)(*userBufPtr)<<24;
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+// 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)
+{
+ long temp;
+ int i,j;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = *userBufPtr;
+ asioBufPtr[i] = (long)(((float)temp) * (1.0f / MAX_INT8_FP));
+ userBufPtr += NumOuputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+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;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = ((short)((*userBufPtr) - 0x80)) << 8;
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = (short)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)
+{
+ long temp;
+ int i,j;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = ((short)((*userBufPtr) - 0x80)) << 24;
+ if (swap) temp = SwapLong(temp);
+ asioBufPtr[i] = temp;
+ userBufPtr += NumOuputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+// 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)
+{
+ long temp;
+ int i,j;
+
+ for (j= 0; j < NumOuputChannels; j++)
+ {
+ float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+ for( i=0; i<framePerBuffer; i++ )
+ {
+ temp = ((short)((*userBufPtr) - 0x80)) << 24;
+ asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT32_FP);
+ userBufPtr += NumOuputChannels;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset)
+{
+ int i,j;
+
+ for( j=0; j<NumOuputChannels; j++ ) {
+ short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ for (i= 0; i < frames; i++) {asioBufPtr[i] = 0; }
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset)
+{
+ int i,j;
+
+ for( j=0; j<NumOuputChannels; j++ ) {
+ long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ for (i= 0; i < frames; i++) {asioBufPtr[i] = 0; }
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Pa_ASIO_Adaptor_Init()
+{
+ if (asioDriverInfo.past->past_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 ??)
+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
+ 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;
+ }
+ }
+
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static 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;
+ }
+}
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static void Pa_ASIO_Callback_End()
+ {
+ /* Empty ASIO ouput : write offset */
+ asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0;
+ }
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+static 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 );
+ }
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------
+ static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
+ ASIOSampleType nativeFormat,
+ long NumInputChannels,
+ long NumOuputChannels,
+ long index,
+ long hostFrameOffset,
+ long 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;
+ }
+}
+
+
+//---------------------------------------------------------------------------------------
+static void Pa_ASIO_Convert_Inter_Input(
+ ASIOBufferInfo* nativeBuffer,
+ void* inputBuffer,
+ long NumInputChannels,
+ long NumOuputChannels,
+ long framePerBuffer,
+ long hostFrameOffset,
+ long userFrameOffset,
+ ASIOSampleType nativeFormat,
+ PaSampleFormat paFormat,
+ PaStreamFlags flags,
+ long 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_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap);
+ break;
+ case ASIOSTInt16MSB:
+ Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
+ break;
+ case ASIOSTInt32LSB:
+ Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
+ break;
+ case ASIOSTInt32MSB:
+ 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_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_Float32(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;
+ }
+ }
+}
+
+
+//---------------------------------------------------------------------------------------
+static void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer,
+ void* outputBuffer,
+ long NumInputChannels,
+ long NumOuputChannels,
+ long framePerBuffer,
+ long hostFrameOffset,
+ long userFrameOffset,
+ ASIOSampleType nativeFormat,
+ PaSampleFormat paFormat,
+ PaStreamFlags flags,
+ long 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 (!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;
+
+ 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? */
+ PaError err = (PaError) Pa_CountDevices();
+ return ( err < 0 ) ? err : paNoError;
+}
+
+/***********************************************************************/
+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; i<sNumDevices; i++ ){
+ dev = &sDevices[i].pad_Info;
+ rates = (double *) dev->sampleRates;
+ 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;
+
+ /* Check if a stream already runs */
+ if (asioDriverInfo.past != NULL) return paHostError;
+
+ /* 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/pd/portaudio/pa_common/pa_convert.c b/pd/portaudio/pa_common/pa_convert.c
new file mode 100644
index 00000000..377a9554
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_convert.c
@@ -0,0 +1,402 @@
+/*
+ * pa_conversions.c
+ * portaudio
+ *
+ * Created by Phil Burk on Mon Mar 18 2002.
+ *
+ */
+#include <stdio.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+
+#define CLIP( val, min, max ) { val = ((val) < (min)) ? min : (((val) < (max)) ? (max) : (val)); }
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ short samp = (short) (*sourceBuffer * (32767.0f));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_Clip(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ long samp = (long) (*sourceBuffer * (32767.0f));
+ CLIP( samp, -0x8000, 0x7FFF );
+ *targetBuffer = (short) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_ClipDither(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (32766.0f)) + dither;
+ long samp = (long) dithered;
+ CLIP( samp, -0x8000, 0x7FFF );
+ *targetBuffer = (short) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_Dither(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (32766.0f)) + dither;
+ *targetBuffer = (short) dithered;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+
+/*************************************************************************/
+static void PaConvert_Int16_Float32(
+ short *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = *sourceBuffer * (1.0f / 32768.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ char samp = (char) (*sourceBuffer * (127.0));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_Clip(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ long samp = *sourceBuffer * 127.0f;
+ CLIP( samp, -0x80, 0x7F );
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_ClipDither(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (126.0f)) + dither;
+ long samp = (long) dithered;
+ CLIP( samp, -0x80, 0x7F );
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_Dither(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE; //FIXME
+ float dithered = (*sourceBuffer * (126.0f)) + dither;
+ long samp = (long) dithered;
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Int8_Float32(
+ char *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = *sourceBuffer * (1.0f / 128.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_UInt8(
+ float *sourceBuffer, int sourceStride,
+ unsigned char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ unsigned char samp = 128 + (unsigned char) (*sourceBuffer * (127.0));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_UInt8_Float32(
+ unsigned char *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = (*sourceBuffer - 128) * (1.0f / 128.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static PortAudioConverter *PaConvert_SelectProc( PaSampleFormat sourceFormat,
+ PaSampleFormat targetFormat, int ifClip, int ifDither )
+{
+ PortAudioConverter *proc = NULL;
+ switch( sourceFormat )
+ {
+ case paUInt8:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_UInt8_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+ case paInt8:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_Int8_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+ case paInt16:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_Int16_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+ case paFloat32:
+ switch( targetFormat )
+ {
+ case paUInt8:
+ proc = (PortAudioConverter *) PaConvert_Float32_UInt8;
+ break;
+ case paInt8:
+ if( ifClip && ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_ClipDither;
+ else if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_Clip;
+ else if( ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_Dither;
+ else proc = (PortAudioConverter *) PaConvert_Float32_Int8;
+ break;
+ case paInt16:
+ if( ifClip && ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_ClipDither;
+ else if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_Clip;
+ else if( ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_Dither;
+ else proc = (PortAudioConverter *) PaConvert_Float32_Int16;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return proc;
+
+}
+
+/*************************************************************************/
+PaError PaConvert_SetupInput( internalPortAudioStream *past,
+ PaSampleFormat nativeInputSampleFormat )
+{
+ past->past_NativeInputSampleFormat = nativeInputSampleFormat;
+ past->past_InputConversionSourceStride = 1;
+ past->past_InputConversionTargetStride = 1;
+
+ if( nativeInputSampleFormat != past->past_InputSampleFormat )
+ {
+ int ifDither = (past->past_Flags & paDitherOff) == 0;
+ past->past_InputConversionProc = PaConvert_SelectProc( nativeInputSampleFormat,
+ past->past_InputSampleFormat, 0, ifDither );
+ if( past->past_InputConversionProc == NULL ) return paSampleFormatNotSupported;
+ }
+ else
+ {
+ past->past_InputConversionProc = NULL; /* no conversion necessary */
+ }
+
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaConvert_SetupOutput( internalPortAudioStream *past,
+ PaSampleFormat nativeOutputSampleFormat )
+{
+
+ past->past_NativeOutputSampleFormat = nativeOutputSampleFormat;
+ past->past_OutputConversionSourceStride = 1;
+ past->past_OutputConversionTargetStride = 1;
+
+ if( nativeOutputSampleFormat != past->past_OutputSampleFormat )
+ {
+ int ifDither = (past->past_Flags & paDitherOff) == 0;
+ int ifClip = (past->past_Flags & paClipOff) == 0;
+
+ past->past_OutputConversionProc = PaConvert_SelectProc( past->past_OutputSampleFormat,
+ nativeOutputSampleFormat, ifClip, ifDither );
+ if( past->past_OutputConversionProc == NULL ) return paSampleFormatNotSupported;
+ }
+ else
+ {
+ past->past_OutputConversionProc = NULL; /* no conversion necessary */
+ }
+
+ return paNoError;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from native format to user format,
+** call user code,
+** then convert output to native format.
+** Returns result from user callback.
+*/
+long PaConvert_Process( internalPortAudioStream *past,
+ void *nativeInputBuffer,
+ void *nativeOutputBuffer )
+{
+ int userResult;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+ /* Get native input data. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ if( past->past_InputSampleFormat == past->past_NativeInputSampleFormat )
+ {
+ /* Already in native format so just read directly from native buffer. */
+ inputBuffer = nativeInputBuffer;
+ }
+ else
+ {
+ inputBuffer = past->past_InputBuffer;
+ /* Convert input data to user format. */
+ (*past->past_InputConversionProc)(nativeInputBuffer, past->past_InputConversionSourceStride,
+ inputBuffer, past->past_InputConversionTargetStride,
+ past->past_FramesPerUserBuffer * past->past_NumInputChannels );
+ }
+ }
+
+ /* Are we doing output? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ outputBuffer = (past->past_OutputConversionProc == NULL) ?
+ nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ /* Advance frame counter for timestamp. */
+ past->past_FrameCount += past->past_FramesPerUserBuffer; // FIXME - should this be in here?
+
+ /* Convert to native format if necessary. */
+ if( (past->past_OutputConversionProc != NULL ) && (outputBuffer != NULL) )
+ {
+ (*past->past_OutputConversionProc)( outputBuffer, past->past_OutputConversionSourceStride,
+ nativeOutputBuffer, past->past_OutputConversionTargetStride,
+ past->past_FramesPerUserBuffer * past->past_NumOutputChannels );
+ }
+
+ return userResult;
+}
diff --git a/pd/portaudio/pa_common/pa_host.h b/pd/portaudio/pa_common/pa_host.h
new file mode 100644
index 00000000..d9cd71ab
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_host.h
@@ -0,0 +1,185 @@
+#ifndef PA_HOST_H
+#define PA_HOST_H
+
+/*
+ * $Id: pa_host.h,v 1.1.1.1 2002-07-29 17:06:18 ggeiger Exp $
+ * Host dependant internal API for PortAudio
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.softsynth.com/portaudio/
+ * DirectSound and Macintosh Implementation
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#ifndef SUPPORT_AUDIO_CAPTURE
+#define SUPPORT_AUDIO_CAPTURE (1)
+#endif
+
+#ifndef int32
+ typedef long int32;
+#endif
+#ifndef uint32
+ typedef unsigned long uint32;
+#endif
+#ifndef int16
+ typedef short int16;
+#endif
+#ifndef uint16
+ typedef unsigned short uint16;
+#endif
+
+/* Used to convert between various sample formats. */
+typedef void (PortAudioConverter)(
+ void *inputBuffer, int inputStride,
+ void *outputBuffer, int outputStride,
+ int numSamples );
+
+#define PA_MAGIC (0x18273645)
+
+/************************************************************************************/
+/****************** Structures ******************************************************/
+/************************************************************************************/
+
+typedef struct internalPortAudioStream
+{
+ uint32 past_Magic; /* ID for struct to catch bugs. */
+ /* 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_NativeInputSampleFormat;
+ PaSampleFormat past_InputSampleFormat;
+ PaSampleFormat past_NativeOutputSampleFormat;
+ 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;
+ /* Format Conversion */
+ /* These are setup by PaConversion_Setup() */
+ PortAudioConverter *past_InputConversionProc;
+ int past_InputConversionSourceStride;
+ int past_InputConversionTargetStride;
+ PortAudioConverter *past_OutputConversionProc;
+ int past_OutputConversionSourceStride;
+ int past_OutputConversionTargetStride;
+}
+internalPortAudioStream;
+
+/************************************************************************************/
+/******** These functions must be provided by a platform implementation. ************/
+/************************************************************************************/
+
+PaError PaHost_Init( void );
+PaError PaHost_Term( void );
+
+PaError PaHost_OpenStream( internalPortAudioStream *past );
+PaError PaHost_CloseStream( internalPortAudioStream *past );
+
+PaError PaHost_StartOutput( internalPortAudioStream *past );
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort );
+PaError PaHost_StartInput( internalPortAudioStream *past );
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort );
+PaError PaHost_StartEngine( internalPortAudioStream *past );
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort );
+PaError PaHost_StreamActive( internalPortAudioStream *past );
+
+void *PaHost_AllocateFastMemory( long numBytes );
+void PaHost_FreeFastMemory( void *addr, long numBytes );
+
+/* This only called if PA_VALIDATE_RATE IS CALLED. */
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+ double *closestFrameRatePtr );
+
+/**********************************************************************/
+/************ Common Utility Routines provided by PA ******************/
+/**********************************************************************/
+
+/* PaHost_IsInitialized() returns non-zero if PA is initialized, 0 otherwise */
+int PaHost_IsInitialized( void );
+
+internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream );
+
+int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable,
+ int numRates, double frameRate );
+
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer );
+
+/* Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit 1.31 fixed point value prior to >>15.
+** Range of output is +/- 65535
+** Multiply by PA_DITHER_SCALE to get a float between -2.0 and 2.0. */
+#define PA_DITHER_BITS (15)
+#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
+long PaConvert_TriangularDither( void );
+
+PaError PaConvert_SetupInput( internalPortAudioStream *past,
+ PaSampleFormat nativeInputSampleFormat );
+
+PaError PaConvert_SetupOutput( internalPortAudioStream *past,
+ PaSampleFormat nativeOutputSampleFormat );
+
+long PaConvert_Process( internalPortAudioStream *past,
+ void *nativeInputBuffer,
+ void *nativeOutputBuffer );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_HOST_H */
diff --git a/pd/portaudio/pa_common/pa_lib.c b/pd/portaudio/pa_common/pa_lib.c
new file mode 100644
index 00000000..ade2d82b
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_lib.c
@@ -0,0 +1,806 @@
+/*
+ * $Id: pa_lib.c,v 1.1.1.1 2002-07-29 17:06:18 ggeiger Exp $
+ * Portable Audio I/O Library
+ * Host Independant Layer
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Modification History:
+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
+ PLB20010820 - fix dither and shift for recording PaUInt8 format
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
+#ifdef _WIN32
+#ifndef __MWERKS__
+#include <memory.h>
+#endif /* __MWERKS__ */
+#else /* !_WIN32 */
+#include <memory.h>
+#endif /* _WIN32 */
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+/* The reason we might NOT want to validate the rate before opening the stream
+ * is because many DirectSound drivers lie about the rates they actually support.
+ */
+#define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */
+
+/*
+O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion
+*/
+
+#ifndef FALSE
+ #define FALSE (0)
+ #define TRUE (!FALSE)
+#endif
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
+
+static PaError Pa_KillStream( PortAudioStream *stream, int abort );
+
+/***********************************************************************/
+int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate )
+{
+ double err, minErr = allowableError;
+ int i, bestFit = -1;
+
+ for( i=0; i<numRates; i++ )
+ {
+ err = fabs( frameRate - rateTable[i] );
+ if( err < minErr )
+ {
+ minErr = err;
+ bestFit = i;
+ }
+ }
+ return bestFit;
+}
+
+/**************************************************************************
+** Make sure sample rate is legal and also convert to enumeration for driver.
+*/
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+ double *closestFrameRatePtr )
+{
+ long bestRateIndex;
+ const PaDeviceInfo *pdi;
+ pdi = Pa_GetDeviceInfo( id );
+ if( pdi == NULL )
+ {
+ return paInvalidDeviceId;
+ }
+
+ if( pdi->numSampleRates == -1 )
+ {
+ /* Is it out of range? */
+ if( (requestedFrameRate < pdi->sampleRates[0]) ||
+ (requestedFrameRate > pdi->sampleRates[1]) )
+ {
+ return paInvalidSampleRate;
+ }
+
+ *closestFrameRatePtr = requestedFrameRate;
+ }
+ else
+ {
+ bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate );
+ if( bestRateIndex < 0 ) return paInvalidSampleRate;
+ *closestFrameRatePtr = pdi->sampleRates[bestRateIndex];
+ }
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError Pa_OpenStream(
+ PortAudioStream** streamPtrPtr,
+ PaDeviceID inputDeviceID,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDeviceID,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ unsigned long streamFlags,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ internalPortAudioStream *past = NULL;
+ PaError result = paNoError;
+ int bitsPerInputSample;
+ int bitsPerOutputSample;
+ /* Print passed parameters. */
+ DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
+ streamPtrPtr, inputDeviceID, numInputChannels,
+ inputSampleFormat, inputDriverInfo ));
+ DBUG((" %d, %d, %d, %p, /* output */\n",
+ outputDeviceID, numOutputChannels,
+ outputSampleFormat, outputDriverInfo ));
+ DBUG((" %g, %d, %d, 0x%x, , %p )\n",
+ sampleRate, framesPerBuffer, numberOfBuffers,
+ streamFlags, userData ));
+
+ /* Check for parameter errors. */
+ if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag;
+ if( streamPtrPtr == NULL ) return paBadStreamPtr;
+ if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId;
+ if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) )
+ {
+ return paInvalidDeviceId;
+ }
+ if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount;
+
+#if SUPPORT_AUDIO_CAPTURE
+ if( inputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( inputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerInputSample = 8 * size;
+ if( (numInputChannels <= 0) ) return paInvalidChannelCount;
+ }
+#else
+ if( inputDeviceID >= 0 )
+ {
+ return paInvalidChannelCount;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ else
+ {
+ if( numInputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerInputSample = 0;
+ }
+
+ if( outputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( outputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerOutputSample = 8 * size;
+ if( (numOutputChannels <= 0) ) return paInvalidChannelCount;
+ }
+ else
+ {
+ if( numOutputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerOutputSample = 0;
+ }
+
+ if( callback == NULL ) return paNullCallback;
+
+ /* Allocate and clear stream structure. */
+ past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) );
+ if( past == NULL ) return paInsufficientMemory;
+ memset( past, 0, sizeof(internalPortAudioStream) );
+ AddTraceMessage("Pa_OpenStream: past", (long) past );
+
+ past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
+ past->past_FramesPerUserBuffer = framesPerBuffer;
+ past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() MUST CHECK FOR ZERO! */
+ past->past_Callback = callback;
+ past->past_UserData = userData;
+ past->past_OutputSampleFormat = outputSampleFormat;
+ past->past_InputSampleFormat = inputSampleFormat;
+ past->past_OutputDeviceID = outputDeviceID;
+ past->past_InputDeviceID = inputDeviceID;
+ past->past_NumInputChannels = numInputChannels;
+ past->past_NumOutputChannels = numOutputChannels;
+ past->past_Flags = streamFlags;
+
+ /* Check for absurd sample rates. */
+ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
+ {
+ result = paInvalidSampleRate;
+ goto cleanup;
+ }
+
+ /* Allocate buffers that may be used for format conversion from user to native buffers. */
+ if( numInputChannels > 0 )
+ {
+
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ /* Allocate single Input buffer for passing formatted samples to user callback. */
+ past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
+ past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
+ if( past->past_InputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_InputBuffer = NULL;
+ }
+
+ /* Allocate single Output buffer. */
+ if( numOutputChannels > 0 )
+ {
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8);
+ past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize);
+ if( past->past_OutputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_OutputBuffer = NULL;
+ }
+
+ result = PaHost_OpenStream( past );
+ if( result < 0 ) goto cleanup;
+
+ *streamPtrPtr = (void *) past;
+
+ return result;
+
+cleanup:
+ if( past != NULL ) Pa_CloseStream( past );
+ *streamPtrPtr = NULL;
+ return result;
+}
+
+
+/*************************************************************************/
+PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ return Pa_OpenStream(
+ stream,
+ ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
+ numInputChannels, sampleFormat, NULL,
+ ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
+ numOutputChannels, sampleFormat, NULL,
+ sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData );
+}
+
+/*************************************************************************/
+PaError Pa_CloseStream( PortAudioStream* stream)
+{
+ PaError result;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_CloseStream()\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ Pa_AbortStream( past );
+ result = PaHost_CloseStream( past );
+
+ if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize );
+ if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize );
+ PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) );
+
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StartStream( PortAudioStream *stream )
+{
+ PaError result = paHostError;
+ internalPortAudioStream *past;
+
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ past->past_FrameCount = 0.0;
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StartInput( past );
+ DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StartOutput( past );
+ DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ result = PaHost_StartEngine( past );
+ DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+
+ return paNoError;
+
+error:
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StopStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 0 );
+}
+
+/*************************************************************************/
+PaError Pa_AbortStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 1 );
+}
+
+/*************************************************************************/
+static PaError Pa_KillStream( PortAudioStream *stream, int abort )
+{
+ PaError result = paNoError;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_StopStream().\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) )
+ {
+ result = PaHost_StopEngine( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StopInput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StopOutput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+error:
+ past->past_Usage = 0;
+ past->past_IfLastExitValid = 0;
+
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StreamActive( PortAudioStream *stream )
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return PaHost_StreamActive( past );
+}
+
+/*************************************************************************/
+const char *Pa_GetErrorText( PaError errnum )
+{
+ const char *msg;
+
+ switch(errnum)
+ {
+ case paNoError: msg = "Success"; break;
+ case paHostError: msg = "Host error."; break;
+ case paInvalidChannelCount: msg = "Invalid number of channels."; break;
+ case paInvalidSampleRate: msg = "Invalid sample rate."; break;
+ case paInvalidDeviceId: msg = "Invalid device ID."; break;
+ case paInvalidFlag: msg = "Invalid flag."; break;
+ case paSampleFormatNotSupported: msg = "Sample format not supported"; break;
+ case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break;
+ case paInsufficientMemory: msg = "Insufficient memory."; break;
+ case paBufferTooBig: msg = "Buffer too big."; break;
+ case paBufferTooSmall: msg = "Buffer too small."; break;
+ case paNullCallback: msg = "No callback routine specified."; break;
+ case paBadStreamPtr: msg = "Invalid stream pointer."; break;
+ case paTimedOut : msg = "Wait Timed Out."; break;
+ case paInternalError: msg = "Internal PortAudio Error."; break;
+ case paDeviceUnavailable: msg = "Device Unavailable."; break;
+ default: msg = "Illegal error number."; break;
+ }
+ return msg;
+}
+
+/*
+ Get CPU Load as a fraction of total CPU time.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ The amount may vary depending on CPU load.
+ This function may be called from the callback function.
+*/
+double Pa_GetCPULoad( PortAudioStream* stream)
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return (double) paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return past->past_Usage;
+}
+
+/*************************************************************************/
+internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream )
+{
+ internalPortAudioStream* result = (internalPortAudioStream*) stream;
+
+ if( result == NULL || result->past_Magic != PA_MAGIC )
+ return NULL;
+ else
+ return result;
+}
+
+/*************************************************************
+** Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit integer prior to >>15.
+** Range of output is +/- 32767
+*/
+#define PA_DITHER_BITS (15)
+#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
+long PaConvert_TriangularDither( void )
+{
+ static unsigned long previous = 0;
+ static unsigned long randSeed1 = 22222;
+ static unsigned long randSeed2 = 5555555;
+ long current, highPass;
+ /* Generate two random numbers. */
+ randSeed1 = (randSeed1 * 196314165) + 907633515;
+ randSeed2 = (randSeed2 * 196314165) + 907633515;
+ /* Generate triangular distribution about 0.
+ * Shift before adding to prevent overflow which would skew the distribution.
+ * Also shift an extra bit for the high pass filter.
+ */
+#define DITHER_SHIFT ((32 - PA_DITHER_BITS) + 1)
+ current = (((long)randSeed1)>>DITHER_SHIFT) + (((long)randSeed2)>>DITHER_SHIFT);
+ /* High pass filter to reduce audibility. */
+ highPass = current - previous;
+ previous = current;
+ return highPass;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Int16, call user code, then convert output
+** to Int16 format for native use.
+** Assumes host native format is paInt16.
+** Returns result from user callback.
+*/
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer )
+{
+ long temp;
+ int userResult;
+ unsigned int i;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+#if SUPPORT_AUDIO_CAPTURE
+ /* Get native data from DirectSound. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ /* Convert from native format to PA format. */
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels;
+ switch(past->past_InputSampleFormat)
+ {
+
+ case paFloat32:
+ {
+ float *inBufPtr = (float *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] * (1.0f / 32767.0f);
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ /* Convert 16 bit data to 32 bit integers */
+ int *inBufPtr = (int *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] << 16;
+ }
+ break;
+ }
+
+ case paInt16:
+ {
+ /* Already in correct format so don't copy. */
+ inputBuffer = nativeInputBuffer;
+ break;
+ }
+
+ case paInt8:
+ {
+ /* Convert 16 bit data to 8 bit chars */
+ char *inBufPtr = (char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = (char)(nativeInputBuffer[i] >> 8);
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (char)(temp >> 8);
+ }
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ /* Convert 16 bit data to 8 bit unsigned chars */
+ unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = ((unsigned char)(nativeInputBuffer[i] >> 8)) + 0x80;
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+
+ /* Are we doing output time? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ /* May already be in native format so just write directly to native buffer. */
+ outputBuffer = (past->past_OutputSampleFormat == paInt16) ?
+ nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+ /* Convert to native format if necessary. */
+ if( outputBuffer != NULL )
+ {
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
+ switch(past->past_OutputSampleFormat)
+ {
+ case paFloat32:
+ {
+ float *outBufPtr = (float *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ if( past->past_Flags & paClipOff ) /* NOTHING */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] * (32767.0f));
+ }
+ }
+ else /* CLIP */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = (long)(outBufPtr[i] * 32767.0f);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ float dither = PaConvert_TriangularDither()*PA_DITHER_SCALE;
+ float dithered = (outBufPtr[i] * (32767.0f)) + dither;
+ temp = (long) (dithered);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ int *outBufPtr = (int *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] >> 16 );
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ /* Shift one bit down before dithering so that we have room for overflow from add. */
+ temp = (outBufPtr[i] >> 1) + PaConvert_TriangularDither();
+ temp = temp >> 15;
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt8:
+ {
+ char *outBufPtr = (char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = ((short)outBufPtr[i]) << 8;
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ unsigned char *outBufPtr = (unsigned char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = ((short)(outBufPtr[i] - 0x80)) << 8;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ return userResult;
+}
+
+/*************************************************************************/
+PaError Pa_Initialize( void )
+{
+ if( gInitCount++ > 0 ) return paNoError;
+ ResetTraceMessages();
+ return PaHost_Init();
+}
+
+PaError Pa_Terminate( void )
+{
+ PaError result = paNoError;
+
+ if( gInitCount == 0 ) return paNoError;
+ else if( --gInitCount == 0 )
+ {
+ result = PaHost_Term();
+ DumpTraceMessages();
+ }
+ return result;
+}
+
+int PaHost_IsInitialized()
+{
+ return gInitCount;
+}
+
+/*************************************************************************/
+PaError Pa_GetSampleSize( PaSampleFormat format )
+{
+ int size;
+ switch(format )
+ {
+
+ case paUInt8:
+ case paInt8:
+ size = 1;
+ break;
+
+ case paInt16:
+ size = 2;
+ break;
+
+ case paPackedInt24:
+ size = 3;
+ break;
+
+ case paFloat32:
+ case paInt32:
+ case paInt24:
+ size = 4;
+ break;
+
+ default:
+ size = paSampleFormatNotSupported;
+ break;
+ }
+ return (PaError) size;
+}
+
+
diff --git a/pd/portaudio/pa_common/pa_trace.c b/pd/portaudio/pa_common/pa_trace.c
new file mode 100644
index 00000000..d55a6d37
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_trace.c
@@ -0,0 +1,83 @@
+/*
+ * $Id: pa_trace.c,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $
+ * Portable Audio I/O Library Trace Facility
+ * Store trace information in real-time for later printing.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pa_trace.h"
+
+#if TRACE_REALTIME_EVENTS
+
+static char *traceTextArray[MAX_TRACE_RECORDS];
+static int traceIntArray[MAX_TRACE_RECORDS];
+static int traceIndex = 0;
+static int traceBlock = 0;
+
+/*********************************************************************/
+void ResetTraceMessages()
+{
+ traceIndex = 0;
+}
+
+/*********************************************************************/
+void DumpTraceMessages()
+{
+ int i;
+ int numDump = (traceIndex < MAX_TRACE_RECORDS) ? traceIndex : MAX_TRACE_RECORDS;
+
+ printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );
+ for( i=0; i<numDump; i++ )
+ {
+ printf("%3d: %s = 0x%08X\n",
+ i, traceTextArray[i], traceIntArray[i] );
+ }
+ ResetTraceMessages();
+ fflush(stdout);
+}
+
+/*********************************************************************/
+void AddTraceMessage( char *msg, int data )
+{
+ if( (traceIndex == MAX_TRACE_RECORDS) && (traceBlock == 0) )
+ {
+ traceBlock = 1;
+ /* DumpTraceMessages(); */
+ }
+ else if( traceIndex < MAX_TRACE_RECORDS )
+ {
+ traceTextArray[traceIndex] = msg;
+ traceIntArray[traceIndex] = data;
+ traceIndex++;
+ }
+}
+
+#endif
diff --git a/pd/portaudio/pa_common/pa_trace.h b/pd/portaudio/pa_common/pa_trace.h
new file mode 100644
index 00000000..d0fc904c
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_trace.h
@@ -0,0 +1,67 @@
+#ifndef PA_TRACE_H
+#define PA_TRACE_H
+/*
+ * $Id: pa_trace.h,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $
+ * Portable Audio I/O Library Trace Facility
+ * Store trace information in real-time for later printing.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#define TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
+#define MAX_TRACE_RECORDS (2048)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+ /************************************************************************************/
+ /****************** Prototypes ******************************************************/
+ /************************************************************************************/
+
+#if TRACE_REALTIME_EVENTS
+
+ void DumpTraceMessages();
+ void ResetTraceMessages();
+ void AddTraceMessage( char *msg, int data );
+
+#else
+
+#define AddTraceMessage(msg,data) /* noop */
+#define ResetTraceMessages() /* noop */
+#define DumpTraceMessages() /* noop */
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PA_TRACE_H */
diff --git a/pd/portaudio/pa_common/portaudio.h b/pd/portaudio/pa_common/portaudio.h
new file mode 100644
index 00000000..06f7079b
--- /dev/null
+++ b/pd/portaudio/pa_common/portaudio.h
@@ -0,0 +1,463 @@
+#ifndef PORT_AUDIO_H
+#define PORT_AUDIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: portaudio.h,v 1.5 2002/03/26 18:04:22 philburk Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError,
+ paDeviceUnavailable
+} PaErrorNum;
+
+/*
+ Pa_Initialize() is the library initialisation function - call this before
+ using the library.
+
+*/
+
+PaError Pa_Initialize( void );
+
+/*
+ Pa_Terminate() is the library termination function - call this after
+ using the library.
+
+*/
+
+PaError Pa_Terminate( void );
+
+/*
+ Pa_GetHostError() returns a host specific error code.
+ This can be called after receiving a PortAudio error code of paHostError.
+
+*/
+
+long Pa_GetHostError( void );
+
+/*
+ Pa_GetErrorText() translates the supplied PortAudio error number
+ into a human readable message.
+
+*/
+
+const char *Pa_GetErrorText( PaError errnum );
+
+/*
+ Sample formats
+
+ These are formats used to pass sound data between the callback and the
+ stream. Each device has a "native" format which may be used when optimum
+ efficiency or control over conversion is required.
+
+ Formats marked "always available" are supported (emulated) by all
+ PortAudio implementations.
+
+ The floating point representation (paFloat32) uses +1.0 and -1.0 as the
+ maximum and minimum respectively.
+
+ paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
+
+*/
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6))
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pa_CountDevices()-1.
+
+ Devices may support input, output or both.
+
+*/
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+int Pa_CountDevices( void );
+
+typedef struct
+{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+ /* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+ /* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+}
+PaDeviceInfo;
+
+/*
+ Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the
+ default device ids for input and output respectively, or paNoDevice if
+ no device is available.
+ The result can be passed to Pa_OpenStream().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ids by using
+ the supplied application "pa_devs".
+
+*/
+
+PaDeviceID Pa_GetDefaultInputDeviceID( void );
+PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+
+
+
+/*
+ Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
+ for the device specified.
+ If the device parameter is out of range the function returns NULL.
+
+ PortAudio manages the memory referenced by the returned pointer, the client
+ must not manipulate or free the memory. The pointer is only guaranteed to be
+ valid between calls to Pa_Initialize() and Pa_Terminate().
+
+*/
+
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device );
+
+/*
+ PaTimestamp is used to represent a continuous sample clock with arbitrary
+ start time that can be used for syncronization. The type is used for the
+ outTime argument to the PortAudioCallback and as the result of Pa_StreamTime()
+
+*/
+
+typedef double PaTimestamp;
+
+/*
+ PortAudioCallback is implemented by PortAudio clients.
+
+ inputBuffer and outputBuffer are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream() (see below).
+
+ framesPerBuffer is the number of sample frames to be processed by the callback.
+
+ outTime is the time in samples when the buffer(s) processed by
+ this callback will begin being played at the audio output.
+ See also Pa_StreamTime()
+
+ userData is the value of a user supplied pointer passed to Pa_OpenStream()
+ intended for storing synthesis data etc.
+
+ return value:
+ The callback can return a non-zero value to stop the stream. This may be
+ useful in applications such as soundfile players where a specific duration
+ of output is required. However, it is not necessary to utilise this mechanism
+ as StopStream() will also terminate the stream. A callback returning a
+ non-zero value must fill the entire outputBuffer.
+
+ NOTE: None of the other stream functions may be called from within the
+ callback function except for Pa_GetCPULoad().
+
+*/
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+/*
+ Stream flags
+
+ These flags may be supplied (ored together) in the streamFlags argument to
+ the Pa_OpenStream() function.
+
+*/
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable default clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+/*
+ A single PortAudioStream provides multiple channels of real-time
+ input and output audio streaming to a client application.
+ Pointers to PortAudioStream objects are passed between PortAudio functions.
+*/
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+/*
+ Pa_OpenStream() opens a stream for either input, output or both.
+
+ stream is the address of a PortAudioStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PaDeviceID above.)
+ inputDevice may be paNoDevice to indicate that an input device is not required.
+
+ numInputChannels is the number of channels of sound to be delivered to the
+ callback. It can range from 1 to the value of maxInputChannels in the
+ PaDeviceInfo record for the device specified by the inputDevice parameter.
+ If inputDevice is paNoDevice numInputChannels is ignored.
+
+ inputSampleFormat is the sample format of inputBuffer provided to the callback
+ function. inputSampleFormat may be any of the formats described by the
+ PaSampleFormat enumeration (see above). PortAudio guarantees support for
+ the device's native formats (nativeSampleFormats in the device info record)
+ and additionally 16 and 32 bit integer and 32 bit floating point formats.
+ Support for other formats is implementation defined.
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ inputDriverInfo is never required for correct operation. If not used
+ inputDriverInfo should be NULL.
+
+ outputDevice is the id of the device used for output (see PaDeviceID above.)
+ outputDevice may be paNoDevice to indicate that an output device is not required.
+
+ numOutputChannels is the number of channels of sound to be supplied by the
+ callback. See the definition of numInputChannels above for more details.
+
+ outputSampleFormat is the sample format of the outputBuffer filled by the
+ callback function. See the definition of inputSampleFormat above for more
+ details.
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ sampleRate is the desired sampleRate. For full-duplex streams it is the
+ sample rate for both input and output
+
+ framesPerBuffer is the length in sample frames of all internal sample buffers
+ used for communication with platform specific audio routines. Wherever
+ possible this corresponds to the framesPerBuffer parameter passed to the
+ callback function.
+
+ numberOfBuffers is the number of buffers used for multibuffered communication
+ with the platform specific audio routines. If you pass zero, then an optimum
+ value will be chosen for you internally. This parameter is provided only
+ as a guide - and does not imply that an implementation must use multibuffered
+ i/o when reliable double buffering is available (such as SndPlayDoubleBuffer()
+ on the Macintosh.)
+
+ streamFlags may contain a combination of flags ORed together.
+ These flags modify the behaviour of the streaming process. Some flags may only
+ be relevant to certain buffer formats.
+
+ callback is a pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers (see above for details.)
+
+ userData is a client supplied pointer which is passed to the callback
+ function. It could for example, contain a pointer to instance data necessary
+ for processing the audio buffers.
+
+ return value:
+ Upon success Pa_OpenStream() returns PaNoError and places a pointer to a
+ valid PortAudioStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails a non-zero error code is returned (see
+ PaError above) and the value of stream is invalid.
+
+*/
+
+PaError Pa_OpenStream( PortAudioStream** stream,
+ PaDeviceID inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+/*
+ Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens
+ the default input and/or output devices. Most parameters have identical meaning
+ to their Pa_OpenStream() counterparts, with the following exceptions:
+
+ If either numInputChannels or numOutputChannels is 0 the respective device
+ is not opened. This has the same effect as passing paNoDevice in the device
+ arguments to Pa_OpenStream().
+
+ sampleFormat applies to both the input and output buffers.
+
+*/
+
+PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+/*
+ Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+
+*/
+
+PaError Pa_CloseStream( PortAudioStream* );
+
+/*
+ Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
+ Pa_StopStream() waits until all pending audio buffers have been played.
+ Pa_AbortStream() stops playing immediately without waiting for pending
+ buffers to complete.
+
+*/
+
+PaError Pa_StartStream( PortAudioStream *stream );
+
+PaError Pa_StopStream( PortAudioStream *stream );
+
+PaError Pa_AbortStream( PortAudioStream *stream );
+
+/*
+ Pa_StreamActive() returns one (1) when the stream is active (ie playing
+ or recording audio), zero (0) when not playing, or a negative error number
+ if the stream is invalid.
+ The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+ but may also become inactive if the callback returns a non-zero value.
+ In the latter case, the stream is considered inactive after the last
+ buffer has finished playing.
+
+*/
+
+PaError Pa_StreamActive( PortAudioStream *stream );
+
+/*
+ Pa_StreamTime() returns the current output time in samples for the stream.
+ This time may be used as a time reference (for example synchronizing audio to
+ MIDI).
+
+*/
+
+PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+/*
+ Pa_GetCPULoad() returns the CPU Load for the stream.
+ The "CPU Load" is a fraction of total CPU time consumed by the stream's
+ audio processing routines including, but not limited to the client supplied
+ callback.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ This function may be called from the callback function or the application.
+
+*/
+
+double Pa_GetCPULoad( PortAudioStream* stream );
+
+/*
+ Pa_GetMinNumBuffers() returns the minimum number of buffers required by
+ the current host based on minimum latency.
+ On the PC, for the DirectSound implementation, latency can be optionally set
+ by user by setting an environment variable.
+ For example, to set latency to 200 msec, put:
+
+ set PA_MIN_LATENCY_MSEC=200
+
+ in the AUTOEXEC.BAT file and reboot.
+ If the environment variable is not set, then the latency will be determined
+ based on the OS. Windows NT has higher latency than Win95.
+
+*/
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
+
+/*
+ Pa_Sleep() puts the caller to sleep for at least 'msec' milliseconds.
+ You may sleep longer than the requested time so don't rely on this for
+ accurate musical timing.
+
+ Pa_Sleep() is provided as a convenience for authors of portable code (such as
+ the tests and examples in the PortAudio distribution.)
+
+*/
+
+void Pa_Sleep( long msec );
+
+/*
+ Pa_GetSampleSize() returns the size in bytes of a single sample in the
+ supplied PaSampleFormat, or paSampleFormatNotSupported if the format is
+ no supported.
+
+*/
+
+PaError Pa_GetSampleSize( PaSampleFormat format );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_AUDIO_H */
diff --git a/pd/portaudio/pa_mac_core/notes.txt b/pd/portaudio/pa_mac_core/notes.txt
new file mode 100644
index 00000000..c79b90e6
--- /dev/null
+++ b/pd/portaudio/pa_mac_core/notes.txt
@@ -0,0 +1,34 @@
+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/pd/portaudio/pa_mac_core/pa_mac_core.c b/pd/portaudio/pa_mac_core/pa_mac_core.c
new file mode 100644
index 00000000..9a4b1488
--- /dev/null
+++ b/pd/portaudio/pa_mac_core/pa_mac_core.c
@@ -0,0 +1,1261 @@
+/*
+ * $Id: pa_mac_core.c,v 1.8 2002/04/12 18:07:20 philburk Exp $
+ * 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
+ 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 <CoreServices/CoreServices.h>
+#include <CoreAudio/CoreAudio.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+/************************************************* Constants ********/
+
+/* 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 PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(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)
+
+/**************************************************************
+ * Structure for internal host specific stream data.
+ * This is allocated on a per stream basis.
+ */
+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 */
+ /* Output -------------- */
+ int pahsc_BytesPerUserNativeOutputBuffer; /* native buffer size in bytes per user chunk */
+ /* Init Time -------------- */
+ int pahsc_FramesPerHostBuffer;
+ int pahsc_UserBuffersPerHostBuffer;
+ /* For measuring CPU utilization. */
+ struct rusage pahsc_EntryRusage;
+ double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
+}
+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 sDefaultInputDeviceID = paNoDevice;
+static int sDefaultOutputDeviceID = paNoDevice;
+static int sPaHostError = 0;
+
+static int sNumCoreDevices = 0;
+static AudioDeviceID *sCoreDeviceIDs; // Array of Core 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 ********/
+
+/************************************************* 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 );
+}
+
+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)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+
+ if( getrusage( RUSAGE_SELF, &currentRusage ) == 0 )
+ {
+ usecsElapsed = SubtractTime_AminusB( &currentRusage.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);
+ }
+}
+/****************************************** END CPU UTILIZATION *******/
+
+/************************************************************************/
+static PaDeviceID Pa_QueryDefaultInputDevice( void )
+{
+ OSStatus err = noErr;
+ UInt32 count;
+ int i;
+ AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
+ PaDeviceID defaultDeviceID = paNoDevice;
+
+ // get the default output device for the HAL
+ // it is required to pass the size of the data to be returned
+ 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=LOWEST_INPUT_DEVID; i<=HIGHEST_INPUT_DEVID; i++ )
+ {
+ DBUG(("Pa_QueryDefaultInputDevice: i = %d, aDevId = %d\n", i, sDeviceInfos[i].audioDeviceID ));
+ if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
+ {
+ defaultDeviceID = i;
+ break;
+ }
+ }
+Bail:
+ return defaultDeviceID;
+}
+
+/************************************************************************/
+static PaDeviceID Pa_QueryDefaultOutputDevice( void )
+{
+ OSStatus err = noErr;
+ UInt32 count;
+ int i;
+ AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
+ PaDeviceID defaultDeviceID = paNoDevice;
+
+ // get the default output device for the HAL
+ // it is required to pass the size of the data to be returned
+ count = sizeof(tempDeviceID);
+ err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &tempDeviceID);
+ if (err != noErr) goto Bail;
+
+ // scan output devices to see which one matches this device
+ defaultDeviceID = paNoDevice;
+ for( i=LOWEST_OUTPUT_DEVID; i<=HIGHEST_OUTPUT_DEVID; i++ )
+ {
+ DBUG(("Pa_QueryDefaultOutputDevice: i = %d, aDevId = %d\n", i, sDeviceInfos[i].audioDeviceID ));
+ if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
+ {
+ defaultDeviceID = i;
+ break;
+ }
+ }
+Bail:
+ return defaultDeviceID;
+}
+
+/******************************************************************/
+static PaError Pa_QueryDevices( void )
+{
+ OSStatus err = noErr;
+ UInt32 outSize;
+ Boolean outWritable;
+ int numBytes;
+
+ // find out how many Core Audio devices there are, if any
+ err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &outSize, &outWritable);
+ if (err != noErr)
+ ERR_RPT(("Couldn't get info about list of audio devices\n"));
+
+ // calculate the number of device available
+ sNumCoreDevices = outSize / sizeof(AudioDeviceID);
+
+ // Bail if there aren't any devices
+ if (sNumCoreDevices < 1)
+ ERR_RPT(("No Devices Available\n"));
+
+ // make space for the devices we are about to get
+ sCoreDeviceIDs = (AudioDeviceID *)malloc(outSize);
+
+ // get an array of AudioDeviceIDs
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sCoreDeviceIDs);
+ if (err != noErr)
+ ERR_RPT(("Couldn't get list of audio device IDs\n"));
+
+ // Allocate structures to hold device info pointers.
+ // There will be a maximum of two Pa devices per Core Audio device, input and/or output.
+ numBytes = sNumCoreDevices * 2 * sizeof(PaHostDeviceInfo);
+ sDeviceInfos = (PaHostDeviceInfo *) PaHost_AllocateFastMemory( numBytes );
+ if( sDeviceInfos == NULL ) return paInsufficientMemory;
+
+ // Scan all the Core Audio devices to see which support input and allocate a
+ // PaHostDeviceInfo structure for each one.
+ PaHost_ScanDevices( IS_INPUT );
+ sNumInputDevices = sNumPaDevices;
+ // Now scan all the output devices.
+ PaHost_ScanDevices( IS_OUTPUT );
+ sNumOutputDevices = sNumPaDevices - sNumInputDevices;
+
+ // Figure out which of the devices that we scanned is the default device.
+ sDefaultInputDeviceID = Pa_QueryDefaultInputDevice();
+ sDefaultOutputDeviceID = Pa_QueryDefaultOutputDevice();
+
+ return paNoError;
+}
+
+/************************************************************************************/
+long Pa_GetHostError()
+{
+ return sPaHostError;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ if( sNumPaDevices <= 0 ) Pa_Initialize();
+ return sNumPaDevices;
+}
+
+/*************************************************************************/
+/* Allocate a string containing the device name. */
+static char *PaHost_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
+{
+ OSStatus err = noErr;
+ UInt32 outSize;
+ Boolean outWritable;
+ char *deviceName = nil;
+
+ // query size of name
+ err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
+ if (err == noErr)
+ {
+ deviceName = (char*)malloc( outSize + 1);
+ if( deviceName )
+ {
+ err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, deviceName);
+ if (err != noErr)
+ ERR_RPT(("Couldn't get audio device name.\n"));
+ }
+ }
+
+ return deviceName;
+}
+
+/*************************************************************************/
+// An AudioStreamBasicDescription is passed in to query whether or not
+// the format is supported. A kAudioDeviceUnsupportedFormatError will
+// be returned if the format is not supported and kAudioHardwareNoError
+// will be returned if it is supported. AudioStreamBasicDescription
+// fields set to 0 will be ignored in the query, but otherwise values
+// must match exactly.
+
+Boolean deviceDoesSupportFormat(AudioDeviceID deviceID, AudioStreamBasicDescription *desc, Boolean isInput )
+{
+ OSStatus err = noErr;
+ UInt32 outSize;
+
+ outSize = sizeof(*desc);
+ err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &outSize, desc);
+
+ if (err == kAudioHardwareNoError)
+ return true;
+ else
+ return false;
+}
+
+/*************************************************************************/
+// return an error string
+char* coreAudioErrorString (int errCode )
+{
+ char *str;
+
+ switch (errCode)
+ {
+ case kAudioHardwareUnspecifiedError:
+ str = "kAudioHardwareUnspecifiedError";
+ break;
+ case kAudioHardwareNotRunningError:
+ str = "kAudioHardwareNotRunningError";
+ break;
+ case kAudioHardwareUnknownPropertyError:
+ str = "kAudioHardwareUnknownPropertyError";
+ break;
+ case kAudioDeviceUnsupportedFormatError:
+ str = "kAudioDeviceUnsupportedFormatError";
+ break;
+ case kAudioHardwareBadPropertySizeError:
+ str = "kAudioHardwareBadPropertySizeError";
+ break;
+ case kAudioHardwareIllegalOperationError:
+ str = "kAudioHardwareIllegalOperationError";
+ break;
+ default:
+ str = "Unknown CoreAudio Error!";
+ break;
+ }
+
+ return str;
+}
+
+/*************************************************************************
+** PaDeviceInfo structures have already been created
+** so just return the pointer.
+**
+*/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ if( id < 0 || id >= sNumPaDevices )
+ return NULL;
+
+ 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; coreDeviceIndex<sNumCoreDevices; coreDeviceIndex++ )
+ {
+ // try to fill in next PaHostDeviceInfo
+ hostDeviceInfo = &sDeviceInfos[sNumPaDevices];
+ result = PaHost_QueryDeviceInfo( hostDeviceInfo, coreDeviceIndex, isInput );
+ DBUG(("PaHost_ScanDevices: paDevId = %d, coreDevId = %d\n", sNumPaDevices, hostDeviceInfo->audioDeviceID ));
+ 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;
+ 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 );
+
+ 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 ++)
+ {
+ memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
+ formatDesc.mSampleRate = possibleSampleRates[index];
+ result = deviceDoesSupportFormat( devID, &formatDesc, isInput );
+
+ 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);
+
+ // 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->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.
+ 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;
+ }
+
+ // Get the device name
+ deviceInfo->name = PaHost_DeviceNameFromID( devID, isInput );
+ return 1;
+
+error:
+ if( sampleRates != NULL ) free( sampleRates );
+ 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 )
+{
+#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( sNumPaDevices == 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 )
+{
+ 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 *inputNativeBufferfPtr = NULL;
+ char *outputNativeBufferfPtr = NULL;
+ 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
+
+ Pa_StartUsageCalculation( past );
+
+ /* If we are using output, then we need an empty output buffer. */
+ if( past->past_NumOutputChannels > 0 )
+ {
+ outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData;
+ }
+
+ /* If we are using input, then we need a full input buffer. */
+ if( past->past_NumInputChannels > 0 )
+ {
+ inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData;
+ }
+
+ buffersProcessed += 1;
+
+ /* Each host buffer contains multiple user buffers so do them all now. */
+ for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
+ {
+ if( done )
+ {
+ if( outputNativeBufferfPtr )
+ {
+ /* 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 );
+ }
+ }
+ else
+ {
+ /* Convert 32 bit native data to user data and call user routine. */
+ result = PaConvert_Process( past, inputNativeBufferfPtr, outputNativeBufferfPtr );
+ if( result != 0) done = 1;
+ }
+ if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer;
+ if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer;
+ }
+
+ 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;
+
+// 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
+ {
+ /* 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)
+ {
+ /* 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;
+}
+
+#if 0
+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;
+}
+#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;
+ int bytesPerInputFrame;
+
+ 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];
+
+ /* 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:
+ 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 < LOWEST_OUTPUT_DEVID) ||
+ (past->past_OutputDeviceID > HIGHEST_OUTPUT_DEVID) )
+ {
+ 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
+ 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);
+
+ if (err != kAudioHardwareNoError)
+ {
+ result = paInvalidChannelCount;
+ goto error;
+ }
+#endif
+ }
+
+ // 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,
+ kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer);
+ if( err != noErr )
+ {
+ ERR_RPT(("Could not force buffer size!"));
+ result = paHostError;
+ goto error;
+ }
+
+ // setup conversion procedure
+ result = PaConvert_SetupOutput( past, paFloat32 );
+
+ return result;
+
+error:
+ return result;
+}
+
+/*******************************************************************/
+PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ return 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
+*/
+static void PaHost_CalcHostBufferSize( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData;
+ unsigned int minNumUserBuffers;
+
+ // 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 ));
+
+ // 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_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
+}
+
+/*******************************************************************/
+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;
+
+ // 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;
+ }
+ }
+
+ PaHost_CalcHostBufferSize( past );
+
+ {
+ 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 ));
+ }
+
+ /* 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;
+ }
+
+ /* ------------------ 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;
+ }
+
+ return result;
+
+error:
+ PaHost_CloseStream( past );
+ return result;
+}
+
+/*************************************************************************/
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ return 0;
+}
+
+/*************************************************************************/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ return 0;
+}
+
+/*************************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ OSStatus err = noErr;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ 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;
+
+#if PA_TRACE_START_STOP
+ AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result );
+#endif
+
+error:
+ return paHostError; // FIXME - save host error
+}
+
+/*************************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ 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;
+ 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 )
+{
+ 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 PA_TRACE_START_STOP
+ AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
+#endif
+
+ 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 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.
+*/
+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.
+*/
+PaError PaHost_Term( void )
+{
+ int i;
+
+ if( sDeviceInfos != NULL )
+ {
+ for( i=0; i<sNumPaDevices; i++ )
+ {
+ if( sDeviceInfos[i].paInfo.name != NULL ) free( (char*)sDeviceInfos[i].paInfo.name );
+ if( sDeviceInfos[i].paInfo.sampleRates != NULL ) free( (void*)sDeviceInfos[i].paInfo.sampleRates );
+ }
+ free( sDeviceInfos );
+ sDeviceInfos = NULL;
+ }
+
+ sNumPaDevices = 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
+ usleep( msec * 1000 );
+#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;
+}
+
+/*************************************************************************/
+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;
+}
diff --git a/pd/portaudio/pablio/README.txt b/pd/portaudio/pablio/README.txt
new file mode 100644
index 00000000..99c7d146
--- /dev/null
+++ b/pd/portaudio/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/pd/portaudio/pablio/pablio.c b/pd/portaudio/pablio/pablio.c
new file mode 100644
index 00000000..53dec058
--- /dev/null
+++ b/pd/portaudio/pablio/pablio.c
@@ -0,0 +1,307 @@
+/*
+ * $Id: pablio.c,v 1.1.1.1 2002-07-29 17:06:16 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include "pablio.h"
+#include <string.h>
+
+/************************************************************************/
+/******** 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; i<numBytes; i++ )
+ {
+ ((char *)outputBuffer)[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Allocate buffer. */
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
+{
+ long numBytes = numFrames * bytesPerFrame;
+ char *buffer = (char *) malloc( numBytes );
+ if( buffer == NULL ) return paInsufficientMemory;
+ memset( buffer, 0, numBytes );
+ return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );
+}
+
+/* Free buffer. */
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf )
+{
+ if( rbuf->buffer ) 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<<numBits);
+}
+
+/************************************************************
+ * 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 **rwblPtr, double sampleRate,
+ PaSampleFormat format, long flags )
+{
+ long bytesPerSample;
+ long doRead = 0;
+ long doWrite = 0;
+ PaError err;
+ PABLIO_Stream *aStream;
+ long minNumBuffers;
+ long numFrames;
+
+ /* Allocate PABLIO_Stream structure for caller. */
+ aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );
+ if( aStream == NULL ) return paInsufficientMemory;
+ memset( aStream, 0, sizeof(PABLIO_Stream) );
+
+ /* Determine size of a sample. */
+ bytesPerSample = Pa_GetSampleSize( format );
+ if( bytesPerSample < 0 )
+ {
+ err = (PaError) bytesPerSample;
+ goto error;
+ }
+ aStream->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/pd/portaudio/pablio/pablio.def b/pd/portaudio/pablio/pablio.def
new file mode 100644
index 00000000..a10f9529
--- /dev/null
+++ b/pd/portaudio/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/pd/portaudio/pablio/pablio.h b/pd/portaudio/pablio/pablio.h
new file mode 100644
index 00000000..9060c560
--- /dev/null
+++ b/pd/portaudio/pablio/pablio.h
@@ -0,0 +1,108 @@
+#ifndef _PABLIO_H
+#define _PABLIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: pablio.h,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include <string.h>
+
+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,
+ */
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+ PaSampleFormat format, long flags );
+
+PaError CloseAudioStream( PABLIO_Stream *aStream );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PABLIO_H */
diff --git a/pd/portaudio/pablio/pablio_pd.c b/pd/portaudio/pablio/pablio_pd.c
new file mode 100644
index 00000000..e7105e9b
--- /dev/null
+++ b/pd/portaudio/pablio/pablio_pd.c
@@ -0,0 +1,335 @@
+/*
+ * $Id: pablio_pd.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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.
+ *
+ */
+
+ /* changes by Miller Puckette to support Pd: device selection,
+ settable audio buffer size, and settable number of channels.
+ LATER also fix it to poll for input and output fifo fill points. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include "pablio_pd.h" /* MSP */
+#include <string.h>
+
+ /* MSP -- FRAMES_PER_BUFFER constant removed */
+
+/************************************************************************/
+/******** 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; i<numBytes; i++ )
+ {
+ ((char *)outputBuffer)[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Allocate buffer. */
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
+{
+ long numBytes = numFrames * bytesPerFrame;
+ char *buffer = (char *) malloc( numBytes );
+ if( buffer == NULL ) return paInsufficientMemory;
+ memset( buffer, 0, numBytes );
+ return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );
+}
+
+/* Free buffer. */
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf )
+{
+ if( rbuf->buffer ) 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<<numBits);
+}
+
+/************************************************************
+ * 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
+ */
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+ PaSampleFormat format, long flags, int nchannels,
+ int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno) /* MSP */
+{
+ long bytesPerSample;
+ long doRead = 0;
+ long doWrite = 0;
+ PaError err;
+ PABLIO_Stream *aStream;
+ long minNumBuffers;
+ long numFrames;
+
+ /* fprintf(stderr,
+ "open %lf fmt %d flags %d ch: %d fperbuf: %d nbuf: %d devs: %d %d\n",
+ sampleRate, format, flags, nchannels,
+ framesperbuf, nbuffers, indeviceno, outdeviceno); */
+
+ if (indeviceno < 0) /* MSP... */
+ {
+ indeviceno = Pa_GetDefaultInputDeviceID();
+ fprintf(stderr, "using default input device number: %d\n", indeviceno);
+ }
+ if (outdeviceno < 0)
+ {
+ outdeviceno = Pa_GetDefaultOutputDeviceID();
+ fprintf(stderr, "using default output device number: %d\n", outdeviceno);
+ }
+ nbuffers = RoundUpToNextPowerOf2(nbuffers);
+ fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n",
+ nchannels, flags, nbuffers, framesperbuf);
+ /* ...MSP */
+
+ /* Allocate PABLIO_Stream structure for caller. */
+ aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );
+ if( aStream == NULL ) return paInsufficientMemory;
+ memset( aStream, 0, sizeof(PABLIO_Stream) );
+
+ /* Determine size of a sample. */
+ bytesPerSample = Pa_GetSampleSize( format );
+ if( bytesPerSample < 0 )
+ {
+ err = (PaError) bytesPerSample;
+ goto error;
+ }
+ aStream->samplesPerFrame = nchannels; /* MSP */
+ 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. */ /* MSP */
+ minNumBuffers = Pa_GetMinNumBuffers(framesperbuf, sampleRate);
+ if (minNumBuffers > nbuffers)
+ fprintf(stderr,
+ "warning: number of buffers %d less than recommended minimum %d\n",
+ (int)nbuffers, (int)minNumBuffers);
+ numFrames = nbuffers * framesperbuf;
+
+ /* 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 ? indeviceno : paNoDevice), /* MSP */
+ (doRead ? aStream->samplesPerFrame : 0 ),
+ format,
+ NULL,
+ (doWrite ? outdeviceno : paNoDevice), /* MSP */
+ (doWrite ? aStream->samplesPerFrame : 0 ),
+ format,
+ NULL,
+ sampleRate,
+ framesperbuf, /* MSP */
+ nbuffers, /* MSP */
+ paNoFlag, /* MSP -- portaudio will clip for us */
+ blockingIOCallback,
+ aStream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( aStream->stream );
+ if( err != paNoError ) /* MSP */
+ {
+ fprintf(stderr, "Pa_StartStream failed; closing audio stream...\n");
+ CloseAudioStream( aStream );
+ goto error;
+ }
+
+ *rwblPtr = aStream;
+ return paNoError;
+
+error:
+ *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/pd/portaudio/pablio/pablio_pd.h b/pd/portaudio/pablio/pablio_pd.h
new file mode 100644
index 00000000..b87b9f5a
--- /dev/null
+++ b/pd/portaudio/pablio/pablio_pd.h
@@ -0,0 +1,110 @@
+#ifndef _PABLIO_H
+#define _PABLIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: pablio_pd.h,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include <string.h>
+
+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,
+ */
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+ PaSampleFormat format, long flags, int nchannels,
+ int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno); /* MSP */
+
+PaError CloseAudioStream( PABLIO_Stream *aStream );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PABLIO_H */
diff --git a/pd/portaudio/pablio/ringbuffer.c b/pd/portaudio/pablio/ringbuffer.c
new file mode 100644
index 00000000..b8cc691f
--- /dev/null
+++ b/pd/portaudio/pablio/ringbuffer.c
@@ -0,0 +1,199 @@
+/*
+ * $Id: ringbuffer.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+/***************************************************************************
+ * 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/pd/portaudio/pablio/ringbuffer.h b/pd/portaudio/pablio/ringbuffer.h
new file mode 100644
index 00000000..1bf78e3a
--- /dev/null
+++ b/pd/portaudio/pablio/ringbuffer.h
@@ -0,0 +1,101 @@
+#ifndef _RINGBUFFER_H
+#define _RINGBUFFER_H
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: ringbuffer.h,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+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/pd/portaudio/pablio/ringbuffer_pd.c b/pd/portaudio/pablio/ringbuffer_pd.c
new file mode 100644
index 00000000..16890d65
--- /dev/null
+++ b/pd/portaudio/pablio/ringbuffer_pd.c
@@ -0,0 +1,214 @@
+/*
+ * $Id: ringbuffer_pd.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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.
+ *
+ */
+/*
+ * modified 2002/07/13 by olaf.matthes@gmx.de to allow any number if channels
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+/***************************************************************************
+ * Initialize FIFO.
+ */
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )
+{
+ rbuf->bufferSize = numBytes;
+ rbuf->buffer = (char *)dataPtr;
+ RingBuffer_Flush( rbuf );
+ return 0;
+}
+/***************************************************************************
+** Return number of bytes available for reading. */
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf )
+{
+ long ret = (rbuf->writeIndex - rbuf->readIndex) + rbuf->bufferSize;
+ if (ret >= 2 * rbuf->bufferSize)
+ ret -= 2 * rbuf->bufferSize;
+ return ( ret );
+}
+/***************************************************************************
+** 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;
+ while (index >= rbuf->bufferSize)
+ index -= rbuf->bufferSize;
+ 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 )
+{
+ long ret = (rbuf->writeIndex + numBytes);
+ if ( ret > 2 * rbuf->bufferSize)
+ ret -= 2 * rbuf->bufferSize; /* check for end of buffer */
+ return rbuf->writeIndex = ret;
+}
+
+/***************************************************************************
+** 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;
+ while (index > rbuf->bufferSize)
+ index -= rbuf->bufferSize;
+
+ 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 )
+{
+ long ret = (rbuf->readIndex + numBytes);
+ if( ret > 2 * rbuf->bufferSize)
+ ret -= 2 * rbuf->bufferSize;
+ return rbuf->readIndex = ret;
+}
+
+/***************************************************************************
+** 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/pd/portaudio/pablio/test_rw.c b/pd/portaudio/pablio/test_rw.c
new file mode 100644
index 00000000..cf54427d
--- /dev/null
+++ b/pd/portaudio/pablio/test_rw.c
@@ -0,0 +1,99 @@
+/*
+ * $Id: test_rw.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#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 (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
+#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 * FRAMES_PER_BLOCK];
+ 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 += FRAMES_PER_BLOCK )
+ {
+ /* 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 );
+
+ 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/pd/portaudio/pablio/test_rw_echo.c b/pd/portaudio/pablio/test_rw_echo.c
new file mode 100644
index 00000000..9b27e3c2
--- /dev/null
+++ b/pd/portaudio/pablio/test_rw_echo.c
@@ -0,0 +1,123 @@
+/*
+ * $Id: test_rw_echo.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio.h"
+#include <string.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 (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/pd/portaudio/pablio/test_w_saw.c b/pd/portaudio/pablio/test_w_saw.c
new file mode 100644
index 00000000..b8e3e71a
--- /dev/null
+++ b/pd/portaudio/pablio/test_w_saw.c
@@ -0,0 +1,108 @@
+/*
+ * $Id: test_w_saw.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio.h"
+#include <string.h>
+
+#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<FRAMES_PER_BLOCK; j++ )
+ {
+ /* Generate a sawtooth wave by incrementing a variable. */
+ phases[0] += PHASE_INCREMENT;
+ /* The signal range is -1.0 to +1.0 so wrap around if we go over. */
+ if( phases[0] > 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/pd/portaudio/pablio/test_w_saw8.c b/pd/portaudio/pablio/test_w_saw8.c
new file mode 100644
index 00000000..b876bd9f
--- /dev/null
+++ b/pd/portaudio/pablio/test_w_saw8.c
@@ -0,0 +1,106 @@
+/*
+ * $Id: test_w_saw8.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio.h"
+#include <string.h>
+
+#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<FRAMES_PER_BLOCK; j++ )
+ {
+ /* Generate a sawtooth wave by incrementing a variable. */
+ phases[0] += 1;
+ /* We don't have to do anything special to wrap when using paUint8 because
+ * 8 bit arithmetic automatically wraps. */
+ samples[j][0] = phases[0];
+
+ /* On the second channel, generate a higher sawtooth wave. */
+ phases[1] += 3;
+ 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/pd/portaudio/pablio/test_w_saw_pd.c b/pd/portaudio/pablio/test_w_saw_pd.c
new file mode 100644
index 00000000..be95d245
--- /dev/null
+++ b/pd/portaudio/pablio/test_w_saw_pd.c
@@ -0,0 +1,108 @@
+/*
+ * $Id: test_w_saw_pd.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio_pd.h"
+#include <string.h>
+
+#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, 2, 512, 8, -1, -1 );
+ 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<FRAMES_PER_BLOCK; j++ )
+ {
+ /* Generate a sawtooth wave by incrementing a variable. */
+ phases[0] += PHASE_INCREMENT;
+ /* The signal range is -1.0 to +1.0 so wrap around if we go over. */
+ if( phases[0] > 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/pd/portaudio/portmidi-macosx/Makefile b/pd/portaudio/portmidi-macosx/Makefile
new file mode 100644
index 00000000..d8667355
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/Makefile
@@ -0,0 +1,24 @@
+CC = cc
+CFLAGS = -Wmost
+LDFLAGS = -framework Carbon -framework CoreMIDI
+OBJS = ptdarwin.o pmutil.o pmmacosx.o pmdarwin.o portmidi.o
+LIBS =
+
+all: libportmidi.a pmtest
+
+libportmidi.a: portmidi.h porttime.h pminternal.h $(OBJS)
+ rm -f libportmidi.a
+ ar rv libportmidi.a $(OBJS)
+ ranlib libportmidi.a
+
+pmtest: pmtest.c libportmidi.a
+ $(CC) $(CFLAGS) pmtest.c $(OBJS) -o pmtest $(LDFLAGS) $(LIBS)
+
+pmmacosx.o: pmmacosx.c portmidi.h pminternal.h pmmacosx.h porttime.h
+pmdarwin.o: pmdarwin.c portmidi.h pmmacosx.h
+pmutil.o: pmutil.c portmidi.h pmutil.h pminternal.h
+portmidi.o: portmidi.c portmidi.h pminternal.h
+ptdarwin.o: ptdarwin.c porttime.h portmidi.h
+
+clean:
+ rm -f pmtest *.o
diff --git a/pd/portaudio/portmidi-macosx/README b/pd/portaudio/portmidi-macosx/README
new file mode 100644
index 00000000..89c0e6fa
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/README
@@ -0,0 +1,12 @@
+PortMidi for MacOS X / Darwin
+Jon Parise <jparise@cmu.edu>
+$Date: 2002-07-29 17:06:16 $
+
+This is the MacOS X / Darwin port of the PortMidi library from the Carnegie
+Mellon Computer Music Group. It is based on the Apple CoreAudio MIDI
+interface.
+
+This port was finished in early 2002. At this point, I consider the code
+base complete.
+
+- Jon
diff --git a/pd/portaudio/portmidi-macosx/pmdarwin.c b/pd/portaudio/portmidi-macosx/pmdarwin.c
new file mode 100644
index 00000000..510339c3
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/pmdarwin.c
@@ -0,0 +1,36 @@
+/*
+ * PortMidi OS-dependent interface for Darwin (MacOS X)
+ * Jon Parise <jparise@cmu.edu>
+ *
+ * $Id: pmdarwin.c,v 1.1.1.1 2002-07-29 17:06:16 ggeiger Exp $
+ */
+
+/*
+ * This file only needs to implement pm_init(), which calls various
+ * routines to register the available midi devices. This file must
+ * be separate from the main portmidi.c file because it is system
+ * dependent, and it is separate from, say, pmwinmm.c, because it
+ * might need to register devices for winmm, directx, and others.
+ */
+
+#include <stdlib.h>
+#include "portmidi.h"
+#include "pmmacosx.h"
+
+PmError pm_init()
+{
+ return pm_macosx_init();
+}
+
+PmError pm_term()
+{
+ return pm_macosx_term();
+}
+
+PmDeviceID Pm_GetDefaultInputDeviceID() { return 0; };
+PmDeviceID Pm_GetDefaultOutputDeviceID() { return 0; };
+
+void *pm_alloc(size_t s) { return malloc(s); }
+
+void pm_free(void *ptr) { free(ptr); }
+
diff --git a/pd/portaudio/portmidi-macosx/pminternal.h b/pd/portaudio/portmidi-macosx/pminternal.h
new file mode 100644
index 00000000..2a92e16d
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/pminternal.h
@@ -0,0 +1,100 @@
+/* pminternal.h -- header for interface implementations */
+
+/* this file is included by files that implement library internals */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/* these are defined in system-specific file */
+void *pm_alloc(size_t s);
+void pm_free(void *ptr);
+
+struct pm_internal_struct;
+
+/* these do not use PmInternal because it is not defined yet... */
+typedef PmError (*pm_write_fn)(struct pm_internal_struct *midi,
+ PmEvent *buffer, long length);
+typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,
+ void *driverInfo);
+typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);
+typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);
+
+typedef struct {
+ pm_write_fn write;
+ pm_open_fn open;
+ pm_abort_fn abort;
+ pm_close_fn close;
+} pm_fns_node, *pm_fns_type;
+
+/* when open fails, the dictionary gets this set of functions: */
+extern pm_fns_node pm_none_dictionary;
+
+typedef struct {
+ PmDeviceInfo pub;
+ void *descriptor; /* system-specific data to open device */
+ pm_fns_type dictionary;
+} descriptor_node, *descriptor_type;
+
+
+#define pm_descriptor_max 32
+extern descriptor_node descriptors[pm_descriptor_max];
+extern int descriptor_index;
+
+
+typedef unsigned long (*time_get_proc_type)(void *time_info);
+
+typedef struct pm_internal_struct {
+ short write_flag; /* MIDI_IN, or MIDI_OUT */
+ int device_id; /* which device is open (index to descriptors) */
+ PmTimeProcPtr time_proc; /* where to get the time */
+ void *time_info; /* pass this to get_time() */
+ PmEvent *buffer; /* input or output buffer */
+ long buffer_len; /* how big is the buffer */
+ long latency; /* time delay in ms between timestamps and actual output */
+ /* set to zero to get immediate, simple blocking output */
+ /* if latency is zero, timestamps will be ignored */
+ int overflow; /* set to non-zero if input is dropped */
+ int flush; /* flag to drop incoming sysex data because of overflow */
+ int sysex_in_progress; /* use for overflow management */
+ struct pm_internal_struct *thru;
+ PmTimestamp last_msg_time; /* timestamp of last message */
+ long head;
+ long tail;
+ pm_fns_type dictionary; /* implementation functions */
+ void *descriptor; /* system-dependent state */
+} PmInternal;
+
+
+typedef struct {
+ long head;
+ long tail;
+ long len;
+ long msg_size;
+ long overflow;
+ char *buffer;
+} PmQueueRep;
+
+
+PmError pm_init(void); /* defined in a system-specific file */
+PmError pm_term(void); /* defined in a system-specific file */
+int pm_in_device(int n, char *interf, char *device);
+int pm_out_device(int n, char *interf, char *device);
+PmError none_write(PmInternal *midi, PmEvent *buffer, long length);
+PmError pm_success_fn(PmInternal *midi);
+PmError pm_fail_fn(PmInternal *midi);
+long pm_in_poll(PmInternal *midi);
+long pm_out_poll(PmInternal *midi);
+
+PmError pm_add_device(char *interf, char *name, int input, void *descriptor,
+ pm_fns_type dictionary);
+
+void pm_enqueue(PmInternal *midi, PmEvent *event);
+
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/pd/portaudio/portmidi-macosx/pmmacosx.c b/pd/portaudio/portmidi-macosx/pmmacosx.c
new file mode 100644
index 00000000..0aafcf7f
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/pmmacosx.c
@@ -0,0 +1,336 @@
+/*
+ * Platform interface to the MacOS X CoreMIDI framework
+ *
+ * Jon Parise <jparise@cmu.edu>
+ *
+ * $Id: pmmacosx.c,v 1.1.1.1 2002-07-29 17:06:16 ggeiger Exp $
+ */
+
+#include "portmidi.h"
+#include "pminternal.h"
+#include "porttime.h"
+#include "pmmacosx.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <CoreServices/CoreServices.h>
+#include <CoreMIDI/MIDIServices.h>
+
+#define PACKET_BUFFER_SIZE 1024
+
+static MIDIClientRef client = NULL; /* Client handle to the MIDI server */
+static MIDIPortRef portIn = NULL; /* Input port handle */
+static MIDIPortRef portOut = NULL; /* Output port handle */
+
+extern pm_fns_node pm_macosx_in_dictionary;
+extern pm_fns_node pm_macosx_out_dictionary;
+
+static int
+midi_length(long msg)
+{
+ int status, high, low;
+ static int high_lengths[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 through 0x70 */
+ 3, 3, 3, 3, 2, 2, 3, 1 /* 0x80 through 0xf0 */
+ };
+ static int low_lengths[] = {
+ 1, 1, 3, 2, 1, 1, 1, 1, /* 0xf0 through 0xf8 */
+ 1, 1, 1, 1, 1, 1, 1, 1 /* 0xf9 through 0xff */
+ };
+
+ status = msg & 0xFF;
+ high = status >> 4;
+ low = status & 15;
+
+ return (high != 0xF0) ? high_lengths[high] : low_lengths[low];
+}
+
+static PmTimestamp
+get_timestamp(PmInternal *midi)
+{
+ PmTimeProcPtr time_proc;
+
+ /* Set the time procedure accordingly */
+ time_proc = midi->time_proc;
+ if (time_proc == NULL) {
+ time_proc = Pt_Time;
+ }
+
+ return (*time_proc)(midi->time_info);
+}
+
+/* called when MIDI packets are received */
+static void
+readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon)
+{
+ PmInternal *midi;
+ PmEvent event;
+ MIDIPacket *packet;
+ unsigned int packetIndex;
+
+ /* Retrieve the context for this connection */
+ midi = (PmInternal *) connRefCon;
+
+ packet = (MIDIPacket *) &newPackets->packet[0];
+ for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) {
+
+ /* Build the PmMessage for the PmEvent structure */
+ switch (packet->length) {
+ case 1:
+ event.message = Pm_Message(packet->data[0], 0, 0);
+ break;
+ case 2:
+ event.message = Pm_Message(packet->data[0], packet->data[1], 0);
+ break;
+ case 3:
+ event.message = Pm_Message(packet->data[0], packet->data[1],
+ packet->data[2]);
+ break;
+ default:
+ /* Skip packets that are too large to fit in a PmMessage */
+ continue;
+ }
+
+ /* Set the timestamp and dispatch this message */
+ event.timestamp = get_timestamp(midi);
+ pm_enqueue(midi, &event);
+
+ /* Advance to the next packet in the packet list */
+ packet = MIDIPacketNext(packet);
+ }
+}
+
+static PmError
+midi_in_open(PmInternal *midi, void *driverInfo)
+{
+ MIDIEndpointRef endpoint;
+
+ endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
+ if (endpoint == NULL) {
+ return pmInvalidDeviceId;
+ }
+
+ if (MIDIPortConnectSource(portIn, endpoint, midi) != noErr) {
+ return pmHostError;
+ }
+
+ return pmNoError;
+}
+
+static PmError
+midi_in_close(PmInternal *midi)
+{
+ MIDIEndpointRef endpoint;
+
+ endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
+ if (endpoint == NULL) {
+ return pmInvalidDeviceId;
+ }
+
+ if (MIDIPortDisconnectSource(portIn, endpoint) != noErr) {
+ return pmHostError;
+ }
+
+ return pmNoError;
+}
+
+static PmError
+midi_out_open(PmInternal *midi, void *driverInfo)
+{
+ /*
+ * MIDISent() only requires an output port (portOut) and a valid MIDI
+ * endpoint (which we've already created and stored in the PmInternal
+ * structure). Therefore, no additional work needs to be done here to
+ * open the device for output.
+ */
+
+ return pmNoError;
+}
+
+static PmError
+midi_out_close(PmInternal *midi)
+{
+ return pmNoError;
+}
+
+static PmError
+midi_abort(PmInternal *midi)
+{
+ return pmNoError;
+}
+
+static PmError
+midi_write(PmInternal *midi, PmEvent *events, long length)
+{
+ Byte packetBuffer[PACKET_BUFFER_SIZE];
+ MIDIEndpointRef endpoint;
+ MIDIPacketList *packetList;
+ MIDIPacket *packet;
+ MIDITimeStamp timestamp;
+ PmTimeProcPtr time_proc;
+ PmEvent event;
+ unsigned int pm_time;
+ unsigned int eventIndex;
+ unsigned int messageLength;
+ Byte message[3];
+
+ endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
+ if (endpoint == NULL) {
+ return pmInvalidDeviceId;
+ }
+
+ /* Make sure the packetBuffer is large enough */
+ if (length > PACKET_BUFFER_SIZE) {
+ return pmHostError;
+ }
+
+ /*
+ * Initialize the packet list. Each packet contains bytes that are to
+ * be played at the same time.
+ */
+ packetList = (MIDIPacketList *) packetBuffer;
+ if ((packet = MIDIPacketListInit(packetList)) == NULL) {
+ return pmHostError;
+ }
+
+ /* Set the time procedure accordingly */
+ time_proc = midi->time_proc;
+ if (time_proc == NULL) {
+ time_proc = Pt_Time;
+ }
+
+ /* Extract the event data and pack it into the message buffer */
+ for (eventIndex = 0; eventIndex < length; eventIndex++) {
+ event = events[eventIndex];
+
+ /* Compute the timestamp */
+ pm_time = (*time_proc)(midi->time_info);
+ timestamp = pm_time + midi->latency;
+
+ messageLength = midi_length(event.message);
+ message[0] = Pm_MessageStatus(event.message);
+ message[1] = Pm_MessageData1(event.message);
+ message[2] = Pm_MessageData2(event.message);
+
+ /* Add this message to the packet list */
+ packet = MIDIPacketListAdd(packetList, sizeof(packetBuffer), packet,
+ timestamp, messageLength, message);
+ if (packet == NULL) {
+ return pmHostError;
+ }
+ }
+
+ if (MIDISend(portOut, endpoint, packetList) != noErr) {
+ return pmHostError;
+ }
+
+ return pmNoError;
+}
+
+pm_fns_node pm_macosx_in_dictionary = {
+ none_write,
+ midi_in_open,
+ midi_abort,
+ midi_in_close
+};
+
+pm_fns_node pm_macosx_out_dictionary = {
+ midi_write,
+ midi_out_open,
+ midi_abort,
+ midi_out_close
+};
+
+PmError
+pm_macosx_init(void)
+{
+ OSStatus status;
+ ItemCount numDevices, numInputs, numOutputs;
+ MIDIEndpointRef endpoint;
+ CFStringEncoding defaultEncoding;
+ CFStringRef deviceName;
+ char nameBuf[256];
+ int i;
+
+ /* Determine the number of MIDI devices on the system */
+ numDevices = MIDIGetNumberOfDevices();
+ numInputs = MIDIGetNumberOfSources();
+ numOutputs = MIDIGetNumberOfDestinations();
+
+ /* Return prematurely if no devices exist on the system */
+ if (numDevices <= 0) {
+ return pmHostError;
+ }
+
+ /* Determine the default system character encording */
+ defaultEncoding = CFStringGetSystemEncoding();
+
+ /* Iterate over the MIDI input devices */
+ for (i = 0; i < numInputs; i++) {
+ endpoint = MIDIGetSource(i);
+ if (endpoint == NULL) {
+ continue;
+ }
+
+ /* Get the name of this device */
+ MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &deviceName);
+ CFStringGetCString(deviceName, nameBuf, 256, defaultEncoding);
+ CFRelease(deviceName);
+
+ /* Register this device with PortMidi */
+ pm_add_device("CoreMIDI", nameBuf, TRUE, (void *)endpoint,
+ &pm_macosx_in_dictionary);
+ }
+
+ /* Iterate over the MIDI output devices */
+ for (i = 0; i < numOutputs; i++) {
+ endpoint = MIDIGetDestination(i);
+ if (endpoint == NULL) {
+ continue;
+ }
+
+ /* Get the name of this device */
+ MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &deviceName);
+ CFStringGetCString(deviceName, nameBuf, 256, defaultEncoding);
+ CFRelease(deviceName);
+
+ /* Register this device with PortMidi */
+ pm_add_device("CoreMIDI", nameBuf, FALSE, (void *)endpoint,
+ &pm_macosx_out_dictionary);
+ }
+
+ /* Initialize the client handle */
+ status = MIDIClientCreate(CFSTR("PortMidi"), NULL, NULL, &client);
+ if (status != noErr) {
+ fprintf(stderr, "Could not initialize client: %d\n", (int)status);
+ return pmHostError;
+ }
+
+ /* Create the input port */
+ status = MIDIInputPortCreate(client, CFSTR("Input port"), readProc, NULL,
+ &portIn);
+ if (status != noErr) {
+ fprintf(stderr, "Could not create input port: %d\n", (int)status);
+ return pmHostError;
+ }
+
+ /* Create the output port */
+ status = MIDIOutputPortCreate(client, CFSTR("Output port"), &portOut);
+ if (status != noErr) {
+ fprintf(stderr, "Could not create output port: %d\n", (int)status);
+ return pmHostError;
+ }
+
+ return pmNoError;
+}
+
+PmError
+pm_macosx_term(void)
+{
+ if (client != NULL) MIDIClientDispose(client);
+ if (portIn != NULL) MIDIPortDispose(portIn);
+ if (portOut != NULL) MIDIPortDispose(portOut);
+
+ return pmNoError;
+}
diff --git a/pd/portaudio/portmidi-macosx/pmmacosx.h b/pd/portaudio/portmidi-macosx/pmmacosx.h
new file mode 100644
index 00000000..15e9551d
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/pmmacosx.h
@@ -0,0 +1,4 @@
+/* system-specific definitions */
+
+PmError pm_macosx_init(void);
+PmError pm_macosx_term(void);
diff --git a/pd/portaudio/portmidi-macosx/pmtest b/pd/portaudio/portmidi-macosx/pmtest
new file mode 100644
index 00000000..8adc5334
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/pmtest
Binary files differ
diff --git a/pd/portaudio/portmidi-macosx/pmtest.c b/pd/portaudio/portmidi-macosx/pmtest.c
new file mode 100644
index 00000000..5628d25e
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/pmtest.c
@@ -0,0 +1,136 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "portmidi.h"
+#include "porttime.h"
+#include "pminternal.h"
+
+#define LATENCY 0
+#define NUM_ECHOES 10
+
+int
+main()
+{
+ int i = 0;
+ int n = 0;
+ PmStream *midi_in;
+ PmStream *midi_out;
+ PmError err;
+ char line[80];
+ PmEvent buffer[NUM_ECHOES];
+ int transpose;
+ int delay;
+ int status, data1, data2;
+ int statusprefix;
+
+
+
+ /* always start the timer before you start midi */
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+
+
+ for (i = 0; i < Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ printf("%d: %s, %s", i, info->interf, info->name);
+ if (info->input) printf(" (input)");
+ if (info->output) printf(" (output)");
+ printf("\n");
+ }
+
+ /* OPEN INPUT DEVICE */
+
+ printf("Type input number: ");
+ while (n != 1) {
+ n = scanf("%d", &i);
+ gets(line);
+ }
+
+ err = Pm_OpenInput(&midi_in, i, NULL, 100, NULL, NULL, NULL);
+ if (err) {
+ printf("could not open midi device: %s\n", Pm_GetErrorText(err));
+ exit(1);
+ }
+ printf("Midi Input opened.\n");
+
+ /* OPEN OUTPUT DEVICE */
+
+ printf("Type output number: ");
+ n = 0;
+ while (n != 1) {
+ n = scanf("%d", &i);
+ gets(line);
+ }
+
+ err = Pm_OpenOutput(&midi_out, i, NULL, 0, NULL, NULL, LATENCY);
+ if (err) {
+ printf("could not open midi device: %s\n", Pm_GetErrorText(err));
+ exit(1);
+ }
+ printf("Midi Output opened with %d ms latency.\n", LATENCY);
+
+
+
+ /* Get input from user for parameters */
+ printf("Type number of milliseconds for echoes: ");
+ n = 0;
+ while (n != 1) {
+ n = scanf("%d", &delay);
+ gets(line);
+ }
+
+ printf("Type number of semitones to transpose up: ");
+ n = 0;
+ while (n != 1) {
+ n = scanf("%d", &transpose);
+ gets(line);
+ }
+
+
+
+ /* loop, echoing input back transposed with multiple taps */
+
+ printf("Press C2 on the keyboard (2 octaves below middle C) to quit.\nWaiting for MIDI input...\n");
+
+ do {
+ err = Pm_Read(midi_in, buffer, 1);
+ if (err == 0) continue; /* no bytes read. */
+
+ /* print a hash mark for each event read. */
+ printf("#");
+ fflush(stdout);
+
+ status = Pm_MessageStatus(buffer[0].message);
+ data1 = Pm_MessageData1(buffer[0].message);
+ data2 = Pm_MessageData2(buffer[0].message);
+ statusprefix = status >> 4;
+
+ /* ignore messages other than key-down and key-up */
+ if ((statusprefix != 0x9) && (statusprefix != 0x8)) continue;
+
+ printf("\nReceived key message = %X %X %X, at time %ld\n", status, data1, data2, buffer[0].timestamp);
+ fflush(stdout);
+
+ /* immediately send the echoes to PortMIDI */
+ for (i = 1; i < NUM_ECHOES; i++) {
+ buffer[i].message = Pm_Message(status, data1 + transpose, data2 >> i);
+ buffer[i].timestamp = buffer[0].timestamp + (i * delay);
+ }
+ Pm_Write(midi_out, buffer, NUM_ECHOES);
+ } while (data1 != 36); /* quit when C2 is pressed */
+
+ printf("Key C2 pressed. Exiting...\n");
+ fflush(stdout);
+
+ /* Give the echoes time to finish before quitting. */
+ sleep(((NUM_ECHOES * delay) / 1000) + 1);
+
+ Pm_Close(midi_in);
+ Pm_Close(midi_out);
+
+ printf("Done.\n");
+ return 0;
+}
+
+
+
diff --git a/pd/portaudio/portmidi-macosx/pmutil.c b/pd/portaudio/portmidi-macosx/pmutil.c
new file mode 100644
index 00000000..f3582a42
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/pmutil.c
@@ -0,0 +1,86 @@
+/* pmutil.c -- some helpful utilities for building midi
+ applications that use PortMidi
+ */
+#include "stdlib.h"
+#include "memory.h"
+#include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+
+
+PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg)
+{
+ PmQueueRep *queue = (PmQueueRep *) malloc(sizeof(PmQueueRep));
+ if (!queue) return NULL;
+ queue->len = num_msgs * bytes_per_msg;
+ queue->buffer = malloc(queue->len);
+ if (!queue->buffer) {
+ free(queue);
+ return NULL;
+ }
+ queue->head = 0;
+ queue->tail = 0;
+ queue->msg_size = bytes_per_msg;
+ queue->overflow = FALSE;
+ return queue;
+}
+
+
+PmError Pm_QueueDestroy(PmQueue *q)
+{
+ PmQueueRep *queue = (PmQueueRep *) q;
+ if (!queue || !queue->buffer) return pmBadPtr;
+ free(queue->buffer);
+ free(queue);
+ return pmNoError;
+}
+
+
+PmError Pm_Dequeue(PmQueue *q, void *msg)
+{
+ long head;
+ PmQueueRep *queue = (PmQueueRep *) q;
+ if (queue->overflow) {
+ queue->overflow = FALSE;
+ return pmBufferOverflow;
+ }
+ head = queue->head; /* make sure this is written after access */
+ if (head == queue->tail) return 0;
+ memcpy(msg, queue->buffer + head, queue->msg_size);
+ head += queue->msg_size;
+ if (head == queue->len) head = 0;
+ queue->head = head;
+ return 1; /* success */
+}
+
+
+/* source should not enqueue data if overflow is set */
+/**/
+PmError Pm_Enqueue(PmQueue *q, void *msg)
+{
+ PmQueueRep *queue = (PmQueueRep *) q;
+ long tail = queue->tail;
+ memcpy(queue->buffer + tail, msg, queue->msg_size);
+ tail += queue->msg_size;
+ if (tail == queue->len) tail = 0;
+ if (tail == queue->head) {
+ queue->overflow = TRUE;
+ /* do not update tail, so message is lost */
+ return pmBufferOverflow;
+ }
+ queue->tail = tail;
+ return pmNoError;
+}
+
+
+int Pm_QueueFull(PmQueue *q)
+{
+ PmQueueRep *queue = (PmQueueRep *) q;
+ long tail = queue->tail;
+ tail += queue->msg_size;
+ if (tail == queue->len) {
+ tail = 0;
+ }
+ return (tail == queue->head);
+}
+
diff --git a/pd/portaudio/portmidi-macosx/pmutil.h b/pd/portaudio/portmidi-macosx/pmutil.h
new file mode 100644
index 00000000..b6268ed3
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/pmutil.h
@@ -0,0 +1,44 @@
+/* pmutil.h -- some helpful utilities for building midi
+ applications that use PortMidi
+ */
+
+typedef void PmQueue;
+
+/*
+ A single-reader, single-writer queue is created by
+ Pm_QueueCreate(), which takes the number of messages and
+ the message size as parameters. The queue only accepts
+ fixed sized messages. Returns NULL if memory cannot be allocated.
+
+ Pm_QueueDestroy() destroys the queue and frees its storage.
+ */
+
+PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg);
+PmError Pm_QueueDestroy(PmQueue *queue);
+
+/*
+ Pm_Dequeue() removes one item from the queue, copying it into msg.
+ Returns 1 if successful, and 0 if the queue is empty.
+ Returns pmBufferOverflow and clears the overflow flag if
+ the flag is set.
+ */
+PmError Pm_Dequeue(PmQueue *queue, void *msg);
+
+
+/*
+ Pm_Enqueue() inserts one item into the queue, copying it from msg.
+ Returns pmNoError if successful and pmBufferOverflow if the queue was
+ already full. If pmBufferOverflow is returned, the overflow flag is set.
+ */
+PmError Pm_Enqueue(PmQueue *queue, void *msg);
+
+
+/*
+ Pm_QueueFull() returns non-zero if the queue is full
+ Pm_QueueEmpty() returns non-zero if the queue is empty
+
+ Either condition may change immediately because a parallel
+ enqueue or dequeue operation could be in progress.
+ */
+int Pm_QueueFull(PmQueue *queue);
+#define Pm_QueueEmpty(m) (m->head == m->tail)
diff --git a/pd/portaudio/portmidi-macosx/portmidi.c b/pd/portaudio/portmidi-macosx/portmidi.c
new file mode 100644
index 00000000..c2a32ae7
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/portmidi.c
@@ -0,0 +1,358 @@
+#include "stdlib.h"
+#include "portmidi.h"
+#include "pminternal.h"
+
+#define is_empty(midi) ((midi)->tail == (midi)->head)
+
+static int pm_initialized = FALSE;
+
+int descriptor_index = 0;
+descriptor_node descriptors[pm_descriptor_max];
+
+
+/* pm_add_device -- describe interface/device pair to library
+ *
+ * This is called at intialization time, once for each
+ * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1)
+ * The strings are retained but NOT COPIED, so do not destroy them!
+ *
+ * returns pmInvalidDeviceId if device memory is exceeded
+ * otherwise returns pmNoError
+ */
+PmError pm_add_device(char *interf, char *name, int input,
+ void *descriptor, pm_fns_type dictionary)
+{
+ if (descriptor_index >= pm_descriptor_max) {
+ return pmInvalidDeviceId;
+ }
+ descriptors[descriptor_index].pub.interf = interf;
+ descriptors[descriptor_index].pub.name = name;
+ descriptors[descriptor_index].pub.input = input;
+ descriptors[descriptor_index].pub.output = !input;
+ descriptors[descriptor_index].descriptor = descriptor;
+ descriptors[descriptor_index].dictionary = dictionary;
+ descriptor_index++;
+ return pmNoError;
+}
+
+
+PmError Pm_Initialize( void )
+{
+ if (!pm_initialized) {
+ PmError err = pm_init(); /* defined by implementation specific file */
+ if (err) return err;
+ pm_initialized = TRUE;
+ }
+ return pmNoError;
+}
+
+
+PmError Pm_Terminate( void )
+{
+ PmError err = pmNoError;
+ if (pm_initialized) {
+ err = pm_term(); /* defined by implementation specific file */
+ /* note that even when pm_term() fails, we mark portmidi as
+ not initialized */
+ pm_initialized = FALSE;
+ }
+ return err;
+}
+
+
+int Pm_CountDevices( void )
+{
+ PmError err = Pm_Initialize();
+ if (err) return err;
+
+ return descriptor_index;
+}
+
+
+const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id )
+{
+ PmError err = Pm_Initialize();
+ if (err) return NULL;
+
+ if (id >= 0 && id < descriptor_index) {
+ return &descriptors[id].pub;
+ }
+ return NULL;
+}
+
+
+/* failure_fn -- "noop" function pointer */
+/**/
+PmError failure_fn(PmInternal *midi)
+{
+ return pmBadPtr;
+}
+
+
+/* pm_success_fn -- "noop" function pointer */
+/**/
+PmError pm_success_fn(PmInternal *midi)
+{
+ return pmNoError;
+}
+
+
+PmError none_write(PmInternal *midi, PmEvent *buffer, long length)
+{
+ return length; /* if we return 0, caller might get into a loop */
+}
+
+PmError pm_fail_fn(PmInternal *midi)
+{
+ return pmBadPtr;
+}
+
+static PmError none_open(PmInternal *midi, void *driverInfo)
+{
+ return pmBadPtr;
+}
+
+#define none_abort pm_fail_fn
+
+#define none_close pm_fail_fn
+
+
+pm_fns_node pm_none_dictionary = {
+ none_write, none_open,
+ none_abort, none_close };
+
+
+/* Pm_Read -- read up to length longs from source into buffer */
+/*
+ * returns number of longs actually read, or error code
+ When the reader wants data:
+ if overflow_flag:
+ do not get anything
+ empty the buffer (read_ptr = write_ptr)
+ clear overflow_flag
+ return pmBufferOverflow
+ get data
+ return number of messages
+
+
+ */
+PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length)
+{
+ PmInternal *midi = (PmInternal *) stream;
+ int n = 0;
+ long head = midi->head;
+ while (head != midi->tail && n < length) {
+ *buffer++ = midi->buffer[head++];
+ if (head == midi->buffer_len) head = 0;
+ n++;
+ }
+ midi->head = head;
+ if (midi->overflow) {
+ midi->head = midi->tail;
+ midi->overflow = FALSE;
+ return pmBufferOverflow;
+ }
+ return n;
+}
+
+
+PmError Pm_Poll( PortMidiStream *stream )
+{
+ PmInternal *midi = (PmInternal *) stream;
+ return midi->head != midi->tail;
+}
+
+
+PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length)
+{
+ PmInternal *midi = (PmInternal *) stream;
+ return (*midi->dictionary->write)(midi, buffer, length);
+}
+
+
+PmError Pm_WriteShort( PortMidiStream *stream, long when, long msg)
+{
+ PmEvent event;
+ event.timestamp = when;
+ event.message = msg;
+ return Pm_Write(stream, &event, 1);
+}
+
+
+PmError Pm_OpenInput( PortMidiStream** stream,
+ PmDeviceID inputDevice,
+ void *inputDriverInfo,
+ long bufferSize,
+ PmTimeProcPtr time_proc,
+ void *time_info,
+ PmStream *thru)
+{
+ PmInternal *midi;
+
+ PmError err = Pm_Initialize();
+ if (err) return err;
+
+ if (inputDevice < 0 || inputDevice >= descriptor_index) {
+ return pmInvalidDeviceId;
+ }
+
+ if (!descriptors[inputDevice].pub.input) {
+ return pmInvalidDeviceId;
+ }
+
+ midi = (PmInternal *) malloc(sizeof(PmInternal));
+ *stream = midi;
+ if (!midi) return pmInsufficientMemory;
+
+ midi->head = 0;
+ midi->tail = 0;
+ midi->dictionary = &pm_none_dictionary;
+ midi->overflow = FALSE;
+ midi->flush = FALSE;
+ midi->sysex_in_progress = FALSE;
+ midi->buffer_len = bufferSize;
+ midi->buffer = (PmEvent *) pm_alloc(sizeof(PmEvent) * midi->buffer_len);
+ if (!midi->buffer) return pmInsufficientMemory;
+ midi->latency = 0;
+ midi->thru = thru;
+ midi->time_proc = time_proc;
+ midi->time_info = time_info;
+ midi->device_id = inputDevice;
+ midi->dictionary = descriptors[inputDevice].dictionary;
+ midi->write_flag = FALSE;
+ err = (*midi->dictionary->open)(midi, inputDriverInfo);
+ if (err) {
+ pm_free(midi->buffer);
+ *stream = NULL;
+ }
+ return err;
+}
+
+
+PmError Pm_OpenOutput( PortMidiStream** stream,
+ PmDeviceID outputDevice,
+ void *outputDriverInfo,
+ long bufferSize,
+ PmTimeProcPtr time_proc,
+ void *time_info,
+ long latency )
+{
+ PmInternal *midi;
+
+ PmError err = Pm_Initialize();
+ if (err) return err;
+
+ if (outputDevice < 0 || outputDevice >= descriptor_index) {
+ return pmInvalidDeviceId;
+ }
+
+ if (!descriptors[outputDevice].pub.output) {
+ return pmInvalidDeviceId;
+ }
+
+ midi = (PmInternal *) pm_alloc(sizeof(PmInternal));
+ *stream = midi;
+ if (!midi) return pmInsufficientMemory;
+
+ midi->head = 0;
+ midi->tail = 0;
+ midi->buffer_len = bufferSize;
+ midi->buffer = NULL;
+ midi->device_id = outputDevice;
+ midi->dictionary = descriptors[outputDevice].dictionary;
+ midi->time_proc = time_proc;
+ midi->time_info = time_info;
+ midi->latency = latency;
+ midi->write_flag = TRUE;
+ err = (*midi->dictionary->open)(midi, outputDriverInfo);
+ if (err) {
+ *stream = NULL;
+ pm_free(midi); // Fixed by Ning Hu, Sep.2001
+ }
+ return err;
+}
+
+
+PmError Pm_Abort( PortMidiStream* stream )
+{
+ PmInternal *midi = (PmInternal *) stream;
+ return (*midi->dictionary->abort)(midi);
+}
+
+
+PmError Pm_Close( PortMidiStream *stream )
+{
+ PmInternal *midi = (PmInternal *) stream;
+ return (*midi->dictionary->close)(midi);
+}
+
+
+const char *Pm_GetErrorText( PmError errnum )
+{
+ const char *msg;
+
+ switch(errnum)
+ {
+ case pmNoError: msg = "Success"; break;
+ case pmHostError: msg = "Host error."; break;
+ case pmInvalidDeviceId: msg = "Invalid device ID."; break;
+ case pmInsufficientMemory: msg = "Insufficient memory."; break;
+ case pmBufferTooSmall: msg = "Buffer too small."; break;
+ case pmBadPtr: msg = "Bad pointer."; break;
+ case pmInternalError: msg = "Internal PortMidi Error."; break;
+ default: msg = "Illegal error number."; break;
+ }
+ return msg;
+}
+
+
+long pm_next_time(PmInternal *midi)
+{
+ return midi->buffer[midi->head].timestamp;
+}
+
+
+/* source should not enqueue data if overflow is set */
+/*
+ When producer has data to enqueue:
+ if buffer is full:
+ set overflow_flag and flush_flag
+ return
+ else if overflow_flag:
+ return
+ else if flush_flag:
+ if sysex message is in progress:
+ return
+ else:
+ clear flush_flag
+ // fall through to enqueue data
+ enqueue the data
+
+ */
+void pm_enqueue(PmInternal *midi, PmEvent *event)
+{
+ long tail = midi->tail;
+ midi->buffer[tail++] = *event;
+ if (tail == midi->buffer_len) tail = 0;
+ if (tail == midi->head || midi->overflow) {
+ midi->overflow = TRUE;
+ midi->flush = TRUE;
+ return;
+ }
+ if (midi->flush) {
+ if (midi->sysex_in_progress) return;
+ else midi->flush = FALSE;
+ }
+ midi->tail = tail;
+}
+
+
+int pm_queue_full(PmInternal *midi)
+{
+ long tail = midi->tail + 1;
+ if (tail == midi->buffer_len) tail = 0;
+ return tail == midi->head;
+}
+
+
+
diff --git a/pd/portaudio/portmidi-macosx/portmidi.h b/pd/portaudio/portmidi-macosx/portmidi.h
new file mode 100644
index 00000000..3e648c90
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/portmidi.h
@@ -0,0 +1,338 @@
+#ifndef PORT_MIDI_H
+#define PORT_MIDI_H
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * PortMidi Portable Real-Time Audio Library
+ * PortMidi API Header File
+ * Latest version available at: http://www.cs.cmu.edu/~music/portmidi/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ * Copyright (c) 2001 Roger B. Dannenberg
+ *
+ * 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.
+ *
+ */
+
+/* CHANGELOG FOR PORTMIDI -- THIS VERSION IS 1.0
+ *
+ * 21Jan02 RBD Added tests in Pm_OpenInput() and Pm_OpenOutput() to
+ * prevent opening an input as output and vice versa.
+ * Added comments and documentation.
+ * Implemented Pm_Terminate().
+ */
+
+#ifndef FALSE
+ #define FALSE 0
+#endif
+#ifndef TRUE
+ #define TRUE 1
+#endif
+
+
+typedef enum {
+ pmNoError = 0,
+
+ pmHostError = -10000,
+ pmInvalidDeviceId, /* out of range or
+ output device when input is requested or
+ input device when output is requested */
+ //pmInvalidFlag,
+ pmInsufficientMemory,
+ pmBufferTooSmall,
+ pmBufferOverflow,
+ pmBadPtr,
+ pmInternalError
+} PmError;
+
+/*
+ Pm_Initialize() is the library initialisation function - call this before
+ using the library.
+*/
+
+PmError Pm_Initialize( void );
+
+/*
+ Pm_Terminate() is the library termination function - call this after
+ using the library.
+*/
+
+PmError Pm_Terminate( void );
+
+/*
+ Return host specific error number. All host-specific errors are translated
+ to the single error class pmHostError. To find out the original error
+ number, call Pm_GetHostError().
+ This can be called after a function returns a PmError equal to pmHostError.
+*/
+int Pm_GetHostError();
+
+/*
+ Translate the error number into a human readable message.
+*/
+const char *Pm_GetErrorText( PmError errnum );
+
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pm_CountDevices()-1.
+
+ Devices may support input, output or both. Device 0 is always the "default"
+ device. Other platform specific devices are specified by positive device
+ ids.
+*/
+
+typedef int PmDeviceID;
+#define pmNoDevice -1
+
+typedef struct {
+ int structVersion;
+ const char *interf;
+ const char *name;
+ int input; /* true iff input is available */
+ int output; /* true iff output is available */
+} PmDeviceInfo;
+
+
+int Pm_CountDevices( void );
+/*
+ Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()
+
+ Return the default device ID or pmNoDevice if there is no devices.
+ The result can be passed to Pm_OpenMidi().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PM_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ID by using
+ the supplied application "pm_devs".
+*/
+PmDeviceID Pm_GetDefaultInputDeviceID( void );
+PmDeviceID Pm_GetDefaultOutputDeviceID( void );
+
+/*
+ PmTimestamp is used to represent a millisecond clock with arbitrary
+ start time. The type is used for all MIDI timestampes and clocks.
+*/
+
+typedef long PmTimestamp;
+
+/* TRUE if t1 before t2? */
+#define PmBefore(t1,t2) ((t1-t2) < 0)
+
+
+/*
+ Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo 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 PortMidi implementation and must
+ not be manipulated or freed. The pointer is guaranteed to be valid
+ between calls to Pm_Initialize() and Pm_Terminate().
+*/
+
+const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
+
+
+/*
+ A single PortMidiStream is a descriptor for an open MIDI device.
+*/
+
+typedef void PortMidiStream;
+#define PmStream PortMidiStream
+
+typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
+
+
+/*
+ Pm_Open() opens a device; for either input or output.
+
+ Port is the address of a PortMidiStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PmDeviceID above.)
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or handle 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 PmDeviceID above.)
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or handle processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ latency is the delay in milliseconds applied to timestamps to determine
+ when the output should actually occur.
+
+ time_proc is a pointer to a procedure that returns time in milliseconds. It
+ may be NULL, in which case a default millisecond timebase is used.
+
+ time_info is a pointer passed to time_proc.
+
+ thru points to a PmMidi descriptor opened for output; Midi input will be
+ copied to this output. To disable Midi thru, use NULL.
+
+ return value:
+ Upon success Pm_Open() returns PmNoError and places a pointer to a
+ valid PortMidiStream in the stream argument.
+ If a call to Pm_Open() fails a nonzero error code is returned (see
+ PMError above) and the value of port is invalid.
+
+*/
+
+PmError Pm_OpenInput( PortMidiStream** stream,
+ PmDeviceID inputDevice,
+ void *inputDriverInfo,
+ long bufferSize,
+ PmTimeProcPtr time_proc,
+ void *time_info,
+ PmStream* thru );
+
+
+PmError Pm_OpenOutput( PortMidiStream** stream,
+ PmDeviceID outputDevice,
+ void *outputDriverInfo,
+ long bufferSize,
+ PmTimeProcPtr time_proc,
+ void *time_info,
+ long latency );
+
+
+/*
+ Pm_Abort() terminates outgoing messages immediately
+ */
+PmError Pm_Abort( PortMidiStream* stream );
+
+/*
+ Pm_Close() closes a midi stream, flushing any pending buffers.
+*/
+
+PmError Pm_Close( PortMidiStream* stream );
+
+
+/*
+ Pm_Message() encodes a short Midi message into a long word. If data1
+ and/or data2 are not present, use zero. The port parameter is the
+ index of the Midi port if the device supports more than one.
+
+ Pm_MessagePort(), Pm_MessageStatus(), Pm_MessageData1(), and
+ Pm_MessageData2() extract fields from a long-encoded midi message.
+*/
+
+#define Pm_Message(status, data1, data2) \
+ ((((data2) << 16) & 0xFF0000) | \
+ (((data1) << 8) & 0xFF00) | \
+ ((status) & 0xFF))
+
+#define Pm_MessageStatus(msg) ((msg) & 0xFF)
+#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
+#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
+
+/* All midi data comes in the form of PmEvent structures. A sysex
+ message is encoded as a sequence of PmEvent structures, with each
+ structure carrying 4 bytes of the message, i.e. only the first
+ PmEvent carries the status byte.
+
+ When receiving sysex messages, the sysex message is terminated
+ by either an EOX status byte (anywhere in the 4 byte message) or
+ by a non-real-time status byte in the low order byte of message.
+ If you get a non-real-time status byte, it means the sysex message
+ was somehow truncated. It is permissible to interleave real-time
+ messages within sysex messages.
+ */
+
+typedef long PmMessage;
+
+typedef struct {
+ PmMessage message;
+ PmTimestamp timestamp;
+} PmEvent;
+
+
+/*
+ Pm_Read() retrieves midi data into a buffer, and returns the number
+ of events read. Result is a non-negative number unless an error occurs,
+ in which case a PmError value will be returned.
+
+ Buffer Overflow
+
+ The problem: if an input overflow occurs, data will be lost, ultimately
+ because there is no flow control all the way back to the data source.
+ When data is lost, the receiver should be notified and some sort of
+ graceful recovery should take place, e.g. you shouldn't resume receiving
+ in the middle of a long sysex message.
+
+ With a lock-free fifo, which is pretty much what we're stuck with to
+ enable portability to the Mac, it's tricky for the producer and consumer
+ to synchronously reset the buffer and resume normal operation.
+
+ Solution: the buffer managed by PortMidi will be flushed when an overflow
+ occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow)
+ and ordinary processing resumes as soon as a new message arrives. The
+ remainder of a partial sysex message is not considered to be a "new
+ message" and will be flushed as well.
+
+*/
+
+PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length );
+
+/*
+ Pm_Poll() tests whether input is available, returning TRUE, FALSE, or
+ an error value.
+*/
+
+PmError Pm_Poll( PortMidiStream *stream);
+
+/*
+ Pm_Write() writes midi data from a buffer. This may contain short
+ messages or sysex messages that are converted into a sequence of PmEvent
+ structures. Use Pm_WriteSysEx() to write a sysex message stored as a
+ contiguous array of bytes.
+*/
+
+PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length );
+
+/*
+ Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
+*/
+
+PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, long msg);
+
+/*
+ Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
+*/
+PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, char *msg);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_MIDI_H */
diff --git a/pd/portaudio/portmidi-macosx/porttime.h b/pd/portaudio/portmidi-macosx/porttime.h
new file mode 100644
index 00000000..8592106d
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/porttime.h
@@ -0,0 +1,30 @@
+/* porttime.h -- portable interface to millisecond timer */
+
+/* Should there be a way to choose the source of time here? */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef enum {
+ ptNoError = 0,
+ ptHostError = -10000,
+ ptAlreadyStarted,
+ ptAlreadyStopped
+} PtError;
+
+
+typedef long PtTimestamp;
+
+typedef int (PtCallback)( PtTimestamp timestamp, void *userData );
+
+
+PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
+PtError Pt_Stop();
+int Pt_Started();
+PtTimestamp Pt_Time();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/pd/portaudio/portmidi-macosx/ptdarwin.c b/pd/portaudio/portmidi-macosx/ptdarwin.c
new file mode 100644
index 00000000..51cf5fde
--- /dev/null
+++ b/pd/portaudio/portmidi-macosx/ptdarwin.c
@@ -0,0 +1,58 @@
+/*
+ * Portable timer implementation for Darwin / MacOS X
+ *
+ * Jon Parise <jparise@cmu.edu>
+ *
+ * $Id: ptdarwin.c,v 1.1.1.1 2002-07-29 17:06:16 ggeiger Exp $
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include "porttime.h"
+
+#define TRUE 1
+#define FALSE 0
+
+static int time_started_flag = FALSE;
+static struct timeval time_offset;
+
+PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
+{
+ struct timezone tz;
+
+ if (callback) printf("error in porttime: callbacks not implemented\n");
+ time_started_flag = TRUE;
+ gettimeofday(&time_offset, &tz);
+
+ return ptNoError;
+}
+
+
+PtError Pt_Stop()
+{
+ time_started_flag = FALSE;
+ return ptNoError;
+}
+
+
+int Pt_Started()
+{
+ return time_started_flag;
+}
+
+
+PtTimestamp Pt_Time()
+{
+ long seconds, milliseconds;
+ struct timeval now;
+ struct timezone tz;
+
+ gettimeofday(&now, &tz);
+ seconds = now.tv_sec - time_offset.tv_sec;
+ milliseconds = (now.tv_usec - time_offset.tv_usec) / 1000;
+
+ return (seconds * 1000 + milliseconds);
+}
+
+
+