Version 3.0
authorGary Scavone <gary@music.mcgill.ca>
Wed, 9 Oct 2013 21:46:54 +0000 (23:46 +0200)
committerStephen Sinclair <sinclair@music.mcgill.ca>
Wed, 9 Oct 2013 23:08:39 +0000 (01:08 +0200)
90 files changed:
INSTALL [deleted file]
README [deleted file]
RtAudio.cpp
RtAudio.h
RtError.h [new file with mode: 0644]
asio/asio.h [new file with mode: 0644]
asio/asiodrivers.h [new file with mode: 0644]
asio/asiolist.h [new file with mode: 0644]
asio/asiosys.h [new file with mode: 0644]
asio/ginclude.h [new file with mode: 0644]
config.guess [changed mode: 0755->0644]
config.sub [changed mode: 0644->0755]
configure.ac
doc/doxygen/Doxyfile
doc/doxygen/footer.html
doc/doxygen/header.html
doc/doxygen/tutorial.txt
doc/images/ccrma.gif [changed mode: 0755->0644]
doc/images/mcgill.gif [new file with mode: 0644]
doc/release.txt
install [new file with mode: 0644]
install.sh [changed mode: 0644->0755]
readme [new file with mode: 0644]
tests/DirectSound/Debug/.placeholder [deleted file]
tests/DirectSound/Release/.placeholder [deleted file]
tests/DirectSound/call_inout.dsp [deleted file]
tests/DirectSound/call_playtwo.dsp [deleted file]
tests/DirectSound/call_saw.dsp [deleted file]
tests/DirectSound/call_twostreams.dsp [deleted file]
tests/DirectSound/in_out.dsp [deleted file]
tests/DirectSound/info.dsp [deleted file]
tests/DirectSound/play_raw.dsp [deleted file]
tests/DirectSound/play_saw.dsp [deleted file]
tests/DirectSound/record_raw.dsp [deleted file]
tests/DirectSound/rtaudio.dsw [deleted file]
tests/DirectSound/twostreams.dsp [deleted file]
tests/Makefile.in
tests/Windows/Debug/.placeholder [new file with mode: 0644]
tests/Windows/Release/.placeholder [new file with mode: 0644]
tests/Windows/asio.cpp [new file with mode: 0644]
tests/Windows/asio.h [new file with mode: 0644]
tests/Windows/asiodrivers.cpp [new file with mode: 0644]
tests/Windows/asiodrivers.h [new file with mode: 0644]
tests/Windows/asiodrvr.h [new file with mode: 0644]
tests/Windows/asiolist.cpp [new file with mode: 0644]
tests/Windows/asiolist.h [new file with mode: 0644]
tests/Windows/asiosys.h [new file with mode: 0644]
tests/Windows/call_inout.dsp [new file with mode: 0644]
tests/Windows/call_playtwo.dsp [new file with mode: 0644]
tests/Windows/call_saw.dsp [new file with mode: 0644]
tests/Windows/call_twostreams.dsp [new file with mode: 0644]
tests/Windows/ginclude.h [new file with mode: 0644]
tests/Windows/iasiodrv.h [new file with mode: 0644]
tests/Windows/in_out.dsp [new file with mode: 0644]
tests/Windows/info.dsp [new file with mode: 0644]
tests/Windows/play_raw.dsp [new file with mode: 0644]
tests/Windows/play_saw.dsp [new file with mode: 0644]
tests/Windows/record_raw.dsp [new file with mode: 0644]
tests/Windows/rtaudio.dsw [new file with mode: 0644]
tests/Windows/twostreams.dsp [new file with mode: 0644]
tests/asio/Debug/.placeholder [deleted file]
tests/asio/Release/.placeholder [deleted file]
tests/asio/asio.cpp [deleted file]
tests/asio/asio.h [deleted file]
tests/asio/asiodrivers.cpp [deleted file]
tests/asio/asiodrivers.h [deleted file]
tests/asio/asiodrvr.h [deleted file]
tests/asio/asiolist.cpp [deleted file]
tests/asio/asiolist.h [deleted file]
tests/asio/asiosys.h [deleted file]
tests/asio/call_inout.dsp [deleted file]
tests/asio/call_saw.dsp [deleted file]
tests/asio/ginclude.h [deleted file]
tests/asio/iasiodrv.h [deleted file]
tests/asio/in_out.dsp [deleted file]
tests/asio/info.dsp [deleted file]
tests/asio/play_raw.dsp [deleted file]
tests/asio/play_saw.dsp [deleted file]
tests/asio/record_raw.dsp [deleted file]
tests/asio/rtaudio.dsw [deleted file]
tests/call_inout.cpp
tests/call_playtwo.cpp [deleted file]
tests/call_saw.cpp
tests/call_twostreams.cpp [deleted file]
tests/in_out.cpp
tests/info.cpp
tests/play_raw.cpp
tests/play_saw.cpp
tests/record_raw.cpp
tests/twostreams.cpp

diff --git a/INSTALL b/INSTALL
deleted file mode 100644 (file)
index abef59e..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,28 +0,0 @@
-RtAudio - a C++ class which provides a common API for realtime audio input/output across Linux (native ALSA and OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound and ASIO) operating systems.
-
-By Gary P. Scavone, 2002.
-
-To configure and compile (on Unix systems):
-
-1. Unpack the RtAudio distribution (tar -xzf rtaudio-2.x.tar.gz).
-2. From within the directory containing this file, run configure:
-
-   ./configure
-
-3. From within the "tests" directory, type "make".
-
-A few options can be passed to configure, including:
-
-  --enable-debug = enable various debug output
-  --with-alsa = choose native ALSA API support (linux only)
-
-Typing "./configure --help" will display all the available options.
-
-If you wish to use a different compiler than that selected by configure, specify that compiler in the command line (ex. to use CC):
-
-  ./configure CXX=CC
-
-
-For Windows Users:
-
-Visual C++ 6.0 project files are included for the test programs.  For projects using the DirectSound API, go to the /tests/DirectSound/ directory.  For projects using the ASIO API, go to the /tests/asio/ directory.
diff --git a/README b/README
deleted file mode 100644 (file)
index 3dd5718..0000000
--- a/README
+++ /dev/null
@@ -1,63 +0,0 @@
-RtAudio - a C++ class which provides a common API for realtime audio input/output across Linux (native ALSA and OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound and ASIO) operating systems.
-
-By Gary P. Scavone, 2002.
-
-This distribution of the Synthesis ToolKit in C++ (STK) contains the following:
-
-doc:      RtAudio documentation
-tests:    example RtAudio programs
-
-
-OVERVIEW:
-
-RtAudio is a C++ class which provides a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA and OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound and ASIO) operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following goals:
-
-  - object oriented C++ design
-  - simple, common API across all supported platforms
-  - single independent header and source file for easy inclusion in programming projects
-  - blocking functionality
-  - callback functionality
-  - extensive audio device parameter control
-  - audio device capability probing
-  - automatic internal conversion for data format, channel number compensation, de-interleaving, and byte-swapping
-  - control over multiple audio streams and devices with a single instance
-
-RtAudio incorporates the concept of audio streams, which represent audio output (playback) and/or input (recording). Available audio devices and their capabilities can be enumerated and then specified when opening a stream. Multiple streams can run at the same time and, when allowed by the underlying audio API, a single device can serve multiple streams.
-
-The RtAudio API provides both blocking (synchronous) and callback (asyncronous) functionality. Callbacks are typically used in conjunction with graphical user interfaces (GUI). Blocking functionality is often necessary for explicit control of multiple input/output stream synchronization or when audio must be synchronized with other system events. 
-
-
-FURTHER READING:
-
-For complete documentation on RtAudio, see the doc directory of the distribution or surf to http://www-ccrma.stanford.edu/~gary/rtaudio/.
-
-
-LEGAL AND ETHICAL:
-
-The RtAudio license is similar to the the MIT License, with the added "feature" that modifications be sent to the developer.
-
-    RtAudio: a realtime audio i/o C++ class
-    Copyright (c) 2001-2002 Gary P. Scavone
-
-    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.
index 8e44ba2d4b54f08a070e2e4c8edb99a4f912ab86..4211e4e3654f7a42248a68547996ef714267731b 100644 (file)
@@ -1,16 +1,16 @@
 /************************************************************************/
 /*! \class RtAudio
-    \brief Realtime audio i/o C++ class.
+    \brief Realtime audio i/o C++ classes.
 
     RtAudio provides a common API (Application Programming Interface)
-    for realtime audio input/output across Linux (native ALSA and
-    OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound
-    and ASIO) operating systems.
+    for realtime audio input/output across Linux (native ALSA, Jack,
+    and OSS), SGI, Macintosh OS X (CoreAudio), and Windows
+    (DirectSound and ASIO) operating systems.
 
-    RtAudio WWW site: http://www-ccrma.stanford.edu/~gary/rtaudio/
+    RtAudio WWW site: http://music.mcgill.ca/~gary/rtaudio/
 
     RtAudio: a realtime audio i/o C++ class
-    Copyright (c) 2001-2002 Gary P. Scavone
+    Copyright (c) 2001-2004 Gary P. Scavone
 
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation files
 */
 /************************************************************************/
 
-// RtAudio: Version 2.1.1, 24 October 2002
+// RtAudio: Version 3.0, 11 March 2004
 
 #include "RtAudio.h"
-#include <vector>
-#include <stdio.h>
-#include <iostream.h>
+#include <iostream>
 
 // Static variable definitions.
-const unsigned int RtAudio :: SAMPLE_RATES[] = {
+const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
+const unsigned int RtApi::SAMPLE_RATES[] = {
   4000, 5512, 8000, 9600, 11025, 16000, 22050,
   32000, 44100, 48000, 88200, 96000, 176400, 192000
 };
-const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1;
-const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2;
-const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4;
-const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8;
-const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16;
-const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32;
 
 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
   #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
-  #define MUTEX_LOCK(A)       EnterCriticalSection(A)
+  #define MUTEX_DESTROY(A)    DeleteCriticalSection(A);
+  #define MUTEX_LOCK(A)      EnterCriticalSection(A)
   #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)
 #else // pthread API
   #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
+  #define MUTEX_DESTROY(A)    pthread_mutex_destroy(A);
   #define MUTEX_LOCK(A)       pthread_mutex_lock(A)
   #define MUTEX_UNLOCK(A)     pthread_mutex_unlock(A)
 #endif
@@ -72,93 +67,202 @@ const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32;
 //
 // *************************************************** //
 
-RtAudio :: RtAudio()
+RtAudio :: RtAudio( RtAudioApi api )
 {
-  initialize();
-
-  if (nDevices <= 0) {
-    sprintf(message, "RtAudio: no audio devices found!");
-    error(RtError::NO_DEVICES_FOUND);
- }
+  initialize( api );
 }
 
-RtAudio :: RtAudio(int *streamId,
-                   int outputDevice, int outputChannels,
-                   int inputDevice, int inputChannels,
-                   RTAUDIO_FORMAT format, int sampleRate,
-                   int *bufferSize, int numberOfBuffers)
+RtAudio :: RtAudio( int outputDevice, int outputChannels,
+                    int inputDevice, int inputChannels,
+                    RtAudioFormat format, int sampleRate,
+                    int *bufferSize, int numberOfBuffers, RtAudioApi api )
 {
-  initialize();
-
-  if (nDevices <= 0) {
-    sprintf(message, "RtAudio: no audio devices found!");
-    error(RtError::NO_DEVICES_FOUND);
-  }
+  initialize( api );
 
   try {
-    *streamId = openStream(outputDevice, outputChannels, inputDevice, inputChannels,
-                           format, sampleRate, bufferSize, numberOfBuffers);
+    rtapi_->openStream( outputDevice, outputChannels,
+                        inputDevice, inputChannels,
+                        format, sampleRate,
+                        bufferSize, numberOfBuffers );
   }
   catch (RtError &exception) {
-    // deallocate the RTAUDIO_DEVICE structures
-    if (devices) free(devices);
+    // Deallocate the RtApi instance.
+    delete rtapi_;
     throw exception;
   }
 }
 
 RtAudio :: ~RtAudio()
 {
-  // close any existing streams
-  while ( streams.size() )
-    closeStream( streams.begin()->first );
+  delete rtapi_;
+}
+
+void RtAudio :: openStream( int outputDevice, int outputChannels,
+                            int inputDevice, int inputChannels,
+                            RtAudioFormat format, int sampleRate,
+                            int *bufferSize, int numberOfBuffers )
+{
+  rtapi_->openStream( outputDevice, outputChannels, inputDevice,
+                      inputChannels, format, sampleRate,
+                      bufferSize, numberOfBuffers );
+}
+
+void RtAudio::initialize( RtAudioApi api )
+{
+  rtapi_ = 0;
+
+  // First look for a compiled match to a specified API value. If one
+  // of these constructors throws an error, it will be passed up the
+  // inheritance chain.
+#if defined(__LINUX_JACK__)
+  if ( api == LINUX_JACK )
+    rtapi_ = new RtApiJack();
+#endif
+#if defined(__LINUX_ALSA__)
+  if ( api == LINUX_ALSA )
+    rtapi_ = new RtApiAlsa();
+#endif
+#if defined(__LINUX_OSS__)
+  if ( api == LINUX_OSS )
+    rtapi_ = new RtApiOss();
+#endif
+#if defined(__WINDOWS_ASIO__)
+  if ( api == WINDOWS_ASIO )
+    rtapi_ = new RtApiAsio();
+#endif
+#if defined(__WINDOWS_DS__)
+  if ( api == WINDOWS_DS )
+    rtapi_ = new RtApiDs();
+#endif
+#if defined(__IRIX_AL__)
+  if ( api == IRIX_AL )
+    rtapi_ = new RtApiAl();
+#endif
+#if defined(__MACOSX_CORE__)
+  if ( api == MACOSX_CORE )
+    rtapi_ = new RtApiCore();
+#endif
+
+  if ( rtapi_ ) return;
+  if ( api > 0 ) {
+    // No compiled support for specified API value.
+    throw RtError( "RtAudio: no compiled support for specified API argument!", RtError::INVALID_PARAMETER );
+  }
+
+  // No specified API ... search for "best" option.
+  try {
+#if defined(__LINUX_JACK__)
+    rtapi_ = new RtApiJack();
+#elif defined(__WINDOWS_ASIO__)
+    rtapi_ = new RtApiAsio();
+#elif defined(__IRIX_AL__)
+    rtapi_ = new RtApiAl();
+#elif defined(__MACOSX_CORE__)
+    rtapi_ = new RtApiCore();
+#else
+    ;
+#endif
+  }
+  catch (RtError &) {
+#if defined(__RTAUDIO_DEBUG__)
+    fprintf(stderr, "\nRtAudio: no devices found for first api option (JACK, ASIO, Al, or CoreAudio).\n\n");
+#endif
+    rtapi_ = 0;
+  }
+
+  if ( rtapi_ ) return;
+
+// Try second API support
+  if ( rtapi_ == 0 ) {
+    try {
+#if defined(__LINUX_ALSA__)
+      rtapi_ = new RtApiAlsa();
+#elif defined(__WINDOWS_DS__)
+      rtapi_ = new RtApiDs();
+#else
+      ;
+#endif
+    }
+    catch (RtError &) {
+#if defined(__RTAUDIO_DEBUG__)
+      fprintf(stderr, "\nRtAudio: no devices found for second api option (Alsa or DirectSound).\n\n");
+#endif
+      rtapi_ = 0;
+    }
+  }
+
+  if ( rtapi_ ) return;
+
+  // Try third API support
+  if ( rtapi_ == 0 ) {
+#if defined(__LINUX_OSS__)
+    try {
+      rtapi_ = new RtApiOss();
+    }
+    catch (RtError &error) {
+      rtapi_ = 0;
+    }
+#else
+    ;
+#endif
+  }
+
+  if ( rtapi_ == 0 ) {
+    // No devices found.
+    throw RtError( "RtAudio: no devices found for compiled audio APIs!", RtError::NO_DEVICES_FOUND );
+  }
+}
+
+RtApi :: RtApi()
+{
+  stream_.mode = UNINITIALIZED;
+  stream_.apiHandle = 0;
+  MUTEX_INITIALIZE(&stream_.mutex);
+}
 
-  // deallocate the RTAUDIO_DEVICE structures
-  if (devices) free(devices);
+RtApi :: ~RtApi()
+{
+  MUTEX_DESTROY(&stream_.mutex);
 }
 
-int RtAudio :: openStream(int outputDevice, int outputChannels,
-                          int inputDevice, int inputChannels,
-                          RTAUDIO_FORMAT format, int sampleRate,
-                          int *bufferSize, int numberOfBuffers)
+void RtApi :: openStream( int outputDevice, int outputChannels,
+                         int inputDevice, int inputChannels,
+                         RtAudioFormat format, int sampleRate,
+                         int *bufferSize, int numberOfBuffers )
 {
-  static int streamKey = 0; // Unique stream identifier ... OK for multiple instances.
+  if ( stream_.mode != UNINITIALIZED ) {
+    sprintf(message_, "RtApi: only one open stream allowed per class instance.");
+    error(RtError::INVALID_STREAM);
+  }
 
   if (outputChannels < 1 && inputChannels < 1) {
-    sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero.");
+    sprintf(message_,"RtApi: one or both 'channel' parameters must be greater than zero.");
     error(RtError::INVALID_PARAMETER);
   }
 
   if ( formatBytes(format) == 0 ) {
-    sprintf(message,"RtAudio: 'format' parameter value is undefined.");
+    sprintf(message_,"RtApi: 'format' parameter value is undefined.");
     error(RtError::INVALID_PARAMETER);
   }
 
   if ( outputChannels > 0 ) {
-    if (outputDevice > nDevices || outputDevice < 0) {
-      sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
+    if (outputDevice > nDevices_ || outputDevice < 0) {
+      sprintf(message_,"RtApi: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
       error(RtError::INVALID_PARAMETER);
     }
   }
 
   if ( inputChannels > 0 ) {
-    if (inputDevice > nDevices || inputDevice < 0) {
-      sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
+    if (inputDevice > nDevices_ || inputDevice < 0) {
+      sprintf(message_,"RtApi: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
       error(RtError::INVALID_PARAMETER);
     }
   }
 
-  // Allocate a new stream structure.
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM));
-  if (stream == NULL) {
-    sprintf(message, "RtAudio: memory allocation error!");
-    error(RtError::MEMORY_ERROR);
-  }
-  stream->mode = UNINITIALIZED;
-  MUTEX_INITIALIZE(&stream->mutex);
-
+  clearStreamInfo();
   bool result = FAILURE;
   int device, defaultDevice = 0;
-  STREAM_MODE mode;
+  StreamMode mode;
   int channels;
   if ( outputChannels > 0 ) {
 
@@ -172,22 +276,23 @@ int RtAudio :: openStream(int outputDevice, int outputChannels,
     else
       device = outputDevice - 1;
 
-    for (int i=-1; i<nDevices; i++) {
-      if (i >= 0 ) { 
+    for ( int i=-1; i<nDevices_; i++ ) {
+      if ( i >= 0 ) { 
         if ( i == defaultDevice ) continue;
         device = i;
       }
-      if (devices[device].probed == false) {
+      if (devices_[device].probed == false) {
         // If the device wasn't successfully probed before, try it
-        // again now.
-        clearDeviceInfo(&devices[device]);
-        probeDeviceInfo(&devices[device]);
+        // (again) now.
+        clearDeviceInfo(&devices_[device]);
+        probeDeviceInfo(&devices_[device]);
       }
-      if ( devices[device].probed )
-        result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
+      if ( devices_[device].probed )
+        result = probeDeviceOpen(device, mode, channels, sampleRate,
                                  format, bufferSize, numberOfBuffers);
-      if (result == SUCCESS) break;
+      if ( result == SUCCESS ) break;
       if ( outputDevice > 0 ) break;
+      clearStreamInfo();
     }
   }
 
@@ -203,153 +308,116 @@ int RtAudio :: openStream(int outputDevice, int outputChannels,
     else
       device = inputDevice - 1;
 
-    for (int i=-1; i<nDevices; i++) {
+    for (int i=-1; i<nDevices_; i++) {
       if (i >= 0 ) { 
         if ( i == defaultDevice ) continue;
         device = i;
       }
-      if (devices[device].probed == false) {
+      if (devices_[device].probed == false) {
         // If the device wasn't successfully probed before, try it
-        // again now.
-        clearDeviceInfo(&devices[device]);
-        probeDeviceInfo(&devices[device]);
+        // (again) now.
+        clearDeviceInfo(&devices_[device]);
+        probeDeviceInfo(&devices_[device]);
       }
-      if ( devices[device].probed )
-        result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
+      if ( devices_[device].probed )
+        result = probeDeviceOpen(device, mode, channels, sampleRate,
                                  format, bufferSize, numberOfBuffers);
       if (result == SUCCESS) break;
       if ( outputDevice > 0 ) break;
     }
   }
 
-  streams[++streamKey] = (void *) stream;
   if ( result == SUCCESS )
-    return streamKey;
+    return;
 
   // If we get here, all attempted probes failed.  Close any opened
-  // devices and delete the allocated stream.
-  closeStream(streamKey);
+  // devices and clear the stream structure.
+  if ( stream_.mode != UNINITIALIZED ) closeStream();
+  clearStreamInfo();
   if ( ( outputDevice == 0 && outputChannels > 0 )
        || ( inputDevice == 0 && inputChannels > 0 ) )
-    sprintf(message,"RtAudio: no devices found for given parameters.");
+    sprintf(message_,"RtApi: no devices found for given stream parameters.");
   else
-    sprintf(message,"RtAudio: unable to open specified device(s) with given stream parameters.");
+    sprintf(message_,"RtApi: unable to open specified device(s) with given stream parameters.");
   error(RtError::INVALID_PARAMETER);
 
-  return -1;
+  return;
 }
 
-int RtAudio :: getDeviceCount(void)
+int RtApi :: getDeviceCount(void)
 {
-  return nDevices;
+  return devices_.size();
 }
 
-void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info)
+RtAudioDeviceInfo RtApi :: getDeviceInfo( int device )
 {
-  if (device > nDevices || device < 1) {
-    sprintf(message, "RtAudio: invalid device specifier (%d)!", device);
+  if (device > (int) devices_.size() || device < 1) {
+    sprintf(message_, "RtApi: invalid device specifier (%d)!", device);
     error(RtError::INVALID_DEVICE);
   }
 
+  RtAudioDeviceInfo info;
   int deviceIndex = device - 1;
 
   // If the device wasn't successfully probed before, try it now (or again).
-  if (devices[deviceIndex].probed == false) {
-    clearDeviceInfo(&devices[deviceIndex]);
-    probeDeviceInfo(&devices[deviceIndex]);
-  }
-
-  // Clear the info structure.
-  memset(info, 0, sizeof(RTAUDIO_DEVICE));
-
-  strncpy(info->name, devices[deviceIndex].name, 128);
-  info->probed = devices[deviceIndex].probed;
-  if ( info->probed == true ) {
-    info->maxOutputChannels = devices[deviceIndex].maxOutputChannels;
-    info->maxInputChannels = devices[deviceIndex].maxInputChannels;
-    info->maxDuplexChannels = devices[deviceIndex].maxDuplexChannels;
-    info->minOutputChannels = devices[deviceIndex].minOutputChannels;
-    info->minInputChannels = devices[deviceIndex].minInputChannels;
-    info->minDuplexChannels = devices[deviceIndex].minDuplexChannels;
-    info->hasDuplexSupport = devices[deviceIndex].hasDuplexSupport;
-    info->nSampleRates = devices[deviceIndex].nSampleRates;
-    if (info->nSampleRates == -1) {
-      info->sampleRates[0] = devices[deviceIndex].sampleRates[0];
-      info->sampleRates[1] = devices[deviceIndex].sampleRates[1];
-    }
-    else {
-      for (int i=0; i<info->nSampleRates; i++)
-        info->sampleRates[i] = devices[deviceIndex].sampleRates[i];
-    }
-    info->nativeFormats = devices[deviceIndex].nativeFormats;
-    if ( deviceIndex == getDefaultOutputDevice() ||
-         deviceIndex == getDefaultInputDevice() )
-      info->isDefault = true;
-  }
-
-  return;
+  if (devices_[deviceIndex].probed == false) {
+    clearDeviceInfo(&devices_[deviceIndex]);
+    probeDeviceInfo(&devices_[deviceIndex]);
+  }
+
+  info.name.append( devices_[deviceIndex].name );
+  info.probed = devices_[deviceIndex].probed;
+  if ( info.probed == true ) {
+    info.outputChannels = devices_[deviceIndex].maxOutputChannels;
+    info.inputChannels = devices_[deviceIndex].maxInputChannels;
+    info.duplexChannels = devices_[deviceIndex].maxDuplexChannels;
+    for (unsigned int i=0; i<devices_[deviceIndex].sampleRates.size(); i++)
+      info.sampleRates.push_back( devices_[deviceIndex].sampleRates[i] );
+    info.nativeFormats = devices_[deviceIndex].nativeFormats;
+    if ( (deviceIndex == getDefaultOutputDevice()) ||
+         (deviceIndex == getDefaultInputDevice()) )
+      info.isDefault = true;
+  }
+
+  return info;
 }
 
-char * const RtAudio :: getStreamBuffer(int streamId)
+char * const RtApi :: getStreamBuffer(void)
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  return stream->userBuffer;
+  verifyStream();
+  return stream_.userBuffer;
 }
 
-#if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__IRIX_AL__)
-
-extern "C" void *callbackHandler(void * ptr);
-
-void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
+int RtApi :: getDefaultInputDevice(void)
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
-  if ( info->usingCallback ) {
-    sprintf(message, "RtAudio: A callback is already set for this stream!");
-    error(RtError::WARNING);
-    return;
-  }
-
-  info->callback = (void *) callback;
-  info->userData = userData;
-  info->usingCallback = true;
-  info->object = (void *) this;
-  info->streamId = streamId;
-
-  int err = pthread_create(&info->thread, NULL, callbackHandler, &stream->callbackInfo);
-
-  if (err) {
-    info->usingCallback = false;
-    sprintf(message, "RtAudio: error starting callback thread!");
-    error(RtError::THREAD_ERROR);
-  }
+  // Should be implemented in subclasses if appropriate.
+  return 0;
 }
 
-void RtAudio :: cancelStreamCallback(int streamId)
+int RtApi :: getDefaultOutputDevice(void)
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  if (stream->callbackInfo.usingCallback) {
-
-    if (stream->state == STREAM_RUNNING)
-      stopStream( streamId );
+  // Should be implemented in subclasses if appropriate.
+  return 0;
+}
 
-    MUTEX_LOCK(&stream->mutex);
+void RtApi :: closeStream(void)
+{
+  // MUST be implemented in subclasses!
+}
 
-    stream->callbackInfo.usingCallback = false;
-    pthread_cancel(stream->callbackInfo.thread);
-    pthread_join(stream->callbackInfo.thread, NULL);
-    stream->callbackInfo.thread = 0;
-    stream->callbackInfo.callback = NULL;
-    stream->callbackInfo.userData = NULL;
+void RtApi :: probeDeviceInfo( RtApiDevice *info )
+{
+  // MUST be implemented in subclasses!
+}
 
-    MUTEX_UNLOCK(&stream->mutex);
-  }
+bool RtApi :: probeDeviceOpen( int device, StreamMode mode, int channels, 
+                               int sampleRate, RtAudioFormat format,
+                               int *bufferSize, int numberOfBuffers )
+{
+  // MUST be implemented in subclasses!
+  return FAILURE;
 }
 
-#endif
 
 // *************************************************** //
 //
@@ -357,126 +425,1188 @@ void RtAudio :: cancelStreamCallback(int streamId)
 //
 // *************************************************** //
 
-#if defined(__MACOSX_CORE__)
-
-// The OS X CoreAudio API is designed to use a separate callback
-// procedure for each of its audio devices.  A single RtAudio duplex
-// stream using two different devices is supported here, though it
-// cannot be guaranteed to always behave correctly because we cannot
-// synchronize these two callbacks.  This same functionality can be
-// achieved with better synchrony by opening two separate streams for
-// the devices and using RtAudio blocking calls (i.e. tickStream()).
-//
-// The possibility of having multiple RtAudio streams accessing the
-// same CoreAudio device is not currently supported.  The problem
-// involves the inability to install our callbackHandler function for
-// the same device more than once.  I experimented with a workaround
-// for this, but it requires an additional buffer for mixing output
-// data before filling the CoreAudio device buffer.  In the end, I
-// decided it wasn't worth supporting.
-//
-// Property listeners are currently not used.  The issue is what could
-// be done if a critical stream parameter (buffer size, sample rate,
-// device disconnect) notification arrived.  The listeners entail
-// quite a bit of extra code and most likely, a user program wouldn't
-// be prepared for the result anyway.  Some initial listener code is
-// commented out.
-
-void RtAudio :: initialize(void)
-{
-  OSStatus err = noErr;
-  UInt32 dataSize;
-  AudioDeviceID        *deviceList = NULL;
-  nDevices = 0;
-
-  // Find out how many audio devices there are, if any.
-  err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL);
-  if (err != noErr) {
-    sprintf(message, "RtAudio: OSX error getting device info!");
-    error(RtError::SYSTEM_ERROR);
-  }
-
-  nDevices = dataSize / sizeof(AudioDeviceID);
-  if (nDevices == 0) return;
+#if defined(__LINUX_OSS__)
 
-  //  Allocate the RTAUDIO_DEVICE structures.
-  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
-  if (devices == NULL) {
-    sprintf(message, "RtAudio: memory allocation error!");
-    error(RtError::MEMORY_ERROR);
-  }
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/soundcard.h>
+#include <errno.h>
+#include <math.h>
 
-  // Make space for the devices we are about to get.
-  deviceList = (AudioDeviceID  *) malloc( dataSize );
-  if (deviceList == NULL) {
-    sprintf(message, "RtAudio: memory allocation error!");
-    error(RtError::MEMORY_ERROR);
-  }
+#define DAC_NAME "/dev/dsp"
+#define MAX_DEVICES 16
+#define MAX_CHANNELS 16
 
-  // Get the array of AudioDeviceIDs.
-  err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList);
-  if (err != noErr) {
-    free(deviceList);
-    sprintf(message, "RtAudio: OSX error getting device properties!");
-    error(RtError::SYSTEM_ERROR);
-  }
+extern "C" void *ossCallbackHandler(void * ptr);
 
-  // Write device identifiers to device structures and then
-  // probe the device capabilities.
-  for (int i=0; i<nDevices; i++) {
-    devices[i].id[0] = deviceList[i];
-    //probeDeviceInfo(&devices[i]);
-  }
+RtApiOss :: RtApiOss()
+{
+  this->initialize();
 
-  free(deviceList);
+  if (nDevices_ <= 0) {
+    sprintf(message_, "RtApiOss: no Linux OSS audio devices found!");
+    error(RtError::NO_DEVICES_FOUND);
+ }
 }
 
-int RtAudio :: getDefaultInputDevice(void)
+RtApiOss :: ~RtApiOss()
 {
-  AudioDeviceID id;
-  UInt32 dataSize = sizeof( AudioDeviceID );
+  if ( stream_.mode != UNINITIALIZED )
+    closeStream();
+}
 
-  OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice,
-                                              &dataSize, &id );
+void RtApiOss :: initialize(void)
+{
+  // Count cards and devices
+  nDevices_ = 0;
 
-  if (result != noErr) {
-    sprintf( message, "RtAudio: OSX error getting default input device." );
-    error(RtError::WARNING);
-    return 0;
+  // We check /dev/dsp before probing devices.  /dev/dsp is supposed to
+  // be a link to the "default" audio device, of the form /dev/dsp0,
+  // /dev/dsp1, etc...  However, I've seen many cases where /dev/dsp was a
+  // real device, so we need to check for that.  Also, sometimes the
+  // link is to /dev/dspx and other times just dspx.  I'm not sure how
+  // the latter works, but it does.
+  char device_name[16];
+  struct stat dspstat;
+  int dsplink = -1;
+  int i = 0;
+  if (lstat(DAC_NAME, &dspstat) == 0) {
+    if (S_ISLNK(dspstat.st_mode)) {
+      i = readlink(DAC_NAME, device_name, sizeof(device_name));
+      if (i > 0) {
+        device_name[i] = '\0';
+        if (i > 8) { // check for "/dev/dspx"
+          if (!strncmp(DAC_NAME, device_name, 8))
+            dsplink = atoi(&device_name[8]);
+        }
+        else if (i > 3) { // check for "dspx"
+          if (!strncmp("dsp", device_name, 3))
+            dsplink = atoi(&device_name[3]);
+        }
+      }
+      else {
+        sprintf(message_, "RtApiOss: cannot read value of symbolic link %s.", DAC_NAME);
+        error(RtError::SYSTEM_ERROR);
+      }
+    }
   }
-
-  for ( int i=0; i<nDevices; i++ ) {
-    if ( id == devices[i].id[0] ) return i;
+  else {
+    sprintf(message_, "RtApiOss: cannot stat %s.", DAC_NAME);
+    error(RtError::SYSTEM_ERROR);
   }
 
-  return 0;
-}
-
-int RtAudio :: getDefaultOutputDevice(void)
-{
-  AudioDeviceID id;
-  UInt32 dataSize = sizeof( AudioDeviceID );
+  // The OSS API doesn't provide a routine for determining the number
+  // of devices.  Thus, we'll just pursue a brute force method.  The
+  // idea is to start with /dev/dsp(0) and continue with higher device
+  // numbers until we reach MAX_DSP_DEVICES.  This should tell us how
+  // many devices we have ... it is not a fullproof scheme, but hopefully
+  // it will work most of the time.
+  int fd = 0;
+  RtApiDevice device;
+  for (i=-1; i<MAX_DEVICES; i++) {
 
-  OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
-                                              &dataSize, &id );
+    // Probe /dev/dsp first, since it is supposed to be the default device.
+    if (i == -1)
+      sprintf(device_name, "%s", DAC_NAME);
+    else if (i == dsplink)
+      continue; // We've aready probed this device via /dev/dsp link ... try next device.
+    else
+      sprintf(device_name, "%s%d", DAC_NAME, i);
 
-  if (result != noErr) {
-    sprintf( message, "RtAudio: OSX error getting default output device." );
-    error(RtError::WARNING);
-    return 0;
-  }
+    // First try to open the device for playback, then record mode.
+    fd = open(device_name, O_WRONLY | O_NONBLOCK);
+    if (fd == -1) {
+      // Open device for playback failed ... either busy or doesn't exist.
+      if (errno != EBUSY && errno != EAGAIN) {
+        // Try to open for capture
+        fd = open(device_name, O_RDONLY | O_NONBLOCK);
+        if (fd == -1) {
+          // Open device for record failed.
+          if (errno != EBUSY && errno != EAGAIN)
+            continue;
+          else {
+            sprintf(message_, "RtApiOss: OSS record device (%s) is busy.", device_name);
+            error(RtError::WARNING);
+            // still count it for now
+          }
+        }
+      }
+      else {
+        sprintf(message_, "RtApiOss: OSS playback device (%s) is busy.", device_name);
+        error(RtError::WARNING);
+        // still count it for now
+      }
+    }
 
-  for ( int i=0; i<nDevices; i++ ) {
-    if ( id == devices[i].id[0] ) return i;
+    if (fd >= 0) close(fd);
+    device.name.erase();
+    device.name.append( (const char *)device_name, strlen(device_name)+1);
+    devices_.push_back(device);
+    nDevices_++;
   }
-
-  return 0;
 }
 
-static bool deviceSupportsFormat( AudioDeviceID id, bool isInput,
-                                  AudioStreamBasicDescription  *desc, bool isDuplex )
+void RtApiOss :: probeDeviceInfo(RtApiDevice *info)
 {
-  OSStatus result = noErr;
+  int i, fd, channels, mask;
+
+  // The OSS API doesn't provide a means for probing the capabilities
+  // of devices.  Thus, we'll just pursue a brute force method.
+
+  // First try for playback
+  fd = open(info->name.c_str(), O_WRONLY | O_NONBLOCK);
+  if (fd == -1) {
+    // Open device failed ... either busy or doesn't exist
+    if (errno == EBUSY || errno == EAGAIN)
+      sprintf(message_, "RtApiOss: OSS playback device (%s) is busy and cannot be probed.",
+              info->name.c_str());
+    else
+      sprintf(message_, "RtApiOss: OSS playback device (%s) open error.", info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    goto capture_probe;
+  }
+
+  // We have an open device ... see how many channels it can handle
+  for (i=MAX_CHANNELS; i>0; i--) {
+    channels = i;
+    if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
+      // This would normally indicate some sort of hardware error, but under ALSA's
+      // OSS emulation, it sometimes indicates an invalid channel value.  Further,
+      // the returned channel value is not changed. So, we'll ignore the possible
+      // hardware error.
+      continue; // try next channel number
+    }
+    // Check to see whether the device supports the requested number of channels
+    if (channels != i ) continue; // try next channel number
+    // If here, we found the largest working channel value
+    break;
+  }
+  info->maxOutputChannels = i;
+
+  // Now find the minimum number of channels it can handle
+  for (i=1; i<=info->maxOutputChannels; i++) {
+    channels = i;
+    if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
+      continue; // try next channel number
+    // If here, we found the smallest working channel value
+    break;
+  }
+  info->minOutputChannels = i;
+  close(fd);
+
+ capture_probe:
+  // Now try for capture
+  fd = open(info->name.c_str(), O_RDONLY | O_NONBLOCK);
+  if (fd == -1) {
+    // Open device for capture failed ... either busy or doesn't exist
+    if (errno == EBUSY || errno == EAGAIN)
+      sprintf(message_, "RtApiOss: OSS capture device (%s) is busy and cannot be probed.",
+              info->name.c_str());
+    else
+      sprintf(message_, "RtApiOss: OSS capture device (%s) open error.", info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    if (info->maxOutputChannels == 0)
+      // didn't open for playback either ... device invalid
+      return;
+    goto probe_parameters;
+  }
+
+  // We have the device open for capture ... see how many channels it can handle
+  for (i=MAX_CHANNELS; i>0; i--) {
+    channels = i;
+    if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
+      continue; // as above
+    }
+    // If here, we found a working channel value
+    break;
+  }
+  info->maxInputChannels = i;
+
+  // Now find the minimum number of channels it can handle
+  for (i=1; i<=info->maxInputChannels; i++) {
+    channels = i;
+    if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
+      continue; // try next channel number
+    // If here, we found the smallest working channel value
+    break;
+  }
+  info->minInputChannels = i;
+  close(fd);
+
+  if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
+    sprintf(message_, "RtApiOss: device (%s) reports zero channels for input and output.",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    return;
+  }
+
+  // If device opens for both playback and capture, we determine the channels.
+  if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
+    goto probe_parameters;
+
+  fd = open(info->name.c_str(), O_RDWR | O_NONBLOCK);
+  if (fd == -1)
+    goto probe_parameters;
+
+  ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
+  ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
+  if (mask & DSP_CAP_DUPLEX) {
+    info->hasDuplexSupport = true;
+    // We have the device open for duplex ... see how many channels it can handle
+    for (i=MAX_CHANNELS; i>0; i--) {
+      channels = i;
+      if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
+        continue; // as above
+      // If here, we found a working channel value
+      break;
+    }
+    info->maxDuplexChannels = i;
+
+    // Now find the minimum number of channels it can handle
+    for (i=1; i<=info->maxDuplexChannels; i++) {
+      channels = i;
+      if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
+        continue; // try next channel number
+      // If here, we found the smallest working channel value
+      break;
+    }
+    info->minDuplexChannels = i;
+  }
+  close(fd);
+
+ probe_parameters:
+  // At this point, we need to figure out the supported data formats
+  // and sample rates.  We'll proceed by openning the device in the
+  // direction with the maximum number of channels, or playback if
+  // they are equal.  This might limit our sample rate options, but so
+  // be it.
+
+  if (info->maxOutputChannels >= info->maxInputChannels) {
+    fd = open(info->name.c_str(), O_WRONLY | O_NONBLOCK);
+    channels = info->maxOutputChannels;
+  }
+  else {
+    fd = open(info->name.c_str(), O_RDONLY | O_NONBLOCK);
+    channels = info->maxInputChannels;
+  }
+
+  if (fd == -1) {
+    // We've got some sort of conflict ... abort
+    sprintf(message_, "RtApiOss: device (%s) won't reopen during probe.",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    return;
+  }
+
+  // We have an open device ... set to maximum channels.
+  i = channels;
+  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
+    // We've got some sort of conflict ... abort
+    close(fd);
+    sprintf(message_, "RtApiOss: device (%s) won't revert to previous channel setting.",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    return;
+  }
+
+  if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
+    close(fd);
+    sprintf(message_, "RtApiOss: device (%s) can't get supported audio formats.",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    return;
+  }
+
+  // Probe the supported data formats ... we don't care about endian-ness just yet.
+  int format;
+  info->nativeFormats = 0;
+#if defined (AFMT_S32_BE)
+  // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
+  if (mask & AFMT_S32_BE) {
+    format = AFMT_S32_BE;
+    info->nativeFormats |= RTAUDIO_SINT32;
+  }
+#endif
+#if defined (AFMT_S32_LE)
+  /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
+  if (mask & AFMT_S32_LE) {
+    format = AFMT_S32_LE;
+    info->nativeFormats |= RTAUDIO_SINT32;
+  }
+#endif
+  if (mask & AFMT_S8) {
+    format = AFMT_S8;
+    info->nativeFormats |= RTAUDIO_SINT8;
+  }
+  if (mask & AFMT_S16_BE) {
+    format = AFMT_S16_BE;
+    info->nativeFormats |= RTAUDIO_SINT16;
+  }
+  if (mask & AFMT_S16_LE) {
+    format = AFMT_S16_LE;
+    info->nativeFormats |= RTAUDIO_SINT16;
+  }
+
+  // Check that we have at least one supported format
+  if (info->nativeFormats == 0) {
+    close(fd);
+    sprintf(message_, "RtApiOss: device (%s) data format not supported by RtAudio.",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    return;
+  }
+
+  // Set the format
+  i = format;
+  if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
+    close(fd);
+    sprintf(message_, "RtApiOss: device (%s) error setting data format.",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    return;
+  }
+
+  // Probe the supported sample rates.
+  info->sampleRates.clear();
+  for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) {
+    int speed = SAMPLE_RATES[k];
+    if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1 && speed == (int)SAMPLE_RATES[k])
+      info->sampleRates.push_back(speed);
+  }
+
+  if (info->sampleRates.size() == 0) {
+    close(fd);
+    sprintf(message_, "RtApiOss: no supported sample rates found for device (%s).",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
+    return;
+  }
+
+  // That's all ... close the device and return
+  close(fd);
+  info->probed = true;
+  return;
+}
+
+bool RtApiOss :: probeDeviceOpen(int device, StreamMode mode, int channels, 
+                                int sampleRate, RtAudioFormat format,
+                                int *bufferSize, int numberOfBuffers)
+{
+  int buffers, buffer_bytes, device_channels, device_format;
+  int srate, temp, fd;
+  int *handle = (int *) stream_.apiHandle;
+
+  const char *name = devices_[device].name.c_str();
+
+  if (mode == OUTPUT)
+    fd = open(name, O_WRONLY | O_NONBLOCK);
+  else { // mode == INPUT
+    if (stream_.mode == OUTPUT && stream_.device[0] == device) {
+      // We just set the same device for playback ... close and reopen for duplex (OSS only).
+      close(handle[0]);
+      handle[0] = 0;
+      // First check that the number previously set channels is the same.
+      if (stream_.nUserChannels[0] != channels) {
+        sprintf(message_, "RtApiOss: input/output channels must be equal for OSS duplex device (%s).", name);
+        goto error;
+      }
+      fd = open(name, O_RDWR | O_NONBLOCK);
+    }
+    else
+      fd = open(name, O_RDONLY | O_NONBLOCK);
+  }
+
+  if (fd == -1) {
+    if (errno == EBUSY || errno == EAGAIN)
+      sprintf(message_, "RtApiOss: device (%s) is busy and cannot be opened.",
+              name);
+    else
+      sprintf(message_, "RtApiOss: device (%s) cannot be opened.", name);
+    goto error;
+  }
+
+  // Now reopen in blocking mode.
+  close(fd);
+  if (mode == OUTPUT)
+    fd = open(name, O_WRONLY | O_SYNC);
+  else { // mode == INPUT
+    if (stream_.mode == OUTPUT && stream_.device[0] == device)
+      fd = open(name, O_RDWR | O_SYNC);
+    else
+      fd = open(name, O_RDONLY | O_SYNC);
+  }
+
+  if (fd == -1) {
+    sprintf(message_, "RtApiOss: device (%s) cannot be opened.", name);
+    goto error;
+  }
+
+  // Get the sample format mask
+  int mask;
+  if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
+    close(fd);
+    sprintf(message_, "RtApiOss: device (%s) can't get supported audio formats.",
+            name);
+    goto error;
+  }
+
+  // Determine how to set the device format.
+  stream_.userFormat = format;
+  device_format = -1;
+  stream_.doByteSwap[mode] = false;
+  if (format == RTAUDIO_SINT8) {
+    if (mask & AFMT_S8) {
+      device_format = AFMT_S8;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+    }
+  }
+  else if (format == RTAUDIO_SINT16) {
+    if (mask & AFMT_S16_NE) {
+      device_format = AFMT_S16_NE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+    }
+#if BYTE_ORDER == LITTLE_ENDIAN
+    else if (mask & AFMT_S16_BE) {
+      device_format = AFMT_S16_BE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+      stream_.doByteSwap[mode] = true;
+    }
+#else
+    else if (mask & AFMT_S16_LE) {
+      device_format = AFMT_S16_LE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+      stream_.doByteSwap[mode] = true;
+    }
+#endif
+  }
+#if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
+  else if (format == RTAUDIO_SINT32) {
+    if (mask & AFMT_S32_NE) {
+      device_format = AFMT_S32_NE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+    }
+#if BYTE_ORDER == LITTLE_ENDIAN
+    else if (mask & AFMT_S32_BE) {
+      device_format = AFMT_S32_BE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+      stream_.doByteSwap[mode] = true;
+    }
+#else
+    else if (mask & AFMT_S32_LE) {
+      device_format = AFMT_S32_LE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+      stream_.doByteSwap[mode] = true;
+    }
+#endif
+  }
+#endif
+
+  if (device_format == -1) {
+    // The user requested format is not natively supported by the device.
+    if (mask & AFMT_S16_NE) {
+      device_format = AFMT_S16_NE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+    }
+#if BYTE_ORDER == LITTLE_ENDIAN
+    else if (mask & AFMT_S16_BE) {
+      device_format = AFMT_S16_BE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+      stream_.doByteSwap[mode] = true;
+    }
+#else
+    else if (mask & AFMT_S16_LE) {
+      device_format = AFMT_S16_LE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+      stream_.doByteSwap[mode] = true;
+    }
+#endif
+#if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
+    else if (mask & AFMT_S32_NE) {
+      device_format = AFMT_S32_NE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+    }
+#if BYTE_ORDER == LITTLE_ENDIAN
+    else if (mask & AFMT_S32_BE) {
+      device_format = AFMT_S32_BE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+      stream_.doByteSwap[mode] = true;
+    }
+#else
+    else if (mask & AFMT_S32_LE) {
+      device_format = AFMT_S32_LE;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+      stream_.doByteSwap[mode] = true;
+    }
+#endif
+#endif
+    else if (mask & AFMT_S8) {
+      device_format = AFMT_S8;
+      stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+    }
+  }
+
+  if (stream_.deviceFormat[mode] == 0) {
+    // This really shouldn't happen ...
+    close(fd);
+    sprintf(message_, "RtApiOss: device (%s) data format not supported by RtAudio.",
+            name);
+    goto error;
+  }
+
+  // Determine the number of channels for this device.  Note that the
+  // channel value requested by the user might be < min_X_Channels.
+  stream_.nUserChannels[mode] = channels;
+  device_channels = channels;
+  if (mode == OUTPUT) {
+    if (channels < devices_[device].minOutputChannels)
+      device_channels = devices_[device].minOutputChannels;
+  }
+  else { // mode == INPUT
+    if (stream_.mode == OUTPUT && stream_.device[0] == device) {
+      // We're doing duplex setup here.
+      if (channels < devices_[device].minDuplexChannels)
+        device_channels = devices_[device].minDuplexChannels;
+    }
+    else {
+      if (channels < devices_[device].minInputChannels)
+        device_channels = devices_[device].minInputChannels;
+    }
+  }
+  stream_.nDeviceChannels[mode] = device_channels;
+
+  // Attempt to set the buffer size.  According to OSS, the minimum
+  // number of buffers is two.  The supposed minimum buffer size is 16
+  // bytes, so that will be our lower bound.  The argument to this
+  // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
+  // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
+  // We'll check the actual value used near the end of the setup
+  // procedure.
+  buffer_bytes = *bufferSize * formatBytes(stream_.deviceFormat[mode]) * device_channels;
+  if (buffer_bytes < 16) buffer_bytes = 16;
+  buffers = numberOfBuffers;
+  if (buffers < 2) buffers = 2;
+  temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
+  if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
+    close(fd);
+    sprintf(message_, "RtApiOss: error setting fragment size for device (%s).",
+            name);
+    goto error;
+  }
+  stream_.nBuffers = buffers;
+
+  // Set the data format.
+  temp = device_format;
+  if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
+    close(fd);
+    sprintf(message_, "RtApiOss: error setting data format for device (%s).",
+            name);
+    goto error;
+  }
+
+  // Set the number of channels.
+  temp = device_channels;
+  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
+    close(fd);
+    sprintf(message_, "RtApiOss: error setting %d channels on device (%s).",
+            temp, name);
+    goto error;
+  }
+
+  // Set the sample rate.
+  srate = sampleRate;
+  temp = srate;
+  if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
+    close(fd);
+    sprintf(message_, "RtApiOss: error setting sample rate = %d on device (%s).",
+            temp, name);
+    goto error;
+  }
+
+  // Verify the sample rate setup worked.
+  if (abs(srate - temp) > 100) {
+    close(fd);
+    sprintf(message_, "RtApiOss: error ... audio device (%s) doesn't support sample rate of %d.",
+            name, temp);
+    goto error;
+  }
+  stream_.sampleRate = sampleRate;
+
+  if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
+    close(fd);
+    sprintf(message_, "RtApiOss: error getting buffer size for device (%s).",
+            name);
+    goto error;
+  }
+
+  // Save buffer size (in sample frames).
+  *bufferSize = buffer_bytes / (formatBytes(stream_.deviceFormat[mode]) * device_channels);
+  stream_.bufferSize = *bufferSize;
+
+  if (mode == INPUT && stream_.mode == OUTPUT &&
+      stream_.device[0] == device) {
+    // We're doing duplex setup here.
+    stream_.deviceFormat[0] = stream_.deviceFormat[1];
+    stream_.nDeviceChannels[0] = device_channels;
+  }
+
+  // Allocate the stream handles if necessary and then save.
+  if ( stream_.apiHandle == 0 ) {
+    handle = (int *) calloc(2, sizeof(int));
+    stream_.apiHandle = (void *) handle;
+    handle[0] = 0;
+    handle[1] = 0;
+  }
+  else {
+    handle = (int *) stream_.apiHandle;
+  }
+  handle[mode] = fd;
+
+  // Set flags for buffer conversion
+  stream_.doConvertBuffer[mode] = false;
+  if (stream_.userFormat != stream_.deviceFormat[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
+    stream_.doConvertBuffer[mode] = true;
+
+  // Allocate necessary internal buffers
+  if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
+
+    long buffer_bytes;
+    if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
+      buffer_bytes = stream_.nUserChannels[0];
+    else
+      buffer_bytes = stream_.nUserChannels[1];
+
+    buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
+    if (stream_.userBuffer) free(stream_.userBuffer);
+    stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
+    if (stream_.userBuffer == NULL) {
+      close(fd);
+      sprintf(message_, "RtApiOss: error allocating user buffer memory (%s).",
+              name);
+      goto error;
+    }
+  }
+
+  if ( stream_.doConvertBuffer[mode] ) {
+
+    long buffer_bytes;
+    bool makeBuffer = true;
+    if ( mode == OUTPUT )
+      buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
+    else { // mode == INPUT
+      buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+        long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
+        if ( buffer_bytes < bytes_out ) makeBuffer = false;
+      }
+    }
+
+    if ( makeBuffer ) {
+      buffer_bytes *= *bufferSize;
+      if (stream_.deviceBuffer) free(stream_.deviceBuffer);
+      stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
+      if (stream_.deviceBuffer == NULL) {
+        close(fd);
+        sprintf(message_, "RtApiOss: error allocating device buffer memory (%s).",
+                name);
+        goto error;
+      }
+    }
+  }
+
+  stream_.device[mode] = device;
+  stream_.state = STREAM_STOPPED;
+
+  if ( stream_.mode == OUTPUT && mode == INPUT ) {
+    stream_.mode = DUPLEX;
+    if (stream_.device[0] == device)
+      handle[0] = fd;
+  }
+  else
+    stream_.mode = mode;
+
+  return SUCCESS;
+
+ error:
+  if (handle) {
+    if (handle[0])
+      close(handle[0]);
+    free(handle);
+    stream_.apiHandle = 0;
+  }
+
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
+  }
+
+  error(RtError::WARNING);
+  return FAILURE;
+}
+
+void RtApiOss :: closeStream()
+{
+  // We don't want an exception to be thrown here because this
+  // function is called by our class destructor.  So, do our own
+  // stream check.
+  if ( stream_.mode == UNINITIALIZED ) {
+    sprintf(message_, "RtApiOss::closeStream(): no open stream to close!");
+    error(RtError::WARNING);
+    return;
+  }
+
+  int *handle = (int *) stream_.apiHandle;
+  if (stream_.state == STREAM_RUNNING) {
+    if (stream_.mode == OUTPUT || stream_.mode == DUPLEX)
+      ioctl(handle[0], SNDCTL_DSP_RESET, 0);
+    else
+      ioctl(handle[1], SNDCTL_DSP_RESET, 0);
+    stream_.state = STREAM_STOPPED;
+  }
+
+  if (stream_.callbackInfo.usingCallback) {
+    stream_.callbackInfo.usingCallback = false;
+    pthread_join(stream_.callbackInfo.thread, NULL);
+  }
+
+  if (handle) {
+    if (handle[0]) close(handle[0]);
+    if (handle[1]) close(handle[1]);
+    free(handle);
+    stream_.apiHandle = 0;
+  }
+
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
+  }
+
+  if (stream_.deviceBuffer) {
+    free(stream_.deviceBuffer);
+    stream_.deviceBuffer = 0;
+  }
+
+  stream_.mode = UNINITIALIZED;
+}
+
+void RtApiOss :: startStream()
+{
+  verifyStream();
+  if (stream_.state == STREAM_RUNNING) return;
+
+  MUTEX_LOCK(&stream_.mutex);
+
+  stream_.state = STREAM_RUNNING;
+
+  // No need to do anything else here ... OSS automatically starts
+  // when fed samples.
+
+  MUTEX_UNLOCK(&stream_.mutex);
+}
+
+void RtApiOss :: stopStream()
+{
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
+
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
+
+  int err;
+  int *handle = (int *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    err = ioctl(handle[0], SNDCTL_DSP_POST, 0);
+    //err = ioctl(handle[0], SNDCTL_DSP_SYNC, 0);
+    if (err < -1) {
+      sprintf(message_, "RtApiOss: error stopping device (%s).",
+              devices_[stream_.device[0]].name.c_str());
+      error(RtError::DRIVER_ERROR);
+    }
+  }
+  else {
+    err = ioctl(handle[1], SNDCTL_DSP_POST, 0);
+    //err = ioctl(handle[1], SNDCTL_DSP_SYNC, 0);
+    if (err < -1) {
+      sprintf(message_, "RtApiOss: error stopping device (%s).",
+              devices_[stream_.device[1]].name.c_str());
+      error(RtError::DRIVER_ERROR);
+    }
+  }
+
+  MUTEX_UNLOCK(&stream_.mutex);
+}
+
+void RtApiOss :: abortStream()
+{
+  stopStream();
+}
+
+int RtApiOss :: streamWillBlock()
+{
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return 0;
+
+  MUTEX_LOCK(&stream_.mutex);
+
+  int bytes = 0, channels = 0, frames = 0;
+  audio_buf_info info;
+  int *handle = (int *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    ioctl(handle[0], SNDCTL_DSP_GETOSPACE, &info);
+    bytes = info.bytes;
+    channels = stream_.nDeviceChannels[0];
+  }
+
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    ioctl(handle[1], SNDCTL_DSP_GETISPACE, &info);
+    if (stream_.mode == DUPLEX ) {
+      bytes = (bytes < info.bytes) ? bytes : info.bytes;
+      channels = stream_.nDeviceChannels[0];
+    }
+    else {
+      bytes = info.bytes;
+      channels = stream_.nDeviceChannels[1];
+    }
+  }
+
+  frames = (int) (bytes / (channels * formatBytes(stream_.deviceFormat[0])));
+  frames -= stream_.bufferSize;
+  if (frames < 0) frames = 0;
+
+  MUTEX_UNLOCK(&stream_.mutex);
+  return frames;
+}
+
+void RtApiOss :: tickStream()
+{
+  verifyStream();
+
+  int stopStream = 0;
+  if (stream_.state == STREAM_STOPPED) {
+    if (stream_.callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
+    return;
+  }
+  else if (stream_.callbackInfo.usingCallback) {
+    RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
+    stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData);
+  }
+
+  MUTEX_LOCK(&stream_.mutex);
+
+  // The state might change while waiting on a mutex.
+  if (stream_.state == STREAM_STOPPED)
+    goto unlock;
+
+  int result, *handle;
+  char *buffer;
+  int samples;
+  RtAudioFormat format;
+  handle = (int *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+
+    // Setup parameters and do buffer conversion if necessary.
+    if (stream_.doConvertBuffer[0]) {
+      convertStreamBuffer(OUTPUT);
+      buffer = stream_.deviceBuffer;
+      samples = stream_.bufferSize * stream_.nDeviceChannels[0];
+      format = stream_.deviceFormat[0];
+    }
+    else {
+      buffer = stream_.userBuffer;
+      samples = stream_.bufferSize * stream_.nUserChannels[0];
+      format = stream_.userFormat;
+    }
+
+    // Do byte swapping if necessary.
+    if (stream_.doByteSwap[0])
+      byteSwapBuffer(buffer, samples, format);
+
+    // Write samples to device.
+    result = write(handle[0], buffer, samples * formatBytes(format));
+
+    if (result == -1) {
+      // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
+      sprintf(message_, "RtApiOss: audio write error for device (%s).",
+              devices_[stream_.device[0]].name.c_str());
+      error(RtError::DRIVER_ERROR);
+    }
+  }
+
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+
+    // Setup parameters.
+    if (stream_.doConvertBuffer[1]) {
+      buffer = stream_.deviceBuffer;
+      samples = stream_.bufferSize * stream_.nDeviceChannels[1];
+      format = stream_.deviceFormat[1];
+    }
+    else {
+      buffer = stream_.userBuffer;
+      samples = stream_.bufferSize * stream_.nUserChannels[1];
+      format = stream_.userFormat;
+    }
+
+    // Read samples from device.
+    result = read(handle[1], buffer, samples * formatBytes(format));
+
+    if (result == -1) {
+      // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
+      sprintf(message_, "RtApiOss: audio read error for device (%s).",
+              devices_[stream_.device[1]].name.c_str());
+      error(RtError::DRIVER_ERROR);
+    }
+
+    // Do byte swapping if necessary.
+    if (stream_.doByteSwap[1])
+      byteSwapBuffer(buffer, samples, format);
+
+    // Do buffer conversion if necessary.
+    if (stream_.doConvertBuffer[1])
+      convertStreamBuffer(INPUT);
+  }
+
+ unlock:
+  MUTEX_UNLOCK(&stream_.mutex);
+
+  if (stream_.callbackInfo.usingCallback && stopStream)
+    this->stopStream();
+}
+
+void RtApiOss :: setStreamCallback(RtAudioCallback callback, void *userData)
+{
+  verifyStream();
+
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+  if ( info->usingCallback ) {
+    sprintf(message_, "RtApiOss: A callback is already set for this stream!");
+    error(RtError::WARNING);
+    return;
+  }
+
+  info->callback = (void *) callback;
+  info->userData = userData;
+  info->usingCallback = true;
+  info->object = (void *) this;
+
+  // Set the thread attributes for joinable and realtime scheduling
+  // priority.  The higher priority will only take affect if the
+  // program is run as root or suid.
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+  pthread_attr_setschedpolicy(&attr, SCHED_RR);
+
+  int err = pthread_create(&(info->thread), &attr, ossCallbackHandler, &stream_.callbackInfo);
+  pthread_attr_destroy(&attr);
+  if (err) {
+    info->usingCallback = false;
+    sprintf(message_, "RtApiOss: error starting callback thread!");
+    error(RtError::THREAD_ERROR);
+  }
+}
+
+void RtApiOss :: cancelStreamCallback()
+{
+  verifyStream();
+
+  if (stream_.callbackInfo.usingCallback) {
+
+    if (stream_.state == STREAM_RUNNING)
+      stopStream();
+
+    MUTEX_LOCK(&stream_.mutex);
+
+    stream_.callbackInfo.usingCallback = false;
+    pthread_join(stream_.callbackInfo.thread, NULL);
+    stream_.callbackInfo.thread = 0;
+    stream_.callbackInfo.callback = NULL;
+    stream_.callbackInfo.userData = NULL;
+
+    MUTEX_UNLOCK(&stream_.mutex);
+  }
+}
+
+extern "C" void *ossCallbackHandler(void *ptr)
+{
+  CallbackInfo *info = (CallbackInfo *) ptr;
+  RtApiOss *object = (RtApiOss *) info->object;
+  bool *usingCallback = &info->usingCallback;
+
+  while ( *usingCallback ) {
+    pthread_testcancel();
+    try {
+      object->tickStream();
+    }
+    catch (RtError &exception) {
+      fprintf(stderr, "\nRtApiOss: callback thread error (%s) ... closing thread.\n\n",
+              exception.getMessageString());
+      break;
+    }
+  }
+
+  return 0;
+}
+
+//******************** End of __LINUX_OSS__ *********************//
+#endif
+
+#if defined(__MACOSX_CORE__)
+
+
+// The OS X CoreAudio API is designed to use a separate callback
+// procedure for each of its audio devices.  A single RtAudio duplex
+// stream using two different devices is supported here, though it
+// cannot be guaranteed to always behave correctly because we cannot
+// synchronize these two callbacks.  This same functionality can be
+// achieved with better synchrony by opening two separate streams for
+// the devices and using RtAudio blocking calls (i.e. tickStream()).
+//
+// A property listener is installed for over/underrun information.
+// However, no functionality is currently provided to allow property
+// listeners to trigger user handlers because it is unclear what could
+// be done if a critical stream parameter (buffer size, sample rate,
+// device disconnect) notification arrived.  The listeners entail
+// quite a bit of extra code and most likely, a user program wouldn't
+// be prepared for the result anyway.
+
+// A structure to hold various information related to the CoreAuio API
+// implementation.
+struct CoreHandle {
+  UInt32 index[2];
+  bool stopStream;
+  bool xrun;
+  char *deviceBuffer;
+  pthread_cond_t condition;
+
+  CoreHandle()
+    :stopStream(false), xrun(false), deviceBuffer(0) {}
+};
+
+RtApiCore :: RtApiCore()
+{
+  this->initialize();
+
+  if (nDevices_ <= 0) {
+    sprintf(message_, "RtApiCore: no Macintosh OS-X Core Audio devices found!");
+    error(RtError::NO_DEVICES_FOUND);
+ }
+}
+
+RtApiCore :: ~RtApiCore()
+{
+  // The subclass destructor gets called before the base class
+  // destructor, so close an existing stream before deallocating
+  // apiDeviceId memory.
+  if ( stream_.mode != UNINITIALIZED ) closeStream();
+
+  // Free our allocated apiDeviceId memory.
+  AudioDeviceID *id;
+  for ( unsigned int i=0; i<devices_.size(); i++ ) {
+    id = (AudioDeviceID *) devices_[i].apiDeviceId;
+    if (id) free(id);
+  }
+}
+
+void RtApiCore :: initialize(void)
+{
+  OSStatus err = noErr;
+  UInt32 dataSize;
+  AudioDeviceID        *deviceList = NULL;
+  nDevices_ = 0;
+
+  // Find out how many audio devices there are, if any.
+  err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL);
+  if (err != noErr) {
+    sprintf(message_, "RtApiCore: OS-X error getting device info!");
+    error(RtError::SYSTEM_ERROR);
+  }
+
+  nDevices_ = dataSize / sizeof(AudioDeviceID);
+  if (nDevices_ == 0) return;
+
+  // Make space for the devices we are about to get.
+  deviceList = (AudioDeviceID  *) malloc( dataSize );
+  if (deviceList == NULL) {
+    sprintf(message_, "RtApiCore: memory allocation error during initialization!");
+    error(RtError::MEMORY_ERROR);
+  }
+
+  // Get the array of AudioDeviceIDs.
+  err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList);
+  if (err != noErr) {
+    free(deviceList);
+    sprintf(message_, "RtApiCore: OS-X error getting device properties!");
+    error(RtError::SYSTEM_ERROR);
+  }
+
+  // Create list of device structures and write device identifiers.
+  RtApiDevice device;
+  AudioDeviceID *id;
+  for (int i=0; i<nDevices_; i++) {
+    devices_.push_back(device);
+    id = (AudioDeviceID *) malloc( sizeof(AudioDeviceID) );
+    *id = deviceList[i];
+    devices_[i].apiDeviceId = (void *) id;
+  }
+
+  free(deviceList);
+}
+
+int RtApiCore :: getDefaultInputDevice(void)
+{
+  AudioDeviceID id, *deviceId;
+  UInt32 dataSize = sizeof( AudioDeviceID );
+
+  OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice,
+                                              &dataSize, &id );
+
+  if (result != noErr) {
+    sprintf( message_, "RtApiCore: OS-X error getting default input device." );
+    error(RtError::WARNING);
+    return 0;
+  }
+
+  for ( int i=0; i<nDevices_; i++ ) {
+    deviceId = (AudioDeviceID *) devices_[i].apiDeviceId;
+    if ( id == *deviceId ) return i;
+  }
+
+  return 0;
+}
+
+int RtApiCore :: getDefaultOutputDevice(void)
+{
+  AudioDeviceID id, *deviceId;
+  UInt32 dataSize = sizeof( AudioDeviceID );
+
+  OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
+                                              &dataSize, &id );
+
+  if (result != noErr) {
+    sprintf( message_, "RtApiCore: OS-X error getting default output device." );
+    error(RtError::WARNING);
+    return 0;
+  }
+
+  for ( int i=0; i<nDevices_; i++ ) {
+    deviceId = (AudioDeviceID *) devices_[i].apiDeviceId;
+    if ( id == *deviceId ) return i;
+  }
+
+  return 0;
+}
+
+static bool deviceSupportsFormat( AudioDeviceID id, bool isInput,
+                                  AudioStreamBasicDescription  *desc, bool isDuplex )
+{
+  OSStatus result = noErr;
   UInt32 dataSize = sizeof( AudioStreamBasicDescription );
 
   result = AudioDeviceGetProperty( id, 0, isInput,
@@ -499,7 +1629,7 @@ static bool deviceSupportsFormat( AudioDeviceID id, bool isInput,
   return false;
 }
 
-void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
+void RtApiCore :: probeDeviceInfo( RtApiDevice *info )
 {
   OSStatus err = noErr;
 
@@ -507,11 +1637,12 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   char name[256];
   char fullname[512];
   UInt32 dataSize = 256;
-  err = AudioDeviceGetProperty( info->id[0], 0, false,
+  AudioDeviceID *id = (AudioDeviceID *) info->apiDeviceId;
+  err = AudioDeviceGetProperty( *id, 0, false,
                                 kAudioDevicePropertyDeviceManufacturer,
                                 &dataSize, name );
   if (err != noErr) {
-    sprintf( message, "RtAudio: OSX error getting device manufacturer." );
+    sprintf( message_, "RtApiCore: OS-X error getting device manufacturer." );
     error(RtError::DEBUG_WARNING);
     return;
   }
@@ -519,32 +1650,33 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   strcat(fullname, ": " );
 
   dataSize = 256;
-  err = AudioDeviceGetProperty( info->id[0], 0, false,
+  err = AudioDeviceGetProperty( *id, 0, false,
                                 kAudioDevicePropertyDeviceName,
                                 &dataSize, name );
   if (err != noErr) {
-    sprintf( message, "RtAudio: OSX error getting device name." );
+    sprintf( message_, "RtApiCore: OS-X error getting device name." );
     error(RtError::DEBUG_WARNING);
     return;
   }
   strncat(fullname, name, 254);
-  strncat(info->name, fullname, 128);
+  info->name.erase();
+  info->name.append( (const char *)fullname, strlen(fullname)+1);
 
   // Get output channel information.
-  unsigned int i, minChannels, maxChannels, nStreams = 0;
+  unsigned int i, minChannels = 0, maxChannels = 0, nStreams = 0;
   AudioBufferList      *bufferList = nil;
-  err = AudioDeviceGetPropertyInfo( info->id[0], 0, false,
+  err = AudioDeviceGetPropertyInfo( *id, 0, false,
                                     kAudioDevicePropertyStreamConfiguration,
                                     &dataSize, NULL );
   if (err == noErr && dataSize > 0) {
     bufferList = (AudioBufferList *) malloc( dataSize );
     if (bufferList == NULL) {
-      sprintf(message, "RtAudio: memory allocation error!");
+      sprintf(message_, "RtApiCore: memory allocation error!");
       error(RtError::DEBUG_WARNING);
       return;
     }
 
-    err = AudioDeviceGetProperty( info->id[0], 0, false,
+    err = AudioDeviceGetProperty( *id, 0, false,
                                   kAudioDevicePropertyStreamConfiguration,
                                   &dataSize, bufferList );
     if (err == noErr) {
@@ -558,13 +1690,15 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
       }
     }
   }
+  free (bufferList);
+
   if (err != noErr || dataSize <= 0) {
-    sprintf( message, "RtAudio: OSX error getting output channels for device (%s).", info->name );
+    sprintf( message_, "RtApiCore: OS-X error getting output channels for device (%s).",
+             info->name.c_str() );
     error(RtError::DEBUG_WARNING);
     return;
   }
 
-  free (bufferList);
   if ( nStreams ) {
     if ( maxChannels > 0 )
       info->maxOutputChannels = maxChannels;
@@ -574,17 +1708,17 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
 
   // Get input channel information.
   bufferList = nil;
-  err = AudioDeviceGetPropertyInfo( info->id[0], 0, true,
+  err = AudioDeviceGetPropertyInfo( *id, 0, true,
                                     kAudioDevicePropertyStreamConfiguration,
                                     &dataSize, NULL );
   if (err == noErr && dataSize > 0) {
     bufferList = (AudioBufferList *) malloc( dataSize );
     if (bufferList == NULL) {
-      sprintf(message, "RtAudio: memory allocation error!");
+      sprintf(message_, "RtApiCore: memory allocation error!");
       error(RtError::DEBUG_WARNING);
       return;
     }
-    err = AudioDeviceGetProperty( info->id[0], 0, true,
+    err = AudioDeviceGetProperty( *id, 0, true,
                                   kAudioDevicePropertyStreamConfiguration,
                                   &dataSize, bufferList );
     if (err == noErr) {
@@ -598,13 +1732,15 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
       }
     }
   }
+  free (bufferList);
+
   if (err != noErr || dataSize <= 0) {
-    sprintf( message, "RtAudio: OSX error getting input channels for device (%s).", info->name );
+    sprintf( message_, "RtApiCore: OS-X error getting input channels for device (%s).",
+             info->name.c_str() );
     error(RtError::DEBUG_WARNING);
     return;
   }
 
-  free (bufferList);
   if ( nStreams ) {
     if ( maxChannels > 0 )
       info->maxInputChannels = maxChannels;
@@ -636,93 +1772,87 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   if ( info->maxDuplexChannels > 0 ) isDuplex = true;
 
   // Determine the supported sample rates.
-  info->nSampleRates = 0;
-  for (i=0; i<MAX_SAMPLE_RATES; i++) {
-    description.mSampleRate = (double) SAMPLE_RATES[i];
-    if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
-      info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
+  info->sampleRates.clear();
+  for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) {
+    description.mSampleRate = (double) SAMPLE_RATES[k];
+    if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
+      info->sampleRates.push_back( SAMPLE_RATES[k] );
   }
 
-  if (info->nSampleRates == 0) {
-    sprintf( message, "RtAudio: No supported sample rates found for OSX device (%s).", info->name );
+  if (info->sampleRates.size() == 0) {
+    sprintf( message_, "RtApiCore: No supported sample rates found for OS-X device (%s).",
+             info->name.c_str() );
     error(RtError::DEBUG_WARNING);
     return;
   }
 
-  // Check for continuous sample rate support.
-  description.mSampleRate = kAudioStreamAnyRate;
-  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) {
-    info->sampleRates[1] = info->sampleRates[info->nSampleRates-1];
-    info->nSampleRates = -1;
-  }
-
   // Determine the supported data formats.
   info->nativeFormats = 0;
   description.mFormatID = kAudioFormatLinearPCM;
   description.mBitsPerChannel = 8;
   description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
-  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+  if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
     info->nativeFormats |= RTAUDIO_SINT8;
   else {
     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
-    if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+    if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
       info->nativeFormats |= RTAUDIO_SINT8;
   }
 
   description.mBitsPerChannel = 16;
   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
-  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+  if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
     info->nativeFormats |= RTAUDIO_SINT16;
   else {
     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
-    if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+    if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
       info->nativeFormats |= RTAUDIO_SINT16;
   }
 
   description.mBitsPerChannel = 32;
   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
-  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+  if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
     info->nativeFormats |= RTAUDIO_SINT32;
   else {
     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
-    if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+    if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
       info->nativeFormats |= RTAUDIO_SINT32;
   }
 
   description.mBitsPerChannel = 24;
   description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagIsBigEndian;
-  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+  if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
     info->nativeFormats |= RTAUDIO_SINT24;
   else {
     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
-    if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+    if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
       info->nativeFormats |= RTAUDIO_SINT24;
   }
 
   description.mBitsPerChannel = 32;
   description.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
-  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+  if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
     info->nativeFormats |= RTAUDIO_FLOAT32;
   else {
     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
-    if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+    if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
       info->nativeFormats |= RTAUDIO_FLOAT32;
   }
 
   description.mBitsPerChannel = 64;
   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
-  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+  if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
     info->nativeFormats |= RTAUDIO_FLOAT64;
   else {
     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
-    if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
+    if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
       info->nativeFormats |= RTAUDIO_FLOAT64;
   }
 
   // Check that we have at least one supported format.
   if (info->nativeFormats == 0) {
-    sprintf(message, "RtAudio: OSX PCM device (%s) data format not supported by RtAudio.",
-            info->name);
+    sprintf(message_, "RtApiCore: OS-X device (%s) data format not supported by RtAudio.",
+            info->name.c_str());
     error(RtError::DEBUG_WARNING);
     return;
   }
@@ -738,68 +1868,51 @@ OSStatus callbackHandler(AudioDeviceID inDevice,
                          const AudioTimeStamp* inOutputTime, 
                          void* infoPointer)
 {
-  CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
+  CallbackInfo *info = (CallbackInfo *) infoPointer;
 
-  RtAudio *object = (RtAudio *) info->object;
+  RtApiCore *object = (RtApiCore *) info->object;
   try {
-    object->callbackEvent( info->streamId, inDevice, (void *)inInputData, (void *)outOutputData );
+    object->callbackEvent( inDevice, (void *)inInputData, (void *)outOutputData );
   }
   catch (RtError &exception) {
-    fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
+    fprintf(stderr, "\nRtApiCore: callback handler error (%s)!\n\n", exception.getMessageString());
     return kAudioHardwareUnspecifiedError;
   }
 
   return kAudioHardwareNoError;
 }
 
-/*
 OSStatus deviceListener(AudioDeviceID inDevice,
                         UInt32 channel,
                         Boolean isInput,
                         AudioDevicePropertyID propertyID,
-                        void* infoPointer)
+                        void* handlePointer)
 {
-  CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
-
-  RtAudio *object = (RtAudio *) info->object;
-  try {
-    object->settingChange( info->streamId );
-  }
-  catch (RtError &exception) {
-    fprintf(stderr, "\nDevice listener error (%s)!\n\n", exception.getMessage());
-    return kAudioHardwareUnspecifiedError;
+  CoreHandle *handle = (CoreHandle *) handlePointer;
+  if ( propertyID == kAudioDeviceProcessorOverload ) {
+    if ( isInput )
+      fprintf(stderr, "\nRtApiCore: OS-X audio input overrun detected!\n");
+    else
+      fprintf(stderr, "\nRtApiCore: OS-X audio output underrun detected!\n");
+    handle->xrun = true;
   }
 
   return kAudioHardwareNoError;
 }
-*/
 
-bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
-                                STREAM_MODE mode, int channels, 
-                                int sampleRate, RTAUDIO_FORMAT format,
-                                int *bufferSize, int numberOfBuffers)
+bool RtApiCore :: probeDeviceOpen( int device, StreamMode mode, int channels, 
+                                   int sampleRate, RtAudioFormat format,
+                                   int *bufferSize, int numberOfBuffers )
 {
-  // Check to make sure we don't already have a stream accessing this device.
-  RTAUDIO_STREAM *streamPtr;
-  std::map<int, void *>::const_iterator i;
-  for ( i=streams.begin(); i!=streams.end(); ++i ) {
-    streamPtr = (RTAUDIO_STREAM *) i->second;
-    if ( streamPtr->device[0] == device || streamPtr->device[1] == device ) {
-      sprintf(message, "RtAudio: no current OS X support for multiple streams accessing the same device!");
-      error(RtError::WARNING);
-      return FAILURE;
-    }
-  }
-
   // Setup for stream mode.
   bool isInput = false;
-  AudioDeviceID id = devices[device].id[0];
+  AudioDeviceID id = *((AudioDeviceID *) devices_[device].apiDeviceId);
   if ( mode == INPUT ) isInput = true;
 
   // Search for a stream which contains the desired number of channels.
   OSStatus err = noErr;
   UInt32 dataSize;
-  unsigned int deviceChannels, nStreams;
+  unsigned int deviceChannels, nStreams = 0;
   UInt32 iChannel = 0, iStream = 0;
   AudioBufferList      *bufferList = nil;
   err = AudioDeviceGetPropertyInfo( id, 0, isInput,
@@ -809,7 +1922,7 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   if (err == noErr && dataSize > 0) {
     bufferList = (AudioBufferList *) malloc( dataSize );
     if (bufferList == NULL) {
-      sprintf(message, "RtAudio: memory allocation error!");
+      sprintf(message_, "RtApiCore: memory allocation error in probeDeviceOpen()!");
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
@@ -818,7 +1931,7 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
                                   &dataSize, bufferList );
 
     if (err == noErr) {
-      stream->deInterleave[mode] = false;
+      stream_.deInterleave[mode] = false;
       nStreams = bufferList->mNumberBuffers;
       for ( iStream=0; iStream<nStreams; iStream++ ) {
         if ( bufferList->mBuffers[iStream].mNumberChannels >= (unsigned int) channels ) break;
@@ -840,7 +1953,7 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
           if ( counter == channels ) {
             iStream -= channels - 1;
             iChannel -= channels - 1;
-            stream->deInterleave[mode] = true;
+            stream_.deInterleave[mode] = true;
             break;
           }
           iChannel += bufferList->mBuffers[iStream].mNumberChannels;
@@ -850,15 +1963,16 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   }
   if (err != noErr || dataSize <= 0) {
     if ( bufferList ) free( bufferList );
-    sprintf( message, "RtAudio: OSX error getting channels for device (%s).", devices[device].name );
+    sprintf( message_, "RtApiCore: OS-X error getting channels for device (%s).",
+             devices_[device].name.c_str() );
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
 
   if (iStream >= nStreams) {
     free (bufferList);
-    sprintf( message, "RtAudio: unable to find OSX audio stream on device (%s) for requested channels (%d).",
-             devices[device].name, channels );
+    sprintf( message_, "RtApiCore: unable to find OS-X audio stream on device (%s) for requested channels (%d).",
+             devices_[device].name.c_str(), channels );
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -874,8 +1988,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
                                 kAudioDevicePropertyBufferSizeRange,
                                 &dataSize, &bufferRange);
   if (err != noErr) {
-    sprintf( message, "RtAudio: OSX error getting buffer size range for device (%s).",
-             devices[device].name );
+    sprintf( message_, "RtApiCore: OS-X error getting buffer size range for device (%s).",
+             devices_[device].name.c_str() );
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -892,8 +2006,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
                                kAudioDevicePropertyBufferSize,
                                dataSize, &theSize);
   if (err != noErr) {
-    sprintf( message, "RtAudio: OSX error setting the buffer size for device (%s).",
-             devices[device].name );
+    sprintf( message_, "RtApiCore: OS-X error setting the buffer size for device (%s).",
+             devices_[device].name.c_str() );
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -901,20 +2015,20 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   // If attempting to setup a duplex stream, the bufferSize parameter
   // MUST be the same in both directions!
   *bufferSize = bufferBytes / ( deviceChannels * formatBytes(RTAUDIO_FLOAT32) );
-  if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
-    sprintf( message, "RtAudio: OSX error setting buffer size for duplex stream on device (%s).",
-             devices[device].name );
+  if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
+    sprintf( message_, "RtApiCore: OS-X error setting buffer size for duplex stream on device (%s).",
+             devices_[device].name.c_str() );
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
 
-  stream->bufferSize = *bufferSize;
-  stream->nBuffers = 1;
+  stream_.bufferSize = *bufferSize;
+  stream_.nBuffers = 1;
 
   // Set the stream format description.  Do for each channel in mono mode.
   AudioStreamBasicDescription  description;
   dataSize = sizeof( AudioStreamBasicDescription );
-  if ( stream->deInterleave[mode] ) nStreams = channels;
+  if ( stream_.deInterleave[mode] ) nStreams = channels;
   else nStreams = 1;
   for ( unsigned int i=0; i<nStreams; i++, iChannel++ ) {
 
@@ -922,7 +2036,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
                                   kAudioDevicePropertyStreamFormat,
                                   &dataSize, &description );
     if (err != noErr) {
-      sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
+      sprintf( message_, "RtApiCore: OS-X error getting stream format for device (%s).",
+               devices_[device].name.c_str() );
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
@@ -934,1663 +2049,1335 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
                                   kAudioDevicePropertyStreamFormat,
                                   dataSize, &description );
     if (err != noErr) {
-      sprintf( message, "RtAudio: OSX error setting sample rate or data format for device (%s).", devices[device].name );
+      sprintf( message_, "RtApiCore: OS-X error setting sample rate or data format for device (%s).",
+               devices_[device].name.c_str() );
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
   }
 
-  // Check whether we need byte-swapping (assuming OS X host is big-endian).
+  // Check whether we need byte-swapping (assuming OS-X host is big-endian).
   iChannel -= nStreams;
   err = AudioDeviceGetProperty( id, iChannel, isInput,
                                 kAudioDevicePropertyStreamFormat,
                                 &dataSize, &description );
   if (err != noErr) {
-    sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
+    sprintf( message_, "RtApiCore: OS-X error getting stream format for device (%s).", devices_[device].name.c_str() );
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
 
-  stream->doByteSwap[mode] = false;
+  stream_.doByteSwap[mode] = false;
   if ( !description.mFormatFlags & kLinearPCMFormatFlagIsBigEndian )
-    stream->doByteSwap[mode] = true;
+    stream_.doByteSwap[mode] = true;
 
   // From the CoreAudio documentation, PCM data must be supplied as
   // 32-bit floats.
-  stream->userFormat = format;
-  stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
+  stream_.userFormat = format;
+  stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
 
-  if ( stream->deInterleave[mode] )
-    stream->nDeviceChannels[mode] = channels;
+  if ( stream_.deInterleave[mode] ) // mono mode
+    stream_.nDeviceChannels[mode] = channels;
+  else
+    stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;
+  stream_.nUserChannels[mode] = channels;
+
+  // Set flags for buffer conversion.
+  stream_.doConvertBuffer[mode] = false;
+  if (stream_.userFormat != stream_.deviceFormat[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.nUserChannels[mode] > 1 && stream_.deInterleave[mode])
+    stream_.doConvertBuffer[mode] = true;
+
+  // Allocate our CoreHandle structure for the stream.
+  CoreHandle *handle;
+  if ( stream_.apiHandle == 0 ) {
+    handle = (CoreHandle *) calloc(1, sizeof(CoreHandle));
+    if ( handle == NULL ) {
+      sprintf(message_, "RtApiCore: OS-X error allocating coreHandle memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
+    handle->index[0] = 0;
+    handle->index[1] = 0;
+    if ( pthread_cond_init(&handle->condition, NULL) ) {
+      sprintf(message_, "RtApiCore: error initializing pthread condition variable (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
+    stream_.apiHandle = (void *) handle;
+  }
   else
-    stream->nDeviceChannels[mode] = description.mChannelsPerFrame;
-  stream->nUserChannels[mode] = channels;
-
-  // Set handle and flags for buffer conversion.
-  stream->handle[mode] = iStream;
-  stream->doConvertBuffer[mode] = false;
-  if (stream->userFormat != stream->deviceFormat[mode])
-    stream->doConvertBuffer[mode] = true;
-  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
-    stream->doConvertBuffer[mode] = true;
-  if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
-    stream->doConvertBuffer[mode] = true;
+     handle = (CoreHandle *) stream_.apiHandle;
+  handle->index[mode] = iStream;
 
   // Allocate necessary internal buffers.
-  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
+  if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
 
     long buffer_bytes;
-    if (stream->nUserChannels[0] >= stream->nUserChannels[1])
-      buffer_bytes = stream->nUserChannels[0];
+    if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
+      buffer_bytes = stream_.nUserChannels[0];
     else
-      buffer_bytes = stream->nUserChannels[1];
-
-    buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
-    if (stream->userBuffer) free(stream->userBuffer);
-    stream->userBuffer = (char *) calloc(buffer_bytes, 1);
-    if (stream->userBuffer == NULL)
-      goto memory_error;
+      buffer_bytes = stream_.nUserChannels[1];
+
+    buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
+    if (stream_.userBuffer) free(stream_.userBuffer);
+    stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
+    if (stream_.userBuffer == NULL) {
+      sprintf(message_, "RtApiCore: OS-X error allocating user buffer memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
   }
 
-  if ( stream->deInterleave[mode] ) {
+  if ( stream_.deInterleave[mode] ) {
 
     long buffer_bytes;
     bool makeBuffer = true;
     if ( mode == OUTPUT )
-      buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
     else { // mode == INPUT
-      buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
-      if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
-        long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+        long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
         if ( buffer_bytes < bytes_out ) makeBuffer = false;
       }
     }
 
     if ( makeBuffer ) {
       buffer_bytes *= *bufferSize;
-      if (stream->deviceBuffer) free(stream->deviceBuffer);
-      stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
-      if (stream->deviceBuffer == NULL)
-        goto memory_error;
+      if (stream_.deviceBuffer) free(stream_.deviceBuffer);
+      stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
+      if (stream_.deviceBuffer == NULL) {
+        sprintf(message_, "RtApiCore: error allocating device buffer memory (%s).",
+                devices_[device].name.c_str());
+        goto error;
+      }
 
-      // If not de-interleaving, we point stream->deviceBuffer to the
+      // If not de-interleaving, we point stream_.deviceBuffer to the
       // OS X supplied device buffer before doing any necessary data
       // conversions.  This presents a problem if we have a duplex
       // stream using one device which needs de-interleaving and
       // another device which doesn't.  So, save a pointer to our own
-      // device buffer in the CALLBACK_INFO structure.
-      stream->callbackInfo.buffers = stream->deviceBuffer;
+      // device buffer in the CallbackInfo structure.
+      handle->deviceBuffer = stream_.deviceBuffer;
     }
   }
 
-  stream->sampleRate = sampleRate;
-  stream->device[mode] = device;
-  stream->state = STREAM_STOPPED;
-  stream->callbackInfo.object = (void *) this;
-  stream->callbackInfo.waitTime = (unsigned long) (200000.0 * stream->bufferSize / stream->sampleRate);
-  stream->callbackInfo.device[mode] = id;
-  if ( stream->mode == OUTPUT && mode == INPUT && stream->device[0] == device )
+  stream_.sampleRate = sampleRate;
+  stream_.device[mode] = device;
+  stream_.state = STREAM_STOPPED;
+  stream_.callbackInfo.object = (void *) this;
+
+  if ( stream_.mode == OUTPUT && mode == INPUT && stream_.device[0] == device )
     // Only one callback procedure per device.
-    stream->mode = DUPLEX;
+    stream_.mode = DUPLEX;
   else {
-    err = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream->callbackInfo );
+    err = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );
     if (err != noErr) {
-      sprintf( message, "RtAudio: OSX error setting callback for device (%s).", devices[device].name );
+      sprintf( message_, "RtApiCore: OS-X error setting callback for device (%s).", devices_[device].name.c_str() );
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
-    if ( stream->mode == OUTPUT && mode == INPUT )
-      stream->mode = DUPLEX;
+    if ( stream_.mode == OUTPUT && mode == INPUT )
+      stream_.mode = DUPLEX;
     else
-      stream->mode = mode;
+      stream_.mode = mode;
   }
 
-  // If we wanted to use property listeners, they would be setup here.
+  // Setup the device property listener for over/underload.
+  err = AudioDeviceAddPropertyListener( id, iChannel, isInput,
+                                        kAudioDeviceProcessorOverload,
+                                        deviceListener, (void *) handle );
 
   return SUCCESS;
 
- memory_error:
-  if (stream->userBuffer) {
-    free(stream->userBuffer);
-    stream->userBuffer = 0;
+ error:
+  if ( handle ) {
+    pthread_cond_destroy(&handle->condition);
+    free(handle);
+    stream_.apiHandle = 0;
   }
-  sprintf(message, "RtAudio: OSX error allocating buffer memory (%s).", devices[device].name);
-  error(RtError::WARNING);
-  return FAILURE;
-}
-
-void RtAudio :: cancelStreamCallback(int streamId)
-{
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  if (stream->callbackInfo.usingCallback) {
-
-    if (stream->state == STREAM_RUNNING)
-      stopStream( streamId );
-
-    MUTEX_LOCK(&stream->mutex);
-
-    stream->callbackInfo.usingCallback = false;
-    stream->callbackInfo.userData = NULL;
-    stream->state = STREAM_STOPPED;
-    stream->callbackInfo.callback = NULL;
 
-    MUTEX_UNLOCK(&stream->mutex);
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
   }
+
+  error(RtError::WARNING);
+  return FAILURE;
 }
 
-void RtAudio :: closeStream(int streamId)
+void RtApiCore :: closeStream()
 {
   // We don't want an exception to be thrown here because this
   // function is called by our class destructor.  So, do our own
-  // streamId check.
-  if ( streams.find( streamId ) == streams.end() ) {
-    sprintf(message, "RtAudio: invalid stream identifier!");
+  // stream check.
+  if ( stream_.mode == UNINITIALIZED ) {
+    sprintf(message_, "RtApiCore::closeStream(): no open stream to close!");
     error(RtError::WARNING);
     return;
   }
 
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
-
-  AudioDeviceID id;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    id = devices[stream->device[0]].id[0];
-    if (stream->state == STREAM_RUNNING)
+  AudioDeviceID id = *( (AudioDeviceID *) devices_[stream_.device[0]].apiDeviceId );
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    if (stream_.state == STREAM_RUNNING)
       AudioDeviceStop( id, callbackHandler );
     AudioDeviceRemoveIOProc( id, callbackHandler );
   }
 
-  if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
-    id = devices[stream->device[1]].id[0];
-    if (stream->state == STREAM_RUNNING)
+  id = *( (AudioDeviceID *) devices_[stream_.device[1]].apiDeviceId );
+  if (stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1]) ) {
+    if (stream_.state == STREAM_RUNNING)
       AudioDeviceStop( id, callbackHandler );
     AudioDeviceRemoveIOProc( id, callbackHandler );
   }
 
-  pthread_mutex_destroy(&stream->mutex);
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
+  }
+
+  if ( stream_.deInterleave[0] || stream_.deInterleave[1] ) {
+    free(stream_.deviceBuffer);
+    stream_.deviceBuffer = 0;
+  }
 
-  if (stream->userBuffer)
-    free(stream->userBuffer);
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
 
-  if ( stream->deInterleave[0] || stream->deInterleave[1] )
-    free(stream->callbackInfo.buffers);
+  // Destroy pthread condition variable and free the CoreHandle structure.
+  if ( handle ) {
+    pthread_cond_destroy(&handle->condition);
+    free( handle );
+    stream_.apiHandle = 0;
+  }
 
-  free(stream);
-  streams.erase(streamId);
+  stream_.mode = UNINITIALIZED;
 }
 
-void RtAudio :: startStream(int streamId)
+void RtApiCore :: startStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_RUNNING) return;
 
-  MUTEX_LOCK(&stream->mutex);
-
-  if (stream->state == STREAM_RUNNING)
-    goto unlock;
+  MUTEX_LOCK(&stream_.mutex);
 
   OSStatus err;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
+  AudioDeviceID id;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
 
-    err = AudioDeviceStart(devices[stream->device[0]].id[0], callbackHandler);
+    id = *( (AudioDeviceID *) devices_[stream_.device[0]].apiDeviceId );
+    err = AudioDeviceStart(id, callbackHandler);
     if (err != noErr) {
-      sprintf(message, "RtAudio: OSX error starting callback procedure on device (%s).",
-              devices[stream->device[0]].name);
-      MUTEX_UNLOCK(&stream->mutex);
+      sprintf(message_, "RtApiCore: OS-X error starting callback procedure on device (%s).",
+              devices_[stream_.device[0]].name.c_str());
+      MUTEX_UNLOCK(&stream_.mutex);
       error(RtError::DRIVER_ERROR);
     }
   }
 
-  if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
+  if (stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1]) ) {
 
-    err = AudioDeviceStart(devices[stream->device[1]].id[0], callbackHandler);
+    id = *( (AudioDeviceID *) devices_[stream_.device[1]].apiDeviceId );
+    err = AudioDeviceStart(id, callbackHandler);
     if (err != noErr) {
-      sprintf(message, "RtAudio: OSX error starting input callback procedure on device (%s).",
-              devices[stream->device[0]].name);
-      MUTEX_UNLOCK(&stream->mutex);
+      sprintf(message_, "RtApiCore: OS-X error starting input callback procedure on device (%s).",
+              devices_[stream_.device[0]].name.c_str());
+      MUTEX_UNLOCK(&stream_.mutex);
       error(RtError::DRIVER_ERROR);
     }
   }
 
-  stream->callbackInfo.streamId = streamId;
-  stream->state = STREAM_RUNNING;
-  stream->callbackInfo.blockTick = true;
-  stream->callbackInfo.stopStream = false;
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
+  handle->stopStream = false;
+  stream_.state = STREAM_RUNNING;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: stopStream(int streamId)
+void RtApiCore :: stopStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-  MUTEX_LOCK(&stream->mutex);
-
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
   OSStatus err;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
+  AudioDeviceID id;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
 
-    err = AudioDeviceStop(devices[stream->device[0]].id[0], callbackHandler);
+    id = *( (AudioDeviceID *) devices_[stream_.device[0]].apiDeviceId );
+    err = AudioDeviceStop(id, callbackHandler);
     if (err != noErr) {
-      sprintf(message, "RtAudio: OSX error stopping callback procedure on device (%s).",
-              devices[stream->device[0]].name);
-      MUTEX_UNLOCK(&stream->mutex);
+      sprintf(message_, "RtApiCore: OS-X error stopping callback procedure on device (%s).",
+              devices_[stream_.device[0]].name.c_str());
+      MUTEX_UNLOCK(&stream_.mutex);
       error(RtError::DRIVER_ERROR);
     }
   }
 
-  if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
+  if (stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1]) ) {
 
-    err = AudioDeviceStop(devices[stream->device[1]].id[0], callbackHandler);
+    id = *( (AudioDeviceID *) devices_[stream_.device[1]].apiDeviceId );
+    err = AudioDeviceStop(id, callbackHandler);
     if (err != noErr) {
-      sprintf(message, "RtAudio: OSX error stopping input callback procedure on device (%s).",
-              devices[stream->device[0]].name);
-      MUTEX_UNLOCK(&stream->mutex);
+      sprintf(message_, "RtApiCore: OS-X error stopping input callback procedure on device (%s).",
+              devices_[stream_.device[0]].name.c_str());
+      MUTEX_UNLOCK(&stream_.mutex);
       error(RtError::DRIVER_ERROR);
     }
   }
 
-  stream->state = STREAM_STOPPED;
-
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
-}
-
-void RtAudio :: abortStream(int streamId)
-{
-  stopStream( streamId );
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-// I don't know how this function can be implemented.
-int RtAudio :: streamWillBlock(int streamId)
+void RtApiCore :: abortStream()
 {
-  sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for OS X.");
-  error(RtError::WARNING);
-  return 0;
+  stopStream();
 }
 
-void RtAudio :: tickStream(int streamId)
+void RtApiCore :: tickStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
 
-  if (stream->state == STREAM_STOPPED)
-    return;
+  if (stream_.state == STREAM_STOPPED) return;
 
-  if (stream->callbackInfo.usingCallback) {
-    sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
+  if (stream_.callbackInfo.usingCallback) {
+    sprintf(message_, "RtApiCore: tickStream() should not be used when a callback function is set!");
     error(RtError::WARNING);
     return;
   }
 
-  // Block waiting here until the user data is processed in callbackEvent().
-  while ( stream->callbackInfo.blockTick )
-    usleep(stream->callbackInfo.waitTime);
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
-  stream->callbackInfo.blockTick = true;
+  pthread_cond_wait(&handle->condition, &stream_.mutex);
 
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: callbackEvent( int streamId, DEVICE_ID deviceId, void *inData, void *outData )
+void RtApiCore :: callbackEvent( AudioDeviceID deviceId, void *inData, void *outData )
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+
+  if (stream_.state == STREAM_STOPPED) return;
 
-  CALLBACK_INFO *info;
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+  CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
   AudioBufferList *inBufferList = (AudioBufferList *) inData;
   AudioBufferList *outBufferList = (AudioBufferList *) outData;
 
-  if (stream->state == STREAM_STOPPED) return;
-
-  info = (CALLBACK_INFO *) &stream->callbackInfo;
-  if ( !info->usingCallback ) {
-    // Block waiting here until we get new user data in tickStream().
-    while ( !info->blockTick )
-      usleep(info->waitTime);
-  }
-  else if ( info->stopStream ) {
+  if ( info->usingCallback && handle->stopStream ) {
     // Check if the stream should be stopped (via the previous user
     // callback return value).  We stop the stream here, rather than
     // after the function call, so that output data can first be
     // processed.
-    this->stopStream(info->streamId);
+    this->stopStream();
     return;
   }
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
   // Invoke user callback first, to get fresh output data.  Don't
-  // invoke the user callback if duplex mode, the input/output devices
-  // are different, and this function is called for the input device.
-  if ( info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[0] ) ) {
-    RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
-    info->stopStream = callback(stream->userBuffer, stream->bufferSize, info->userData);
+  // invoke the user callback if duplex mode AND the input/output devices
+  // are different AND this function is called for the input device.
+  AudioDeviceID id = *( (AudioDeviceID *) devices_[stream_.device[0]].apiDeviceId );
+  if ( info->usingCallback && (stream_.mode != DUPLEX || deviceId == id ) ) {
+    RtAudioCallback callback = (RtAudioCallback) info->callback;
+    handle->stopStream = callback(stream_.userBuffer, stream_.bufferSize, info->userData);
+    if ( handle->xrun == true ) {
+      handle->xrun = false;
+      MUTEX_UNLOCK(&stream_.mutex);
+      return;
+    }
   }
 
-  if ( stream->mode == OUTPUT || ( stream->mode == DUPLEX && deviceId == info->device[0] ) ) {
+  if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == id ) ) {
 
-    if (stream->doConvertBuffer[0]) {
+    if (stream_.doConvertBuffer[0]) {
 
-      if ( !stream->deInterleave[0] )
-        stream->deviceBuffer = (char *) outBufferList->mBuffers[stream->handle[0]].mData;
+      if ( !stream_.deInterleave[0] )
+        stream_.deviceBuffer = (char *) outBufferList->mBuffers[handle->index[0]].mData;
       else
-        stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
-
-      convertStreamBuffer(stream, OUTPUT);
-      if ( stream->doByteSwap[0] )
-        byteSwapBuffer(stream->deviceBuffer,
-                       stream->bufferSize * stream->nDeviceChannels[0],
-                       stream->deviceFormat[0]);
-
-      if ( stream->deInterleave[0] ) {
-        int bufferBytes = outBufferList->mBuffers[stream->handle[0]].mDataByteSize;
-        for ( int i=0; i<stream->nDeviceChannels[0]; i++ ) {
-          memcpy(outBufferList->mBuffers[stream->handle[0]+i].mData,
-                 &stream->deviceBuffer[i*bufferBytes], bufferBytes );
+        stream_.deviceBuffer = handle->deviceBuffer;
+
+      convertStreamBuffer(OUTPUT);
+      if ( stream_.doByteSwap[0] )
+        byteSwapBuffer(stream_.deviceBuffer,
+                       stream_.bufferSize * stream_.nDeviceChannels[0],
+                       stream_.deviceFormat[0]);
+
+      if ( stream_.deInterleave[0] ) {
+        int bufferBytes = outBufferList->mBuffers[handle->index[0]].mDataByteSize;
+        for ( int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
+          memcpy(outBufferList->mBuffers[handle->index[0]+i].mData,
+                 &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
         }
       }
 
     }
     else {
-      if (stream->doByteSwap[0])
-        byteSwapBuffer(stream->userBuffer,
-                       stream->bufferSize * stream->nUserChannels[0],
-                       stream->userFormat);
+      if (stream_.doByteSwap[0])
+        byteSwapBuffer(stream_.userBuffer,
+                       stream_.bufferSize * stream_.nUserChannels[0],
+                       stream_.userFormat);
 
-      memcpy(outBufferList->mBuffers[stream->handle[0]].mData,
-             stream->userBuffer,
-             outBufferList->mBuffers[stream->handle[0]].mDataByteSize );
+      memcpy(outBufferList->mBuffers[handle->index[0]].mData,
+             stream_.userBuffer,
+             outBufferList->mBuffers[handle->index[0]].mDataByteSize );
     }
   }
 
-  if ( stream->mode == INPUT || ( stream->mode == DUPLEX && deviceId == info->device[1] ) ) {
+  if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == id ) ) {
 
-    if (stream->doConvertBuffer[1]) {
+    if (stream_.doConvertBuffer[1]) {
 
-      if ( stream->deInterleave[1] ) {
-        stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
-        int bufferBytes = inBufferList->mBuffers[stream->handle[1]].mDataByteSize;
-        for ( int i=0; i<stream->nDeviceChannels[1]; i++ ) {
-          memcpy(&stream->deviceBuffer[i*bufferBytes],
-                 inBufferList->mBuffers[stream->handle[1]+i].mData, bufferBytes );
+      if ( stream_.deInterleave[1] ) {
+        stream_.deviceBuffer = (char *) handle->deviceBuffer;
+        int bufferBytes = inBufferList->mBuffers[handle->index[1]].mDataByteSize;
+        for ( int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
+          memcpy(&stream_.deviceBuffer[i*bufferBytes],
+                 inBufferList->mBuffers[handle->index[1]+i].mData, bufferBytes );
         }
       }
       else
-        stream->deviceBuffer = (char *) inBufferList->mBuffers[stream->handle[1]].mData;
-
-      if ( stream->doByteSwap[1] )
-        byteSwapBuffer(stream->deviceBuffer,
-                       stream->bufferSize * stream->nDeviceChannels[1],
-                       stream->deviceFormat[1]);
-      convertStreamBuffer(stream, INPUT);
-
-    }
-    else {
-      memcpy(stream->userBuffer,
-             inBufferList->mBuffers[stream->handle[1]].mData,
-             inBufferList->mBuffers[stream->handle[1]].mDataByteSize );
-
-      if (stream->doByteSwap[1])
-        byteSwapBuffer(stream->userBuffer,
-                       stream->bufferSize * stream->nUserChannels[1],
-                       stream->userFormat);
-    }
-  }
-
-  if ( !info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[1] ) )
-    info->blockTick = false;
-
-  MUTEX_UNLOCK(&stream->mutex);
-
-}
-
-void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
-{
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  stream->callbackInfo.callback = (void *) callback;
-  stream->callbackInfo.userData = userData;
-  stream->callbackInfo.usingCallback = true;
-}
-
-//******************** End of __MACOSX_CORE__ *********************//
-
-#elif defined(__LINUX_ALSA__)
-
-#define MAX_DEVICES 16
-
-void RtAudio :: initialize(void)
-{
-  int card, result, device;
-  char name[32];
-  const char *cardId;
-  char deviceNames[MAX_DEVICES][32];
-  snd_ctl_t *handle;
-  snd_ctl_card_info_t *info;
-  snd_ctl_card_info_alloca(&info);
-
-  // Count cards and devices
-  nDevices = 0;
-  card = -1;
-  snd_card_next(&card);
-  while ( card >= 0 ) {
-    sprintf(name, "hw:%d", card);
-    result = snd_ctl_open(&handle, name, 0);
-    if (result < 0) {
-      sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(result));
-      error(RtError::DEBUG_WARNING);
-      goto next_card;
-               }
-    result = snd_ctl_card_info(handle, info);
-               if (result < 0) {
-      sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(result));
-      error(RtError::DEBUG_WARNING);
-      goto next_card;
-               }
-    cardId = snd_ctl_card_info_get_id(info);
-               device = -1;
-               while (1) {
-      result = snd_ctl_pcm_next_device(handle, &device);
-                       if (result < 0) {
-        sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(result));
-        error(RtError::DEBUG_WARNING);
-        break;
-      }
-                       if (device < 0)
-        break;
-      if ( strlen(cardId) )
-        sprintf( deviceNames[nDevices++], "hw:%s,%d", cardId, device );
-      else
-        sprintf( deviceNames[nDevices++], "hw:%d,%d", card, device );
-      if ( nDevices > MAX_DEVICES ) break;
-    }
-    if ( nDevices > MAX_DEVICES ) break;
-  next_card:
-    snd_ctl_close(handle);
-    snd_card_next(&card);
-  }
-
-  if (nDevices == 0) return;
-
-  //  Allocate the RTAUDIO_DEVICE structures.
-  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
-  if (devices == NULL) {
-    sprintf(message, "RtAudio: memory allocation error!");
-    error(RtError::MEMORY_ERROR);
-  }
-
-  // Write device ascii identifiers to device structures and then
-  // probe the device capabilities.
-  for (int i=0; i<nDevices; i++) {
-    strncpy(devices[i].name, deviceNames[i], 32);
-    //probeDeviceInfo(&devices[i]);
-  }
-}
-
-int RtAudio :: getDefaultInputDevice(void)
-{
-  // No ALSA API functions for default devices.
-  return 0;
-}
-
-int RtAudio :: getDefaultOutputDevice(void)
-{
-  // No ALSA API functions for default devices.
-  return 0;
-}
-
-void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
-{
-  int err;
-  int open_mode = SND_PCM_ASYNC;
-  snd_pcm_t *handle;
-  snd_ctl_t *chandle;
-  snd_pcm_stream_t stream;
-       snd_pcm_info_t *pcminfo;
-       snd_pcm_info_alloca(&pcminfo);
-  snd_pcm_hw_params_t *params;
-  snd_pcm_hw_params_alloca(&params);
-  char name[32];
-  char *card;
-
-  // Open the control interface for this card.
-  strncpy( name, info->name, 32 );
-  card = strtok(name, ",");
-  err = snd_ctl_open(&chandle, card, 0);
-  if (err < 0) {
-    sprintf(message, "RtAudio: ALSA control open (%s): %s.", card, snd_strerror(err));
-    error(RtError::DEBUG_WARNING);
-    return;
-  }
-  unsigned int dev = (unsigned int) atoi( strtok(NULL, ",") );
-
-  // First try for playback
-  stream = SND_PCM_STREAM_PLAYBACK;
-  snd_pcm_info_set_device(pcminfo, dev);
-  snd_pcm_info_set_subdevice(pcminfo, 0);
-  snd_pcm_info_set_stream(pcminfo, stream);
-
-  if ((err = snd_ctl_pcm_info(chandle, pcminfo)) < 0) {
-    if (err == -ENOENT) {
-      sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle output!", info->name);
-      error(RtError::DEBUG_WARNING);
-    }
-    else {
-      sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) output: %s",
-              info->name, snd_strerror(err));
-      error(RtError::DEBUG_WARNING);
-    }
-    goto capture_probe;
-  }
-
-  err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK );
-  if (err < 0) {
-    if ( err == EBUSY )
-      sprintf(message, "RtAudio: ALSA pcm playback device (%s) is busy: %s.",
-              info->name, snd_strerror(err));
-    else
-      sprintf(message, "RtAudio: ALSA pcm playback open (%s) error: %s.",
-              info->name, snd_strerror(err));
-    error(RtError::DEBUG_WARNING);
-    goto capture_probe;
-  }
-
-  // We have an open device ... allocate the parameter structure.
-  err = snd_pcm_hw_params_any(handle, params);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
-            info->name, snd_strerror(err));
-    error(RtError::WARNING);
-    goto capture_probe;
-  }
-
-  // Get output channel information.
-  info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params);
-  info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params);
-
-  snd_pcm_close(handle);
-
- capture_probe:
-  // Now try for capture
-  stream = SND_PCM_STREAM_CAPTURE;
-  snd_pcm_info_set_stream(pcminfo, stream);
-
-  err = snd_ctl_pcm_info(chandle, pcminfo);
-  snd_ctl_close(chandle);
-  if ( err < 0 ) {
-    if (err == -ENOENT) {
-      sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle input!", info->name);
-      error(RtError::DEBUG_WARNING);
-    }
-    else {
-      sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) input: %s",
-              info->name, snd_strerror(err));
-      error(RtError::DEBUG_WARNING);
-    }
-    if (info->maxOutputChannels == 0)
-      // didn't open for playback either ... device invalid
-      return;
-    goto probe_parameters;
-  }
-
-  err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK);
-  if (err < 0) {
-    if ( err == EBUSY )
-      sprintf(message, "RtAudio: ALSA pcm capture device (%s) is busy: %s.",
-              info->name, snd_strerror(err));
-    else
-      sprintf(message, "RtAudio: ALSA pcm capture open (%s) error: %s.",
-              info->name, snd_strerror(err));
-    error(RtError::DEBUG_WARNING);
-    if (info->maxOutputChannels == 0)
-      // didn't open for playback either ... device invalid
-      return;
-    goto probe_parameters;
-  }
-
-  // We have an open capture device ... allocate the parameter structure.
-  err = snd_pcm_hw_params_any(handle, params);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
-            info->name, snd_strerror(err));
-    error(RtError::WARNING);
-    if (info->maxOutputChannels > 0)
-      goto probe_parameters;
-    else
-      return;
-  }
-
-  // Get input channel information.
-  info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
-  info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
-
-  snd_pcm_close(handle);
-
-  // If device opens for both playback and capture, we determine the channels.
-  if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
-    goto probe_parameters;
-
-  info->hasDuplexSupport = true;
-  info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
-    info->maxInputChannels : info->maxOutputChannels;
-  info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
-    info->minInputChannels : info->minOutputChannels;
-
- probe_parameters:
-  // At this point, we just need to figure out the supported data
-  // formats and sample rates.  We'll proceed by opening the device in
-  // the direction with the maximum number of channels, or playback if
-  // they are equal.  This might limit our sample rate options, but so
-  // be it.
-
-  if (info->maxOutputChannels >= info->maxInputChannels)
-    stream = SND_PCM_STREAM_PLAYBACK;
-  else
-    stream = SND_PCM_STREAM_CAPTURE;
-
-  err = snd_pcm_open(&handle, info->name, stream, open_mode);
-  if (err < 0) {
-    sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.",
-            info->name, snd_strerror(err));
-    error(RtError::WARNING);
-    return;
-  }
-
-  // We have an open device ... allocate the parameter structure.
-  err = snd_pcm_hw_params_any(handle, params);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.",
-            info->name, snd_strerror(err));
-    error(RtError::WARNING);
-    return;
-  }
-
-  // Test a non-standard sample rate to see if continuous rate is supported.
-  int dir = 0;
-  if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
-    // It appears that continuous sample rate support is available.
-    info->nSampleRates = -1;
-    info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir);
-    info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir);
-  }
-  else {
-    // No continuous rate support ... test our discrete set of sample rate values.
-    info->nSampleRates = 0;
-    for (int i=0; i<MAX_SAMPLE_RATES; i++) {
-      if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) {
-        info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
-        info->nSampleRates++;
-      }
+        stream_.deviceBuffer = (char *) inBufferList->mBuffers[handle->index[1]].mData;
+
+      if ( stream_.doByteSwap[1] )
+        byteSwapBuffer(stream_.deviceBuffer,
+                       stream_.bufferSize * stream_.nDeviceChannels[1],
+                       stream_.deviceFormat[1]);
+      convertStreamBuffer(INPUT);
+
     }
-    if (info->nSampleRates == 0) {
-      snd_pcm_close(handle);
-      return;
+    else {
+      memcpy(stream_.userBuffer,
+             inBufferList->mBuffers[handle->index[1]].mData,
+             inBufferList->mBuffers[handle->index[1]].mDataByteSize );
+
+      if (stream_.doByteSwap[1])
+        byteSwapBuffer(stream_.userBuffer,
+                       stream_.bufferSize * stream_.nUserChannels[1],
+                       stream_.userFormat);
     }
   }
 
-  // Probe the supported data formats ... we don't care about endian-ness just yet
-  snd_pcm_format_t format;
-  info->nativeFormats = 0;
-  format = SND_PCM_FORMAT_S8;
-  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
-    info->nativeFormats |= RTAUDIO_SINT8;
-  format = SND_PCM_FORMAT_S16;
-  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
-    info->nativeFormats |= RTAUDIO_SINT16;
-  format = SND_PCM_FORMAT_S24;
-  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
-    info->nativeFormats |= RTAUDIO_SINT24;
-  format = SND_PCM_FORMAT_S32;
-  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
-    info->nativeFormats |= RTAUDIO_SINT32;
-  format = SND_PCM_FORMAT_FLOAT;
-  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
-    info->nativeFormats |= RTAUDIO_FLOAT32;
-  format = SND_PCM_FORMAT_FLOAT64;
-  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
-    info->nativeFormats |= RTAUDIO_FLOAT64;
+  if ( !info->usingCallback && (stream_.mode != DUPLEX || deviceId == id ) )
+    pthread_cond_signal(&handle->condition);
 
-  // Check that we have at least one supported format
-  if (info->nativeFormats == 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.",
-            info->name);
+  MUTEX_UNLOCK(&stream_.mutex);
+}
+
+void RtApiCore :: setStreamCallback(RtAudioCallback callback, void *userData)
+{
+  verifyStream();
+
+  if ( stream_.callbackInfo.usingCallback ) {
+    sprintf(message_, "RtApiCore: A callback is already set for this stream!");
     error(RtError::WARNING);
     return;
   }
 
-  // That's all ... close the device and return
-  snd_pcm_close(handle);
-  info->probed = true;
-  return;
+  stream_.callbackInfo.callback = (void *) callback;
+  stream_.callbackInfo.userData = userData;
+  stream_.callbackInfo.usingCallback = true;
 }
 
-bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
-                                STREAM_MODE mode, int channels, 
-                                int sampleRate, RTAUDIO_FORMAT format,
-                                int *bufferSize, int numberOfBuffers)
+void RtApiCore :: cancelStreamCallback()
 {
-#if defined(__RTAUDIO_DEBUG__)
-  snd_output_t *out;
-  snd_output_stdio_attach(&out, stderr, 0);
-#endif
+  verifyStream();
 
-  // I'm not using the "plug" interface ... too much inconsistent behavior.
-  const char *name = devices[device].name;
+  if (stream_.callbackInfo.usingCallback) {
 
-  snd_pcm_stream_t alsa_stream;
-  if (mode == OUTPUT)
-    alsa_stream = SND_PCM_STREAM_PLAYBACK;
-  else
-    alsa_stream = SND_PCM_STREAM_CAPTURE;
+    if (stream_.state == STREAM_RUNNING)
+      stopStream();
 
-  int err;
-  snd_pcm_t *handle;
-  int alsa_open_mode = SND_PCM_ASYNC;
-  err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
-  if (err < 0) {
-    sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.",
-            name, snd_strerror(err));
-    error(RtError::WARNING);
-    return FAILURE;
-  }
+    MUTEX_LOCK(&stream_.mutex);
 
-  // Fill the parameter structure.
-  snd_pcm_hw_params_t *hw_params;
-  snd_pcm_hw_params_alloca(&hw_params);
-  err = snd_pcm_hw_params_any(handle, hw_params);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.",
-            name, snd_strerror(err));
-    error(RtError::WARNING);
-    return FAILURE;
+    stream_.callbackInfo.usingCallback = false;
+    stream_.callbackInfo.userData = NULL;
+    stream_.state = STREAM_STOPPED;
+    stream_.callbackInfo.callback = NULL;
+
+    MUTEX_UNLOCK(&stream_.mutex);
   }
+}
 
-#if defined(__RTAUDIO_DEBUG__)
-  fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n");
-  snd_pcm_hw_params_dump(hw_params, out);
+
+//******************** End of __MACOSX_CORE__ *********************//
 #endif
 
+#if defined(__LINUX_JACK__)
 
-  // Set access ... try interleaved access first, then non-interleaved
-  if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) ) {
-    err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
-  }
-  else if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED) ) {
-               err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
-    stream->deInterleave[mode] = true;
-  }
-  else {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA device (%s) access not supported by RtAudio.", name);
-    error(RtError::WARNING);
-    return FAILURE;
-  }
+// JACK is a low-latency audio server, written primarily for the
+// GNU/Linux operating system. It can connect a number of different
+// applications to an audio device, as well as allowing them to share
+// audio between themselves.
+//
+// The JACK server must be running before RtApiJack can be instantiated.
+// RtAudio will report just a single "device", which is the JACK audio
+// server.  The JACK server is typically started in a terminal as follows:
+//
+// .jackd -d alsa -d hw:0
+//
+// Many of the parameters normally set for a stream are fixed by the
+// JACK server and can be specified when the JACK server is started.
+// In particular,
+//
+// .jackd -d alsa -d hw:0 -r 44100 -p 512 -n 4
+//
+// specifies a sample rate of 44100 Hz, a buffer size of 512 sample
+// frames, and number of buffers = 4.  Once the server is running, it
+// is not possible to override these values.  If the values are not
+// specified in the command-line, the JACK server uses default values.
 
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.", name, snd_strerror(err));
-    error(RtError::WARNING);
-    return FAILURE;
-  }
+#include <jack/jack.h>
+#include <unistd.h>
 
-  // Determine how to set the device format.
-  stream->userFormat = format;
-  snd_pcm_format_t device_format;
+// A structure to hold various information related to the Jack API
+// implementation.
+struct JackHandle {
+  jack_client_t *client;
+  jack_port_t **ports[2];
+  bool clientOpen;
+  bool stopStream;
+  pthread_cond_t condition;
+
+  JackHandle()
+    :client(0), clientOpen(false), stopStream(false) {}
+};
 
-  if (format == RTAUDIO_SINT8)
-    device_format = SND_PCM_FORMAT_S8;
-  else if (format == RTAUDIO_SINT16)
-    device_format = SND_PCM_FORMAT_S16;
-  else if (format == RTAUDIO_SINT24)
-    device_format = SND_PCM_FORMAT_S24;
-  else if (format == RTAUDIO_SINT32)
-    device_format = SND_PCM_FORMAT_S32;
-  else if (format == RTAUDIO_FLOAT32)
-    device_format = SND_PCM_FORMAT_FLOAT;
-  else if (format == RTAUDIO_FLOAT64)
-    device_format = SND_PCM_FORMAT_FLOAT64;
+std::string jackmsg;
 
-  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
-    stream->deviceFormat[mode] = format;
-    goto set_format;
-  }
+static void jackerror (const char *desc)
+{
+  jackmsg.erase();
+  jackmsg.append( desc, strlen(desc)+1 );
+}
 
-  // The user requested format is not natively supported by the device.
-  device_format = SND_PCM_FORMAT_FLOAT64;
-  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
-    stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
-    goto set_format;
-  }
+RtApiJack :: RtApiJack()
+{
+  this->initialize();
 
-  device_format = SND_PCM_FORMAT_FLOAT;
-  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
-    stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
-    goto set_format;
+  if (nDevices_ <= 0) {
+    sprintf(message_, "RtApiJack: no Linux Jack server found or connection error (jack: %s)!",
+            jackmsg.c_str());
+    error(RtError::NO_DEVICES_FOUND);
   }
+}
 
-  device_format = SND_PCM_FORMAT_S32;
-  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
-    stream->deviceFormat[mode] = RTAUDIO_SINT32;
-    goto set_format;
-  }
+RtApiJack :: ~RtApiJack()
+{
+  if ( stream_.mode != UNINITIALIZED ) closeStream();
+}
 
-  device_format = SND_PCM_FORMAT_S24;
-  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
-    stream->deviceFormat[mode] = RTAUDIO_SINT24;
-    goto set_format;
-  }
+void RtApiJack :: initialize(void)
+{
+  nDevices_ = 0;
 
-  device_format = SND_PCM_FORMAT_S16;
-  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
-    stream->deviceFormat[mode] = RTAUDIO_SINT16;
-    goto set_format;
-  }
+  // Tell the jack server to call jackerror() when it experiences an
+  // error.  This function saves the error message for subsequent
+  // reporting via the normal RtAudio error function.
+       jack_set_error_function( jackerror );
 
-  device_format = SND_PCM_FORMAT_S8;
-  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
-    stream->deviceFormat[mode] = RTAUDIO_SINT8;
-    goto set_format;
-  }
+  // Look for jack server and try to become a client.
+  jack_client_t *client;
+  if ( (client = jack_client_new( "RtApiJack" )) == 0)
+    return;
 
-  // If we get here, no supported format was found.
-  sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name);
-  snd_pcm_close(handle);
-  error(RtError::WARNING);
-  return FAILURE;
+  RtApiDevice device;
+  // Determine the name of the device.
+  device.name = "Jack Server";
+  devices_.push_back(device);
+  nDevices_++;
 
- set_format:
-  err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error setting format (%s): %s.",
-            name, snd_strerror(err));
+  jack_client_close(client);
+}
+
+void RtApiJack :: probeDeviceInfo(RtApiDevice *info)
+{
+  // Look for jack server and try to become a client.
+  jack_client_t *client;
+  if ( (client = jack_client_new( "RtApiJack" )) == 0) {
+    sprintf(message_, "RtApiJack: error connecting to Linux Jack server in probeDeviceInfo() (jack: %s)!",
+            jackmsg.c_str());
     error(RtError::WARNING);
-    return FAILURE;
+    return;
   }
 
-  // Determine whether byte-swaping is necessary.
-  stream->doByteSwap[mode] = false;
-  if (device_format != SND_PCM_FORMAT_S8) {
-    err = snd_pcm_format_cpu_endian(device_format);
-    if (err == 0)
-      stream->doByteSwap[mode] = true;
-    else if (err < 0) {
-      snd_pcm_close(handle);
-      sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.",
-              name, snd_strerror(err));
-      error(RtError::WARNING);
-      return FAILURE;
-    }
+  // Get the current jack server sample rate.
+  info->sampleRates.clear();
+  info->sampleRates.push_back( jack_get_sample_rate(client) );
+
+  // Count the available ports as device channels.  Jack "input ports"
+  // equal RtAudio output channels.
+  const char **ports;
+  char *port;
+  unsigned int nChannels = 0;
+  ports = jack_get_ports( client, NULL, NULL, JackPortIsInput );
+  if ( ports ) {
+    port = (char *) ports[nChannels];
+    while ( port )
+      port = (char *) ports[++nChannels];
+    free( ports );
+    info->maxOutputChannels = nChannels;
+    info->minOutputChannels = 1;
+  }
+
+  // Jack "output ports" equal RtAudio input channels.
+  nChannels = 0;
+  ports = jack_get_ports( client, NULL, NULL, JackPortIsOutput );
+  if ( ports ) {
+    port = (char *) ports[nChannels];
+    while ( port )
+      port = (char *) ports[++nChannels];
+    free( ports );
+    info->maxInputChannels = nChannels;
+    info->minInputChannels = 1;
   }
 
-  // Set the sample rate.
-  err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.",
-            sampleRate, name, snd_strerror(err));
+  if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
+    jack_client_close(client);
+    sprintf(message_, "RtApiJack: error determining jack input/output channels!");
     error(RtError::WARNING);
-    return FAILURE;
+    return;
   }
 
-  // Determine the number of channels for this device.  We support a possible
-  // minimum device channel number > than the value requested by the user.
-  stream->nUserChannels[mode] = channels;
-  int device_channels = snd_pcm_hw_params_get_channels_max(hw_params);
-  if (device_channels < channels) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: channels (%d) not supported by device (%s).",
-            channels, name);
-    error(RtError::WARNING);
-    return FAILURE;
+  if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
+    info->hasDuplexSupport = true;
+    info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
+      info->maxInputChannels : info->maxOutputChannels;
+    info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
+      info->minInputChannels : info->minOutputChannels;
   }
 
-  device_channels = snd_pcm_hw_params_get_channels_min(hw_params);
-  if (device_channels < channels) device_channels = channels;
-  stream->nDeviceChannels[mode] = device_channels;
+  // Get the jack data format type.  There isn't much documentation
+  // regarding supported data formats in jack.  I'm assuming here that
+  // the default type will always be a floating-point type, of length
+  // equal to either 4 or 8 bytes.
+  int sample_size = sizeof( jack_default_audio_sample_t );
+  if ( sample_size == 4 )
+    info->nativeFormats = RTAUDIO_FLOAT32;
+  else if ( sample_size == 8 )
+    info->nativeFormats = RTAUDIO_FLOAT64;
 
-  // Set the device channels.
-  err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.",
-            device_channels, name, snd_strerror(err));
+  // Check that we have a supported format
+  if (info->nativeFormats == 0) {
+    jack_client_close(client);
+    sprintf(message_, "RtApiJack: error determining jack server data format!");
     error(RtError::WARNING);
-    return FAILURE;
+    return;
   }
 
-  // Set the buffer number, which in ALSA is referred to as the "period".
-  int dir;
-  int periods = numberOfBuffers;
-  // Even though the hardware might allow 1 buffer, it won't work reliably.
-  if (periods < 2) periods = 2;
-  err = snd_pcm_hw_params_get_periods_min(hw_params, &dir);
-  if (err > periods) periods = err;
-  err = snd_pcm_hw_params_get_periods_max(hw_params, &dir);
-  if (err < periods) periods = err;
+  jack_client_close(client);
+  info->probed = true;
+}
 
-  err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.",
-            name, snd_strerror(err));
-    error(RtError::WARNING);
-    return FAILURE;
+int jackCallbackHandler(jack_nframes_t nframes, void *infoPointer)
+{
+  CallbackInfo *info = (CallbackInfo *) infoPointer;
+  RtApiJack *object = (RtApiJack *) info->object;
+  try {
+    object->callbackEvent( (unsigned long) nframes );
+  }
+  catch (RtError &exception) {
+    fprintf(stderr, "\nRtApiJack: callback handler error (%s)!\n\n", exception.getMessageString());
+    return 0;
   }
 
-  // Set the buffer (or period) size.
-  err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir);
-  if (err > *bufferSize) *bufferSize = err;
+  return 0;
+}
 
-  err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.",
-            name, snd_strerror(err));
-    error(RtError::WARNING);
-    return FAILURE;
+void jackShutdown(void *infoPointer)
+{
+  CallbackInfo *info = (CallbackInfo *) infoPointer;
+  JackHandle *handle = (JackHandle *) info->apiInfo;
+  handle->clientOpen = false;
+  RtApiJack *object = (RtApiJack *) info->object;
+  try {
+    object->closeStream();
+  }
+  catch (RtError &exception) {
+    fprintf(stderr, "\nRtApiJack: jackShutdown error (%s)!\n\n", exception.getMessageString());
+    return;
   }
 
-  // If attempting to setup a duplex stream, the bufferSize parameter
-  // MUST be the same in both directions!
-  if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
-    sprintf( message, "RtAudio: ALSA error setting buffer size for duplex stream on device (%s).",
-             name );
+  fprintf(stderr, "\nRtApiJack: the Jack server is shutting down ... stream stopped and closed!!!\n\n");
+}
+
+int jackXrun( void * )
+{
+  fprintf(stderr, "\nRtApiJack: audio overrun/underrun reported!\n");
+  return 0;
+}
+
+bool RtApiJack :: probeDeviceOpen(int device, StreamMode mode, int channels, 
+                                int sampleRate, RtAudioFormat format,
+                                int *bufferSize, int numberOfBuffers)
+{
+  // Compare the jack server channels to the requested number of channels.
+  if ( (mode == OUTPUT && devices_[device].maxOutputChannels < channels ) || 
+       (mode == INPUT && devices_[device].maxInputChannels < channels ) ) {
+    sprintf(message_, "RtApiJack: the Jack server does not support requested channels!");
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
 
-  stream->bufferSize = *bufferSize;
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;
 
-  // Install the hardware configuration
-  err = snd_pcm_hw_params(handle, hw_params);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.",
-            name, snd_strerror(err));
-    error(RtError::WARNING);
-    return FAILURE;
+  // Look for jack server and try to become a client (only do once per stream).
+  char label[32];
+  jack_client_t *client = 0;
+  if ( mode == OUTPUT || (mode == INPUT && stream_.mode != OUTPUT) ) {
+    snprintf(label, 32, "RtApiJack");
+    if ( (client = jack_client_new( (const char *) label )) == 0) {
+      sprintf(message_, "RtApiJack: cannot connect to Linux Jack server in probeDeviceOpen() (jack: %s)!",
+              jackmsg.c_str());
+      error(RtError::DEBUG_WARNING);
+      return FAILURE;
+    }
+  }
+  else {
+    // The handle must have been created on an earlier pass.
+    client = handle->client;
   }
 
-#if defined(__RTAUDIO_DEBUG__)
-  fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n");
-  snd_pcm_hw_params_dump(hw_params, out);
-#endif
-
-  /*
-  // Install the software configuration
-  snd_pcm_sw_params_t *sw_params = NULL;
-  snd_pcm_sw_params_alloca(&sw_params);
-  snd_pcm_sw_params_current(handle, sw_params);
-  err = snd_pcm_sw_params(handle, sw_params);
-  if (err < 0) {
-    snd_pcm_close(handle);
-    sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.",
-            name, snd_strerror(err));
-    error(RtError::WARNING);
+  // First, check the jack server sample rate.
+  int jack_rate;
+  jack_rate = (int) jack_get_sample_rate(client);
+  if ( sampleRate != jack_rate ) {
+    jack_client_close(client);
+    sprintf( message_, "RtApiJack: the requested sample rate (%d) is different than the JACK server rate (%d).",
+             sampleRate, jack_rate );
+    error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
-  */
-
-  // Set handle and flags for buffer conversion
-  stream->handle[mode] = handle;
-  stream->doConvertBuffer[mode] = false;
-  if (stream->userFormat != stream->deviceFormat[mode])
-    stream->doConvertBuffer[mode] = true;
-  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
-    stream->doConvertBuffer[mode] = true;
-  if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
-    stream->doConvertBuffer[mode] = true;
+  stream_.sampleRate = jack_rate;
+
+  // The jack server seems to support just a single floating-point
+  // data type.  Since we already checked it before, just use what we
+  // found then.
+  stream_.deviceFormat[mode] = devices_[device].nativeFormats;
+  stream_.userFormat = format;
+
+  // Jack always uses non-interleaved buffers.  We'll need to
+  // de-interleave if we have more than one channel.
+  stream_.deInterleave[mode] = false;
+  if ( channels > 1 )
+    stream_.deInterleave[mode] = true;
+
+  // Jack always provides host byte-ordered data.
+  stream_.doByteSwap[mode] = false;
+
+  // Get the buffer size.  The buffer size and number of buffers
+  // (periods) is set when the jack server is started.
+  stream_.bufferSize = (int) jack_get_buffer_size(client);
+  *bufferSize = stream_.bufferSize;
+
+  stream_.nDeviceChannels[mode] = channels;
+  stream_.nUserChannels[mode] = channels;
+
+  stream_.doConvertBuffer[mode] = false;
+  if (stream_.userFormat != stream_.deviceFormat[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.deInterleave[mode])
+    stream_.doConvertBuffer[mode] = true;
+
+  // Allocate our JackHandle structure for the stream.
+  if ( handle == 0 ) {
+    handle = (JackHandle *) calloc(1, sizeof(JackHandle));
+    if ( handle == NULL ) {
+      sprintf(message_, "RtApiJack: error allocating JackHandle memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
+    handle->ports[0] = 0;
+    handle->ports[1] = 0;
+    if ( pthread_cond_init(&handle->condition, NULL) ) {
+      sprintf(message_, "RtApiJack: error initializing pthread condition variable!");
+      goto error;
+    }
+    stream_.apiHandle = (void *) handle;
+    handle->client = client;
+    handle->clientOpen = true;
+  }
 
-  // Allocate necessary internal buffers
-  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
+  // Allocate necessary internal buffers.
+  if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
 
     long buffer_bytes;
-    if (stream->nUserChannels[0] >= stream->nUserChannels[1])
-      buffer_bytes = stream->nUserChannels[0];
+    if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
+      buffer_bytes = stream_.nUserChannels[0];
     else
-      buffer_bytes = stream->nUserChannels[1];
-
-    buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
-    if (stream->userBuffer) free(stream->userBuffer);
-    stream->userBuffer = (char *) calloc(buffer_bytes, 1);
-    if (stream->userBuffer == NULL)
-      goto memory_error;
+      buffer_bytes = stream_.nUserChannels[1];
+
+    buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
+    if (stream_.userBuffer) free(stream_.userBuffer);
+    stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
+    if (stream_.userBuffer == NULL) {
+      sprintf(message_, "RtApiJack: error allocating user buffer memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
   }
 
-  if ( stream->doConvertBuffer[mode] ) {
+  if ( stream_.doConvertBuffer[mode] ) {
 
     long buffer_bytes;
     bool makeBuffer = true;
     if ( mode == OUTPUT )
-      buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
     else { // mode == INPUT
-      buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
-      if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
-        long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+        long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
         if ( buffer_bytes < bytes_out ) makeBuffer = false;
       }
     }
 
     if ( makeBuffer ) {
       buffer_bytes *= *bufferSize;
-      if (stream->deviceBuffer) free(stream->deviceBuffer);
-      stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
-      if (stream->deviceBuffer == NULL)
-        goto memory_error;
+      if (stream_.deviceBuffer) free(stream_.deviceBuffer);
+      stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
+      if (stream_.deviceBuffer == NULL) {
+        sprintf(message_, "RtApiJack: error allocating device buffer memory (%s).",
+                devices_[device].name.c_str());
+        goto error;
+      }
     }
   }
 
-  stream->device[mode] = device;
-  stream->state = STREAM_STOPPED;
-  if ( stream->mode == OUTPUT && mode == INPUT )
-    // We had already set up an output stream.
-    stream->mode = DUPLEX;
-  else
-    stream->mode = mode;
-  stream->nBuffers = periods;
-  stream->sampleRate = sampleRate;
+  // Allocate memory for the Jack ports (channels) identifiers.
+  handle->ports[mode] = (jack_port_t **) malloc (sizeof (jack_port_t *) * channels);
+  if ( handle->ports[mode] == NULL )  {
+    sprintf(message_, "RtApiJack: error allocating port handle memory (%s).",
+            devices_[device].name.c_str());
+    goto error;
+  }
 
-  return SUCCESS;
+  stream_.device[mode] = device;
+  stream_.state = STREAM_STOPPED;
+  stream_.callbackInfo.usingCallback = false;
+  stream_.callbackInfo.object = (void *) this;
+  stream_.callbackInfo.apiInfo = (void *) handle;
 
- memory_error:
-  if (stream->handle[0]) {
-    snd_pcm_close(stream->handle[0]);
-    stream->handle[0] = 0;
+  if ( stream_.mode == OUTPUT && mode == INPUT )
+    // We had already set up the stream for output.
+    stream_.mode = DUPLEX;
+  else {
+    stream_.mode = mode;
+    jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
+    jack_set_xrun_callback( handle->client, jackXrun, NULL );
+    jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
   }
-  if (stream->handle[1]) {
-    snd_pcm_close(stream->handle[1]);
-    stream->handle[1] = 0;
+
+  return SUCCESS;
+
+ error:
+  if ( handle ) {
+    pthread_cond_destroy(&handle->condition);
+    if ( handle->clientOpen == true )
+      jack_client_close(handle->client);
+
+    if ( handle->ports[0] ) free(handle->ports[0]);
+    if ( handle->ports[1] ) free(handle->ports[1]);
+
+    free( handle );
+    stream_.apiHandle = 0;
   }
-  if (stream->userBuffer) {
-    free(stream->userBuffer);
-    stream->userBuffer = 0;
+
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
   }
-  sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name);
+
   error(RtError::WARNING);
   return FAILURE;
 }
 
-void RtAudio :: closeStream(int streamId)
+void RtApiJack :: closeStream()
 {
   // We don't want an exception to be thrown here because this
   // function is called by our class destructor.  So, do our own
-  // streamId check.
-  if ( streams.find( streamId ) == streams.end() ) {
-    sprintf(message, "RtAudio: invalid stream identifier!");
+  // stream check.
+  if ( stream_.mode == UNINITIALIZED ) {
+    sprintf(message_, "RtApiJack::closeStream(): no open stream to close!");
     error(RtError::WARNING);
     return;
   }
 
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;
+  if ( handle && handle->clientOpen == true ) {
+    if (stream_.state == STREAM_RUNNING)
+      jack_deactivate(handle->client);
 
-  if (stream->callbackInfo.usingCallback) {
-    pthread_cancel(stream->callbackInfo.thread);
-    pthread_join(stream->callbackInfo.thread, NULL);
+    jack_client_close(handle->client);
   }
 
-  if (stream->state == STREAM_RUNNING) {
-    if (stream->mode == OUTPUT || stream->mode == DUPLEX)
-      snd_pcm_drop(stream->handle[0]);
-    if (stream->mode == INPUT || stream->mode == DUPLEX)
-      snd_pcm_drop(stream->handle[1]);
+  if ( handle ) {
+    if ( handle->ports[0] ) free(handle->ports[0]);
+    if ( handle->ports[1] ) free(handle->ports[1]);
+    pthread_cond_destroy(&handle->condition);
+    free( handle );
+    stream_.apiHandle = 0;
   }
 
-  pthread_mutex_destroy(&stream->mutex);
-
-  if (stream->handle[0])
-    snd_pcm_close(stream->handle[0]);
-
-  if (stream->handle[1])
-    snd_pcm_close(stream->handle[1]);
-
-  if (stream->userBuffer)
-    free(stream->userBuffer);
-
-  if (stream->deviceBuffer)
-    free(stream->deviceBuffer);
-
-  free(stream);
-  streams.erase(streamId);
-}
-
-void RtAudio :: startStream(int streamId)
-{
-  // This method calls snd_pcm_prepare if the device isn't already in that state.
-
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
-
-  if (stream->state == STREAM_RUNNING)
-    goto unlock;
-
-  int err;
-  snd_pcm_state_t state;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    state = snd_pcm_state(stream->handle[0]);
-    if (state != SND_PCM_STATE_PREPARED) {
-      err = snd_pcm_prepare(stream->handle[0]);
-      if (err < 0) {
-        sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
-                devices[stream->device[0]].name, snd_strerror(err));
-        MUTEX_UNLOCK(&stream->mutex);
-        error(RtError::DRIVER_ERROR);
-      }
-    }
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    state = snd_pcm_state(stream->handle[1]);
-    if (state != SND_PCM_STATE_PREPARED) {
-      err = snd_pcm_prepare(stream->handle[1]);
-      if (err < 0) {
-        sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
-                devices[stream->device[1]].name, snd_strerror(err));
-        MUTEX_UNLOCK(&stream->mutex);
-        error(RtError::DRIVER_ERROR);
-      }
-    }
+  if (stream_.deviceBuffer) {
+    free(stream_.deviceBuffer);
+    stream_.deviceBuffer = 0;
   }
-  stream->state = STREAM_RUNNING;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  stream_.mode = UNINITIALIZED;
 }
 
-void RtAudio :: stopStream(int streamId)
-{
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
-
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
-
-  int err;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    err = snd_pcm_drain(stream->handle[0]);
-    if (err < 0) {
-      sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
-              devices[stream->device[0]].name, snd_strerror(err));
-      MUTEX_UNLOCK(&stream->mutex);
-      error(RtError::DRIVER_ERROR);
-    }
-  }
-
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    err = snd_pcm_drain(stream->handle[1]);
-    if (err < 0) {
-      sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
-              devices[stream->device[1]].name, snd_strerror(err));
-      MUTEX_UNLOCK(&stream->mutex);
-      error(RtError::DRIVER_ERROR);
-    }
-  }
-  stream->state = STREAM_STOPPED;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
-}
-
-void RtAudio :: abortStream(int streamId)
+void RtApiJack :: startStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
+  verifyStream();
+  if (stream_.state == STREAM_RUNNING) return;
 
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
+  MUTEX_LOCK(&stream_.mutex);
 
-  int err;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    err = snd_pcm_drop(stream->handle[0]);
-    if (err < 0) {
-      sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
-              devices[stream->device[0]].name, snd_strerror(err));
-      MUTEX_UNLOCK(&stream->mutex);
-      error(RtError::DRIVER_ERROR);
+  char label[64];
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+    for ( int i=0; i<stream_.nUserChannels[0]; i++ ) {
+      snprintf(label, 64, "outport %d", i);
+      handle->ports[0][i] = jack_port_register(handle->client, (const char *)label,
+                                               JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
     }
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    err = snd_pcm_drop(stream->handle[1]);
-    if (err < 0) {
-      sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
-              devices[stream->device[1]].name, snd_strerror(err));
-      MUTEX_UNLOCK(&stream->mutex);
-      error(RtError::DRIVER_ERROR);
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+    for ( int i=0; i<stream_.nUserChannels[1]; i++ ) {
+      snprintf(label, 64, "inport %d", i);
+      handle->ports[1][i] = jack_port_register(handle->client, (const char *)label,
+                                               JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
     }
   }
-  stream->state = STREAM_STOPPED;
-
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
-}
-
-int RtAudio :: streamWillBlock(int streamId)
-{
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
 
-  int err = 0, frames = 0;
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
-
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    err = snd_pcm_avail_update(stream->handle[0]);
-    if (err < 0) {
-      sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
-              devices[stream->device[0]].name, snd_strerror(err));
-      MUTEX_UNLOCK(&stream->mutex);
-      error(RtError::DRIVER_ERROR);
-    }
+  if (jack_activate(handle->client)) {
+    sprintf(message_, "RtApiJack: unable to activate JACK client!");
+    error(RtError::SYSTEM_ERROR);
   }
 
-  frames = err;
-
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    err = snd_pcm_avail_update(stream->handle[1]);
-    if (err < 0) {
-      sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
-              devices[stream->device[1]].name, snd_strerror(err));
-      MUTEX_UNLOCK(&stream->mutex);
-      error(RtError::DRIVER_ERROR);
+  const char **ports;
+  int result;
+  // Get the list of available ports.
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+    ports = jack_get_ports(handle->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
+    if ( ports == NULL) {
+      sprintf(message_, "RtApiJack: error determining available jack input ports!");
+      error(RtError::SYSTEM_ERROR);
+    }
+
+    // Now make the port connections.  Since RtAudio wasn't designed to
+    // allow the user to select particular channels of a device, we'll
+    // just open the first "nChannels" ports.
+    for ( int i=0; i<stream_.nUserChannels[0]; i++ ) {
+      result = 1;
+      if ( ports[i] )
+        result = jack_connect( handle->client, jack_port_name(handle->ports[0][i]), ports[i] );
+      if ( result ) {
+        free(ports);
+        sprintf(message_, "RtApiJack: error connecting output ports!");
+        error(RtError::SYSTEM_ERROR);
+      }
     }
-    if (frames > err) frames = err;
-  }
-
-  frames = stream->bufferSize - frames;
-  if (frames < 0) frames = 0;
-
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
-  return frames;
-}
-
-void RtAudio :: tickStream(int streamId)
-{
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  int stopStream = 0;
-  if (stream->state == STREAM_STOPPED) {
-    if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
-    return;
-  }
-  else if (stream->callbackInfo.usingCallback) {
-    RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
-    stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
+    free(ports);
   }
 
-  MUTEX_LOCK(&stream->mutex);
-
-  // The state might change while waiting on a mutex.
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
-
-  int err;
-  char *buffer;
-  int channels;
-  RTAUDIO_FORMAT format;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-
-    // Setup parameters and do buffer conversion if necessary.
-    if (stream->doConvertBuffer[0]) {
-      convertStreamBuffer(stream, OUTPUT);
-      buffer = stream->deviceBuffer;
-      channels = stream->nDeviceChannels[0];
-      format = stream->deviceFormat[0];
-    }
-    else {
-      buffer = stream->userBuffer;
-      channels = stream->nUserChannels[0];
-      format = stream->userFormat;
-    }
-
-    // Do byte swapping if necessary.
-    if (stream->doByteSwap[0])
-      byteSwapBuffer(buffer, stream->bufferSize * channels, format);
-
-    // Write samples to device in interleaved/non-interleaved format.
-    if (stream->deInterleave[0]) {
-      void *bufs[channels];
-      size_t offset = stream->bufferSize * formatBytes(format);
-      for (int i=0; i<channels; i++)
-        bufs[i] = (void *) (buffer + (i * offset));
-      err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize);
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+    ports = jack_get_ports( handle->client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput );
+    if ( ports == NULL) {
+      sprintf(message_, "RtApiJack: error determining available jack output ports!");
+      error(RtError::SYSTEM_ERROR);
     }
-    else
-      err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize);
 
-    if (err < stream->bufferSize) {
-      // Either an error or underrun occured.
-      if (err == -EPIPE) {
-        snd_pcm_state_t state = snd_pcm_state(stream->handle[0]);
-        if (state == SND_PCM_STATE_XRUN) {
-          sprintf(message, "RtAudio: ALSA underrun detected.");
-          error(RtError::WARNING);
-          err = snd_pcm_prepare(stream->handle[0]);
-          if (err < 0) {
-            sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.",
-                    snd_strerror(err));
-            MUTEX_UNLOCK(&stream->mutex);
-            error(RtError::DRIVER_ERROR);
-          }
-        }
-        else {
-          sprintf(message, "RtAudio: ALSA error, current state is %s.",
-                  snd_pcm_state_name(state));
-          MUTEX_UNLOCK(&stream->mutex);
-          error(RtError::DRIVER_ERROR);
-        }
-        goto unlock;
-      }
-      else {
-        sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.",
-                devices[stream->device[0]].name, snd_strerror(err));
-        MUTEX_UNLOCK(&stream->mutex);
-        error(RtError::DRIVER_ERROR);
+    // Now make the port connections.  See note above.
+    for ( int i=0; i<stream_.nUserChannels[1]; i++ ) {
+      result = 1;
+      if ( ports[i] )
+        result = jack_connect( handle->client, ports[i], jack_port_name(handle->ports[1][i]) );
+      if ( result ) {
+        free(ports);
+        sprintf(message_, "RtApiJack: error connecting input ports!");
+        error(RtError::SYSTEM_ERROR);
       }
     }
+    free(ports);
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-
-    // Setup parameters.
-    if (stream->doConvertBuffer[1]) {
-      buffer = stream->deviceBuffer;
-      channels = stream->nDeviceChannels[1];
-      format = stream->deviceFormat[1];
-    }
-    else {
-      buffer = stream->userBuffer;
-      channels = stream->nUserChannels[1];
-      format = stream->userFormat;
-    }
+  handle->stopStream = false;
+  stream_.state = STREAM_RUNNING;
 
-    // Read samples from device in interleaved/non-interleaved format.
-    if (stream->deInterleave[1]) {
-      void *bufs[channels];
-      size_t offset = stream->bufferSize * formatBytes(format);
-      for (int i=0; i<channels; i++)
-        bufs[i] = (void *) (buffer + (i * offset));
-      err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize);
-    }
-    else
-      err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize);
+  MUTEX_UNLOCK(&stream_.mutex);
+}
 
-    if (err < stream->bufferSize) {
-      // Either an error or underrun occured.
-      if (err == -EPIPE) {
-        snd_pcm_state_t state = snd_pcm_state(stream->handle[1]);
-        if (state == SND_PCM_STATE_XRUN) {
-          sprintf(message, "RtAudio: ALSA overrun detected.");
-          error(RtError::WARNING);
-          err = snd_pcm_prepare(stream->handle[1]);
-          if (err < 0) {
-            sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.",
-                    snd_strerror(err));
-            MUTEX_UNLOCK(&stream->mutex);
-            error(RtError::DRIVER_ERROR);
-          }
-        }
-        else {
-          sprintf(message, "RtAudio: ALSA error, current state is %s.",
-                  snd_pcm_state_name(state));
-          MUTEX_UNLOCK(&stream->mutex);
-          error(RtError::DRIVER_ERROR);
-        }
-        goto unlock;
-      }
-      else {
-        sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.",
-                devices[stream->device[1]].name, snd_strerror(err));
-        MUTEX_UNLOCK(&stream->mutex);
-        error(RtError::DRIVER_ERROR);
-      }
-    }
+void RtApiJack :: stopStream()
+{
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-    // Do byte swapping if necessary.
-    if (stream->doByteSwap[1])
-      byteSwapBuffer(buffer, stream->bufferSize * channels, format);
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
-    // Do buffer conversion if necessary.
-    if (stream->doConvertBuffer[1])
-      convertStreamBuffer(stream, INPUT);
-  }
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;
+  jack_deactivate(handle->client);
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
+}
 
-  if (stream->callbackInfo.usingCallback && stopStream)
-    this->stopStream(streamId);
+void RtApiJack :: abortStream()
+{
+  stopStream();
 }
 
-extern "C" void *callbackHandler(void *ptr)
+void RtApiJack :: tickStream()
 {
-  CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
-  RtAudio *object = (RtAudio *) info->object;
-  int stream = info->streamId;
-  bool *usingCallback = &info->usingCallback;
+  verifyStream();
 
-  while ( *usingCallback ) {
-    pthread_testcancel();
-    try {
-      object->tickStream(stream);
-    }
-    catch (RtError &exception) {
-      fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
-              exception.getMessage());
-      break;
-    }
-  }
+  if (stream_.state == STREAM_STOPPED) return;
 
-  return 0;
-}
+  if (stream_.callbackInfo.usingCallback) {
+    sprintf(message_, "RtApiJack: tickStream() should not be used when a callback function is set!");
+    error(RtError::WARNING);
+    return;
+  }
 
-//******************** End of __LINUX_ALSA__ *********************//
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;
 
-#elif defined(__LINUX_OSS__)
+  MUTEX_LOCK(&stream_.mutex);
 
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/soundcard.h>
-#include <errno.h>
-#include <math.h>
+  pthread_cond_wait(&handle->condition, &stream_.mutex);
 
-#define DAC_NAME "/dev/dsp"
-#define MAX_DEVICES 16
-#define MAX_CHANNELS 16
+  MUTEX_UNLOCK(&stream_.mutex);
+}
 
-void RtAudio :: initialize(void)
+void RtApiJack :: callbackEvent( unsigned long nframes )
 {
-  // Count cards and devices
-  nDevices = 0;
+  verifyStream();
 
-  // We check /dev/dsp before probing devices.  /dev/dsp is supposed to
-  // be a link to the "default" audio device, of the form /dev/dsp0,
-  // /dev/dsp1, etc...  However, I've seen many cases where /dev/dsp was a
-  // real device, so we need to check for that.  Also, sometimes the
-  // link is to /dev/dspx and other times just dspx.  I'm not sure how
-  // the latter works, but it does.
-  char device_name[16];
-  struct stat dspstat;
-  int dsplink = -1;
-  int i = 0;
-  if (lstat(DAC_NAME, &dspstat) == 0) {
-    if (S_ISLNK(dspstat.st_mode)) {
-      i = readlink(DAC_NAME, device_name, sizeof(device_name));
-      if (i > 0) {
-        device_name[i] = '\0';
-        if (i > 8) { // check for "/dev/dspx"
-          if (!strncmp(DAC_NAME, device_name, 8))
-            dsplink = atoi(&device_name[8]);
-        }
-        else if (i > 3) { // check for "dspx"
-          if (!strncmp("dsp", device_name, 3))
-            dsplink = atoi(&device_name[3]);
-        }
-      }
-      else {
-        sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME);
-        error(RtError::SYSTEM_ERROR);
-      }
-    }
-  }
-  else {
-    sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME);
-    error(RtError::SYSTEM_ERROR);
+  if (stream_.state == STREAM_STOPPED) return;
+
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+  JackHandle *handle = (JackHandle *) stream_.apiHandle;
+  if ( info->usingCallback && handle->stopStream ) {
+    // Check if the stream should be stopped (via the previous user
+    // callback return value).  We stop the stream here, rather than
+    // after the function call, so that output data can first be
+    // processed.
+    this->stopStream();
+    return;
   }
 
-  // The OSS API doesn't provide a routine for determining the number
-  // of devices.  Thus, we'll just pursue a brute force method.  The
-  // idea is to start with /dev/dsp(0) and continue with higher device
-  // numbers until we reach MAX_DSP_DEVICES.  This should tell us how
-  // many devices we have ... it is not a fullproof scheme, but hopefully
-  // it will work most of the time.
+  MUTEX_LOCK(&stream_.mutex);
 
-  int fd = 0;
-  char names[MAX_DEVICES][16];
-  for (i=-1; i<MAX_DEVICES; i++) {
+  // Invoke user callback first, to get fresh output data.
+  if ( info->usingCallback ) {
+    RtAudioCallback callback = (RtAudioCallback) info->callback;
+    handle->stopStream = callback(stream_.userBuffer, stream_.bufferSize, info->userData);
+  }
 
-    // Probe /dev/dsp first, since it is supposed to be the default device.
-    if (i == -1)
-      sprintf(device_name, "%s", DAC_NAME);
-    else if (i == dsplink)
-      continue; // We've aready probed this device via /dev/dsp link ... try next device.
-    else
-      sprintf(device_name, "%s%d", DAC_NAME, i);
+  jack_default_audio_sample_t *jackbuffer;
+  long bufferBytes = nframes * sizeof (jack_default_audio_sample_t);
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
 
-    // First try to open the device for playback, then record mode.
-    fd = open(device_name, O_WRONLY | O_NONBLOCK);
-    if (fd == -1) {
-      // Open device for playback failed ... either busy or doesn't exist.
-      if (errno != EBUSY && errno != EAGAIN) {
-        // Try to open for capture
-        fd = open(device_name, O_RDONLY | O_NONBLOCK);
-        if (fd == -1) {
-          // Open device for record failed.
-          if (errno != EBUSY && errno != EAGAIN)
-            continue;
-          else {
-            sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name);
-            error(RtError::WARNING);
-            // still count it for now
-          }
-        }
-      }
-      else {
-        sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
-        error(RtError::WARNING);
-        // still count it for now
+    if (stream_.doConvertBuffer[0]) {
+      convertStreamBuffer(OUTPUT);
+
+      for ( int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
+        jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][i],
+                                                                          (jack_nframes_t) nframes);
+        memcpy(jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
       }
     }
+    else { // single channel only
+      jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][0],
+                                                                        (jack_nframes_t) nframes);
+      memcpy(jackbuffer, stream_.userBuffer, bufferBytes );
+    }
+  }
 
-    if (fd >= 0) close(fd);
-    strncpy(names[nDevices], device_name, 16);
-    nDevices++;
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+
+    if (stream_.doConvertBuffer[1]) {
+    for ( int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
+      jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[1][i],
+                                                                        (jack_nframes_t) nframes);
+      memcpy(&stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes );
+    }
+    convertStreamBuffer(INPUT);
+    }
+    else { // single channel only
+      jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[1][0],
+                                                                        (jack_nframes_t) nframes);
+      memcpy(stream_.userBuffer, jackbuffer, bufferBytes );
+    }
   }
 
-  if (nDevices == 0) return;
+  if ( !info->usingCallback )
+    pthread_cond_signal(&handle->condition);
 
-  //  Allocate the RTAUDIO_DEVICE structures.
-  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
-  if (devices == NULL) {
-    sprintf(message, "RtAudio: memory allocation error!");
-    error(RtError::MEMORY_ERROR);
+  MUTEX_UNLOCK(&stream_.mutex);
+}
+
+void RtApiJack :: setStreamCallback(RtAudioCallback callback, void *userData)
+{
+  verifyStream();
+
+  if ( stream_.callbackInfo.usingCallback ) {
+    sprintf(message_, "RtApiJack: A callback is already set for this stream!");
+    error(RtError::WARNING);
+    return;
   }
 
-  // Write device ascii identifiers to device control structure and then probe capabilities.
-  for (i=0; i<nDevices; i++) {
-    strncpy(devices[i].name, names[i], 16);
-    //probeDeviceInfo(&devices[i]);
+  stream_.callbackInfo.callback = (void *) callback;
+  stream_.callbackInfo.userData = userData;
+  stream_.callbackInfo.usingCallback = true;
+}
+
+void RtApiJack :: cancelStreamCallback()
+{
+  verifyStream();
+
+  if (stream_.callbackInfo.usingCallback) {
+
+    if (stream_.state == STREAM_RUNNING)
+      stopStream();
+
+    MUTEX_LOCK(&stream_.mutex);
+
+    stream_.callbackInfo.usingCallback = false;
+    stream_.callbackInfo.userData = NULL;
+    stream_.state = STREAM_STOPPED;
+    stream_.callbackInfo.callback = NULL;
+
+    MUTEX_UNLOCK(&stream_.mutex);
   }
+}
 
-  return;
+#endif
+
+#if defined(__LINUX_ALSA__)
+
+#include <alsa/asoundlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
+extern "C" void *alsaCallbackHandler(void * ptr);
+
+RtApiAlsa :: RtApiAlsa()
+{
+  this->initialize();
+
+  if (nDevices_ <= 0) {
+    sprintf(message_, "RtApiAlsa: no Linux ALSA audio devices found!");
+    error(RtError::NO_DEVICES_FOUND);
+  }
 }
 
-int RtAudio :: getDefaultInputDevice(void)
+RtApiAlsa :: ~RtApiAlsa()
 {
-  // No OSS API functions for default devices.
-  return 0;
+  if ( stream_.mode != UNINITIALIZED )
+    closeStream();
 }
 
-int RtAudio :: getDefaultOutputDevice(void)
+void RtApiAlsa :: initialize(void)
 {
-  // No OSS API functions for default devices.
-  return 0;
+  int card, subdevice, result;
+  char name[64];
+  const char *cardId;
+  snd_ctl_t *handle;
+  snd_ctl_card_info_t *info;
+  snd_ctl_card_info_alloca(&info);
+  RtApiDevice device;
+
+  // Count cards and devices
+  nDevices_ = 0;
+  card = -1;
+  snd_card_next(&card);
+  while ( card >= 0 ) {
+    sprintf(name, "hw:%d", card);
+    result = snd_ctl_open(&handle, name, 0);
+    if (result < 0) {
+      sprintf(message_, "RtApiAlsa: control open (%i): %s.", card, snd_strerror(result));
+      error(RtError::DEBUG_WARNING);
+      goto next_card;
+               }
+    result = snd_ctl_card_info(handle, info);
+               if (result < 0) {
+      sprintf(message_, "RtApiAlsa: control hardware info (%i): %s.", card, snd_strerror(result));
+      error(RtError::DEBUG_WARNING);
+      goto next_card;
+               }
+    cardId = snd_ctl_card_info_get_id(info);
+               subdevice = -1;
+               while (1) {
+      result = snd_ctl_pcm_next_device(handle, &subdevice);
+                       if (result < 0) {
+        sprintf(message_, "RtApiAlsa: control next device (%i): %s.", card, snd_strerror(result));
+        error(RtError::DEBUG_WARNING);
+        break;
+      }
+                       if (subdevice < 0)
+        break;
+      sprintf( name, "hw:%d,%d", card, subdevice );
+      // If a cardId exists and it contains at least one non-numeric
+      // character, use it to identify the device.  This avoids a bug
+      // in ALSA such that a numeric string is interpreted as a device
+      // number.
+      for ( unsigned int i=0; i<strlen(cardId); i++ ) {
+        if ( !isdigit( cardId[i] ) ) {
+          sprintf( name, "hw:%s,%d", cardId, subdevice );
+          break;
+        }
+      }
+      device.name.erase();
+      device.name.append( (const char *)name, strlen(name)+1 );
+      devices_.push_back(device);
+      nDevices_++;
+    }
+  next_card:
+    snd_ctl_close(handle);
+    snd_card_next(&card);
+  }
 }
 
-void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
+void RtApiAlsa :: probeDeviceInfo(RtApiDevice *info)
 {
-  int i, fd, channels, mask;
+  int err;
+  int open_mode = SND_PCM_ASYNC;
+  snd_pcm_t *handle;
+  snd_ctl_t *chandle;
+  snd_pcm_stream_t stream;
+       snd_pcm_info_t *pcminfo;
+       snd_pcm_info_alloca(&pcminfo);
+  snd_pcm_hw_params_t *params;
+  snd_pcm_hw_params_alloca(&params);
+  char name[64];
+  char *card;
 
-  // The OSS API doesn't provide a means for probing the capabilities
-  // of devices.  Thus, we'll just pursue a brute force method.
+  // Open the control interface for this card.
+  strncpy( name, info->name.c_str(), 64 );
+  card = strtok(name, ",");
+  err = snd_ctl_open(&chandle, card, SND_CTL_NONBLOCK);
+  if (err < 0) {
+    sprintf(message_, "RtApiAlsa: control open (%s): %s.", card, snd_strerror(err));
+    error(RtError::DEBUG_WARNING);
+    return;
+  }
+  unsigned int dev = (unsigned int) atoi( strtok(NULL, ",") );
 
   // First try for playback
-  fd = open(info->name, O_WRONLY | O_NONBLOCK);
-  if (fd == -1) {
-    // Open device failed ... either busy or doesn't exist
-    if (errno == EBUSY || errno == EAGAIN)
-      sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.",
-              info->name);
+  stream = SND_PCM_STREAM_PLAYBACK;
+  snd_pcm_info_set_device(pcminfo, dev);
+  snd_pcm_info_set_subdevice(pcminfo, 0);
+  snd_pcm_info_set_stream(pcminfo, stream);
+
+  if ((err = snd_ctl_pcm_info(chandle, pcminfo)) < 0) {
+    if (err == -ENOENT) {
+      sprintf(message_, "RtApiAlsa: pcm device (%s) doesn't handle output!", info->name.c_str());
+      error(RtError::DEBUG_WARNING);
+    }
+    else {
+      sprintf(message_, "RtApiAlsa: snd_ctl_pcm_info error for device (%s) output: %s",
+              info->name.c_str(), snd_strerror(err));
+      error(RtError::DEBUG_WARNING);
+    }
+    goto capture_probe;
+  }
+
+  err = snd_pcm_open(&handle, info->name.c_str(), stream, open_mode | SND_PCM_NONBLOCK );
+  if (err < 0) {
+    if ( err == EBUSY )
+      sprintf(message_, "RtApiAlsa: pcm playback device (%s) is busy: %s.",
+              info->name.c_str(), snd_strerror(err));
     else
-      sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name);
+      sprintf(message_, "RtApiAlsa: pcm playback open (%s) error: %s.",
+              info->name.c_str(), snd_strerror(err));
     error(RtError::DEBUG_WARNING);
     goto capture_probe;
   }
 
-  // We have an open device ... see how many channels it can handle
-  for (i=MAX_CHANNELS; i>0; i--) {
-    channels = i;
-    if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
-      // This would normally indicate some sort of hardware error, but under ALSA's
-      // OSS emulation, it sometimes indicates an invalid channel value.  Further,
-      // the returned channel value is not changed. So, we'll ignore the possible
-      // hardware error.
-      continue; // try next channel number
-    }
-    // Check to see whether the device supports the requested number of channels
-    if (channels != i ) continue; // try next channel number
-    // If here, we found the largest working channel value
-    break;
+  // We have an open device ... allocate the parameter structure.
+  err = snd_pcm_hw_params_any(handle, params);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: hardware probe error (%s): %s.",
+            info->name.c_str(), snd_strerror(err));
+    error(RtError::WARNING);
+    goto capture_probe;
   }
-  info->maxOutputChannels = i;
 
-  // Now find the minimum number of channels it can handle
-  for (i=1; i<=info->maxOutputChannels; i++) {
-    channels = i;
-    if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
-      continue; // try next channel number
-    // If here, we found the smallest working channel value
-    break;
+  // Get output channel information.
+  unsigned int value;
+  err = snd_pcm_hw_params_get_channels_min(params, &value);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: hardware minimum channel probe error (%s): %s.",
+            info->name.c_str(), snd_strerror(err));
+    error(RtError::WARNING);
+    goto capture_probe;
   }
-  info->minOutputChannels = i;
-  close(fd);
+  info->minOutputChannels = value;
+
+  err = snd_pcm_hw_params_get_channels_max(params, &value);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: hardware maximum channel probe error (%s): %s.",
+            info->name.c_str(), snd_strerror(err));
+    error(RtError::WARNING);
+    goto capture_probe;
+  }
+  info->maxOutputChannels = value;
+
+  snd_pcm_close(handle);
 
  capture_probe:
   // Now try for capture
-  fd = open(info->name, O_RDONLY | O_NONBLOCK);
-  if (fd == -1) {
-    // Open device for capture failed ... either busy or doesn't exist
-    if (errno == EBUSY || errno == EAGAIN)
-      sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.",
-              info->name);
+  stream = SND_PCM_STREAM_CAPTURE;
+  snd_pcm_info_set_stream(pcminfo, stream);
+
+  err = snd_ctl_pcm_info(chandle, pcminfo);
+  snd_ctl_close(chandle);
+  if ( err < 0 ) {
+    if (err == -ENOENT) {
+      sprintf(message_, "RtApiAlsa: pcm device (%s) doesn't handle input!", info->name.c_str());
+      error(RtError::DEBUG_WARNING);
+    }
+    else {
+      sprintf(message_, "RtApiAlsa: snd_ctl_pcm_info error for device (%s) input: %s",
+              info->name.c_str(), snd_strerror(err));
+      error(RtError::DEBUG_WARNING);
+    }
+    if (info->maxOutputChannels == 0)
+      // didn't open for playback either ... device invalid
+      return;
+    goto probe_parameters;
+  }
+
+  err = snd_pcm_open(&handle, info->name.c_str(), stream, open_mode | SND_PCM_NONBLOCK);
+  if (err < 0) {
+    if ( err == EBUSY )
+      sprintf(message_, "RtApiAlsa: pcm capture device (%s) is busy: %s.",
+              info->name.c_str(), snd_strerror(err));
     else
-      sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name);
+      sprintf(message_, "RtApiAlsa: pcm capture open (%s) error: %s.",
+              info->name.c_str(), snd_strerror(err));
     error(RtError::DEBUG_WARNING);
     if (info->maxOutputChannels == 0)
       // didn't open for playback either ... device invalid
@@ -2598,829 +3385,976 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
     goto probe_parameters;
   }
 
-  // We have the device open for capture ... see how many channels it can handle
-  for (i=MAX_CHANNELS; i>0; i--) {
-    channels = i;
-    if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
-      continue; // as above
-    }
-    // If here, we found a working channel value
-    break;
+  // We have an open capture device ... allocate the parameter structure.
+  err = snd_pcm_hw_params_any(handle, params);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: hardware probe error (%s): %s.",
+            info->name.c_str(), snd_strerror(err));
+    error(RtError::WARNING);
+    if (info->maxOutputChannels > 0)
+      goto probe_parameters;
+    else
+      return;
   }
-  info->maxInputChannels = i;
 
-  // Now find the minimum number of channels it can handle
-  for (i=1; i<=info->maxInputChannels; i++) {
-    channels = i;
-    if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
-      continue; // try next channel number
-    // If here, we found the smallest working channel value
-    break;
+  // Get input channel information.
+  err = snd_pcm_hw_params_get_channels_min(params, &value);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: hardware minimum in channel probe error (%s): %s.",
+            info->name.c_str(), snd_strerror(err));
+    error(RtError::WARNING);
+    if (info->maxOutputChannels > 0)
+      goto probe_parameters;
+    else
+      return;
   }
-  info->minInputChannels = i;
-  close(fd);
+  info->minInputChannels = value;
 
-  if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
-    sprintf(message, "RtAudio: OSS device (%s) reports zero channels for input and output.",
-            info->name);
-    error(RtError::DEBUG_WARNING);
-    return;
+  err = snd_pcm_hw_params_get_channels_max(params, &value);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: hardware maximum in channel probe error (%s): %s.",
+            info->name.c_str(), snd_strerror(err));
+    error(RtError::WARNING);
+    if (info->maxOutputChannels > 0)
+      goto probe_parameters;
+    else
+      return;
   }
+  info->maxInputChannels = value;
+
+  snd_pcm_close(handle);
 
   // If device opens for both playback and capture, we determine the channels.
   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
     goto probe_parameters;
 
-  fd = open(info->name, O_RDWR | O_NONBLOCK);
-  if (fd == -1)
-    goto probe_parameters;
-
-  ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
-  ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
-  if (mask & DSP_CAP_DUPLEX) {
-    info->hasDuplexSupport = true;
-    // We have the device open for duplex ... see how many channels it can handle
-    for (i=MAX_CHANNELS; i>0; i--) {
-      channels = i;
-      if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
-        continue; // as above
-      // If here, we found a working channel value
-      break;
-    }
-    info->maxDuplexChannels = i;
-
-    // Now find the minimum number of channels it can handle
-    for (i=1; i<=info->maxDuplexChannels; i++) {
-      channels = i;
-      if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
-        continue; // try next channel number
-      // If here, we found the smallest working channel value
-      break;
-    }
-    info->minDuplexChannels = i;
-  }
-  close(fd);
+  info->hasDuplexSupport = true;
+  info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
+    info->maxInputChannels : info->maxOutputChannels;
+  info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
+    info->minInputChannels : info->minOutputChannels;
 
  probe_parameters:
-  // At this point, we need to figure out the supported data formats
-  // and sample rates.  We'll proceed by openning the device in the
-  // direction with the maximum number of channels, or playback if
+  // At this point, we just need to figure out the supported data
+  // formats and sample rates.  We'll proceed by opening the device in
+  // the direction with the maximum number of channels, or playback if
   // they are equal.  This might limit our sample rate options, but so
   // be it.
 
-  if (info->maxOutputChannels >= info->maxInputChannels) {
-    fd = open(info->name, O_WRONLY | O_NONBLOCK);
-    channels = info->maxOutputChannels;
-  }
-  else {
-    fd = open(info->name, O_RDONLY | O_NONBLOCK);
-    channels = info->maxInputChannels;
-  }
+  if (info->maxOutputChannels >= info->maxInputChannels)
+    stream = SND_PCM_STREAM_PLAYBACK;
+  else
+    stream = SND_PCM_STREAM_CAPTURE;
 
-  if (fd == -1) {
-    // We've got some sort of conflict ... abort
-    sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
-            info->name);
-    error(RtError::DEBUG_WARNING);
+  err = snd_pcm_open(&handle, info->name.c_str(), stream, open_mode);
+  if (err < 0) {
+    sprintf(message_, "RtApiAlsa: pcm (%s) won't reopen during probe: %s.",
+            info->name.c_str(), snd_strerror(err));
+    error(RtError::WARNING);
     return;
   }
 
-  // We have an open device ... set to maximum channels.
-  i = channels;
-  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
-    // We've got some sort of conflict ... abort
-    close(fd);
-    sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.",
-            info->name);
-    error(RtError::DEBUG_WARNING);
+  // We have an open device ... allocate the parameter structure.
+  err = snd_pcm_hw_params_any(handle, params);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: hardware reopen probe error (%s): %s.",
+            info->name.c_str(), snd_strerror(err));
+    error(RtError::WARNING);
     return;
   }
 
-  if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
-            info->name);
+  // Test our discrete set of sample rate values.
+  int dir = 0;
+  info->sampleRates.clear();
+  for (unsigned int i=0; i<MAX_SAMPLE_RATES; i++) {
+    if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0)
+      info->sampleRates.push_back(SAMPLE_RATES[i]);
+  }
+  if (info->sampleRates.size() == 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: no supported sample rates found for device (%s).",
+            info->name.c_str());
     error(RtError::DEBUG_WARNING);
     return;
   }
 
-  // Probe the supported data formats ... we don't care about endian-ness just yet.
-  int format;
+  // Probe the supported data formats ... we don't care about endian-ness just yet
+  snd_pcm_format_t format;
   info->nativeFormats = 0;
-#if defined (AFMT_S32_BE)
-  // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
-  if (mask & AFMT_S32_BE) {
-    format = AFMT_S32_BE;
-    info->nativeFormats |= RTAUDIO_SINT32;
-  }
-#endif
-#if defined (AFMT_S32_LE)
-  /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
-  if (mask & AFMT_S32_LE) {
-    format = AFMT_S32_LE;
-    info->nativeFormats |= RTAUDIO_SINT32;
-  }
-#endif
-  if (mask & AFMT_S8) {
-    format = AFMT_S8;
+  format = SND_PCM_FORMAT_S8;
+  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
     info->nativeFormats |= RTAUDIO_SINT8;
-  }
-  if (mask & AFMT_S16_BE) {
-    format = AFMT_S16_BE;
-    info->nativeFormats |= RTAUDIO_SINT16;
-  }
-  if (mask & AFMT_S16_LE) {
-    format = AFMT_S16_LE;
+  format = SND_PCM_FORMAT_S16;
+  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
     info->nativeFormats |= RTAUDIO_SINT16;
-  }
+  format = SND_PCM_FORMAT_S24;
+  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
+    info->nativeFormats |= RTAUDIO_SINT24;
+  format = SND_PCM_FORMAT_S32;
+  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
+    info->nativeFormats |= RTAUDIO_SINT32;
+  format = SND_PCM_FORMAT_FLOAT;
+  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
+    info->nativeFormats |= RTAUDIO_FLOAT32;
+  format = SND_PCM_FORMAT_FLOAT64;
+  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
+    info->nativeFormats |= RTAUDIO_FLOAT64;
 
   // Check that we have at least one supported format
   if (info->nativeFormats == 0) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
-            info->name);
-    error(RtError::DEBUG_WARNING);
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: pcm device (%s) data format not supported by RtAudio.",
+            info->name.c_str());
+    error(RtError::WARNING);
     return;
   }
 
-  // Set the format
-  i = format;
-  if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS device (%s) error setting data format.",
-            info->name);
-    error(RtError::DEBUG_WARNING);
-    return;
+  // That's all ... close the device and return
+  snd_pcm_close(handle);
+  info->probed = true;
+  return;
+}
+
+bool RtApiAlsa :: probeDeviceOpen( int device, StreamMode mode, int channels, 
+                                   int sampleRate, RtAudioFormat format,
+                                   int *bufferSize, int numberOfBuffers )
+{
+#if defined(__RTAUDIO_DEBUG__)
+  snd_output_t *out;
+  snd_output_stdio_attach(&out, stderr, 0);
+#endif
+
+  // I'm not using the "plug" interface ... too much inconsistent behavior.
+  const char *name = devices_[device].name.c_str();
+
+  snd_pcm_stream_t alsa_stream;
+  if (mode == OUTPUT)
+    alsa_stream = SND_PCM_STREAM_PLAYBACK;
+  else
+    alsa_stream = SND_PCM_STREAM_CAPTURE;
+
+  int err;
+  snd_pcm_t *handle;
+  int alsa_open_mode = SND_PCM_ASYNC;
+  err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
+  if (err < 0) {
+    sprintf(message_,"RtApiAlsa: pcm device (%s) won't open: %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
 
-  // Probe the supported sample rates ... first get lower limit
-  int speed = 1;
-  if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
-    // If we get here, we're probably using an ALSA driver with OSS-emulation,
-    // which doesn't conform to the OSS specification.  In this case,
-    // we'll probe our predefined list of sample rates for working values.
-    info->nSampleRates = 0;
-    for (i=0; i<MAX_SAMPLE_RATES; i++) {
-      speed = SAMPLE_RATES[i];
-      if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) {
-        info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
-        info->nSampleRates++;
-      }
-    }
-    if (info->nSampleRates == 0) {
-      close(fd);
-      return;
-    }
-    goto finished;
+  // Fill the parameter structure.
+  snd_pcm_hw_params_t *hw_params;
+  snd_pcm_hw_params_alloca(&hw_params);
+  err = snd_pcm_hw_params_any(handle, hw_params);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error getting parameter handle (%s): %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
-  info->sampleRates[0] = speed;
 
-  // Now get upper limit
-  speed = 1000000;
-  if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.",
-            info->name);
-    error(RtError::DEBUG_WARNING);
-    return;
+#if defined(__RTAUDIO_DEBUG__)
+  fprintf(stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n");
+  snd_pcm_hw_params_dump(hw_params, out);
+#endif
+
+  // Set access ... try interleaved access first, then non-interleaved
+  if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) ) {
+    err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+  }
+  else if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED) ) {
+               err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
+    stream_.deInterleave[mode] = true;
+  }
+  else {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: device (%s) access not supported by RtAudio.", name);
+    error(RtError::WARNING);
+    return FAILURE;
   }
-  info->sampleRates[1] = speed;
-  info->nSampleRates = -1;
 
- finished: // That's all ... close the device and return
-  close(fd);
-  info->probed = true;
-  return;
-}
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error setting access ( (%s): %s.", name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
+  }
 
-bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
-                                STREAM_MODE mode, int channels, 
-                                int sampleRate, RTAUDIO_FORMAT format,
-                                int *bufferSize, int numberOfBuffers)
-{
-  int buffers, buffer_bytes, device_channels, device_format;
-  int srate, temp, fd;
+  // Determine how to set the device format.
+  stream_.userFormat = format;
+  snd_pcm_format_t device_format = SND_PCM_FORMAT_UNKNOWN;
+
+  if (format == RTAUDIO_SINT8)
+    device_format = SND_PCM_FORMAT_S8;
+  else if (format == RTAUDIO_SINT16)
+    device_format = SND_PCM_FORMAT_S16;
+  else if (format == RTAUDIO_SINT24)
+    device_format = SND_PCM_FORMAT_S24;
+  else if (format == RTAUDIO_SINT32)
+    device_format = SND_PCM_FORMAT_S32;
+  else if (format == RTAUDIO_FLOAT32)
+    device_format = SND_PCM_FORMAT_FLOAT;
+  else if (format == RTAUDIO_FLOAT64)
+    device_format = SND_PCM_FORMAT_FLOAT64;
 
-  const char *name = devices[device].name;
+  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
+    stream_.deviceFormat[mode] = format;
+    goto set_format;
+  }
 
-  if (mode == OUTPUT)
-    fd = open(name, O_WRONLY | O_NONBLOCK);
-  else { // mode == INPUT
-    if (stream->mode == OUTPUT && stream->device[0] == device) {
-      // We just set the same device for playback ... close and reopen for duplex (OSS only).
-      close(stream->handle[0]);
-      stream->handle[0] = 0;
-      // First check that the number previously set channels is the same.
-      if (stream->nUserChannels[0] != channels) {
-        sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name);
-        goto error;
-      }
-      fd = open(name, O_RDWR | O_NONBLOCK);
-    }
-    else
-      fd = open(name, O_RDONLY | O_NONBLOCK);
+  // The user requested format is not natively supported by the device.
+  device_format = SND_PCM_FORMAT_FLOAT64;
+  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
+    goto set_format;
+  }
+
+  device_format = SND_PCM_FORMAT_FLOAT;
+  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
+    goto set_format;
+  }
+
+  device_format = SND_PCM_FORMAT_S32;
+  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
+    stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+    goto set_format;
   }
 
-  if (fd == -1) {
-    if (errno == EBUSY || errno == EAGAIN)
-      sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.",
-              name);
-    else
-      sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
-    goto error;
+  device_format = SND_PCM_FORMAT_S24;
+  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
+    stream_.deviceFormat[mode] = RTAUDIO_SINT24;
+    goto set_format;
   }
 
-  // Now reopen in blocking mode.
-  close(fd);
-  if (mode == OUTPUT)
-    fd = open(name, O_WRONLY | O_SYNC);
-  else { // mode == INPUT
-    if (stream->mode == OUTPUT && stream->device[0] == device)
-      fd = open(name, O_RDWR | O_SYNC);
-    else
-      fd = open(name, O_RDONLY | O_SYNC);
+  device_format = SND_PCM_FORMAT_S16;
+  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
+    stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+    goto set_format;
   }
 
-  if (fd == -1) {
-    sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
-    goto error;
+  device_format = SND_PCM_FORMAT_S8;
+  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
+    stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+    goto set_format;
   }
 
-  // Get the sample format mask
-  int mask;
-  if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
-            name);
-    goto error;
+  // If we get here, no supported format was found.
+  sprintf(message_,"RtApiAlsa: pcm device (%s) data format not supported by RtAudio.", name);
+  snd_pcm_close(handle);
+  error(RtError::WARNING);
+  return FAILURE;
+
+ set_format:
+  err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error setting format (%s): %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
 
-  // Determine how to set the device format.
-  stream->userFormat = format;
-  device_format = -1;
-  stream->doByteSwap[mode] = false;
-  if (format == RTAUDIO_SINT8) {
-    if (mask & AFMT_S8) {
-      device_format = AFMT_S8;
-      stream->deviceFormat[mode] = RTAUDIO_SINT8;
+  // Determine whether byte-swaping is necessary.
+  stream_.doByteSwap[mode] = false;
+  if (device_format != SND_PCM_FORMAT_S8) {
+    err = snd_pcm_format_cpu_endian(device_format);
+    if (err == 0)
+      stream_.doByteSwap[mode] = true;
+    else if (err < 0) {
+      snd_pcm_close(handle);
+      sprintf(message_, "RtApiAlsa: error getting format endian-ness (%s): %s.",
+              name, snd_strerror(err));
+      error(RtError::WARNING);
+      return FAILURE;
     }
   }
-  else if (format == RTAUDIO_SINT16) {
-    if (mask & AFMT_S16_NE) {
-      device_format = AFMT_S16_NE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT16;
-    }
-#if BYTE_ORDER == LITTLE_ENDIAN
-    else if (mask & AFMT_S16_BE) {
-      device_format = AFMT_S16_BE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT16;
-      stream->doByteSwap[mode] = true;
-    }
-#else
-    else if (mask & AFMT_S16_LE) {
-      device_format = AFMT_S16_LE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT16;
-      stream->doByteSwap[mode] = true;
-    }
-#endif
+
+  // Set the sample rate.
+  err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error setting sample rate (%d) on device (%s): %s.",
+            sampleRate, name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
-#if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
-  else if (format == RTAUDIO_SINT32) {
-    if (mask & AFMT_S32_NE) {
-      device_format = AFMT_S32_NE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT32;
-    }
-#if BYTE_ORDER == LITTLE_ENDIAN
-    else if (mask & AFMT_S32_BE) {
-      device_format = AFMT_S32_BE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT32;
-      stream->doByteSwap[mode] = true;
-    }
-#else
-    else if (mask & AFMT_S32_LE) {
-      device_format = AFMT_S32_LE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT32;
-      stream->doByteSwap[mode] = true;
-    }
-#endif
+
+  // Determine the number of channels for this device.  We support a possible
+  // minimum device channel number > than the value requested by the user.
+  stream_.nUserChannels[mode] = channels;
+  unsigned int value;
+  err = snd_pcm_hw_params_get_channels_max(hw_params, &value);
+  int device_channels = value;
+  if (err < 0 || device_channels < channels) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: channels (%d) not supported by device (%s).",
+            channels, name);
+    error(RtError::WARNING);
+    return FAILURE;
   }
-#endif
 
-  if (device_format == -1) {
-    // The user requested format is not natively supported by the device.
-    if (mask & AFMT_S16_NE) {
-      device_format = AFMT_S16_NE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT16;
-    }
-#if BYTE_ORDER == LITTLE_ENDIAN
-    else if (mask & AFMT_S16_BE) {
-      device_format = AFMT_S16_BE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT16;
-      stream->doByteSwap[mode] = true;
-    }
-#else
-    else if (mask & AFMT_S16_LE) {
-      device_format = AFMT_S16_LE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT16;
-      stream->doByteSwap[mode] = true;
-    }
-#endif
-#if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
-    else if (mask & AFMT_S32_NE) {
-      device_format = AFMT_S32_NE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT32;
-    }
-#if BYTE_ORDER == LITTLE_ENDIAN
-    else if (mask & AFMT_S32_BE) {
-      device_format = AFMT_S32_BE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT32;
-      stream->doByteSwap[mode] = true;
-    }
-#else
-    else if (mask & AFMT_S32_LE) {
-      device_format = AFMT_S32_LE;
-      stream->deviceFormat[mode] = RTAUDIO_SINT32;
-      stream->doByteSwap[mode] = true;
-    }
-#endif
-#endif
-    else if (mask & AFMT_S8) {
-      device_format = AFMT_S8;
-      stream->deviceFormat[mode] = RTAUDIO_SINT8;
-    }
+  err = snd_pcm_hw_params_get_channels_min(hw_params, &value);
+  if (err < 0 ) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error getting min channels count on device (%s).", name);
+    error(RtError::WARNING);
+    return FAILURE;
   }
+  device_channels = value;
+  if (device_channels < channels) device_channels = channels;
+  stream_.nDeviceChannels[mode] = device_channels;
 
-  if (stream->deviceFormat[mode] == 0) {
-    // This really shouldn't happen ...
-    close(fd);
-    sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
-            name);
-    goto error;
+  // Set the device channels.
+  err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error setting channels (%d) on device (%s): %s.",
+            device_channels, name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
 
-  // Determine the number of channels for this device.  Note that the
-  // channel value requested by the user might be < min_X_Channels.
-  stream->nUserChannels[mode] = channels;
-  device_channels = channels;
-  if (mode == OUTPUT) {
-    if (channels < devices[device].minOutputChannels)
-      device_channels = devices[device].minOutputChannels;
+  // Set the buffer number, which in ALSA is referred to as the "period".
+  int dir;
+  unsigned int periods = numberOfBuffers;
+  // Even though the hardware might allow 1 buffer, it won't work reliably.
+  if (periods < 2) periods = 2;
+  err = snd_pcm_hw_params_get_periods_min(hw_params, &value, &dir);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error getting min periods on device (%s): %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
-  else { // mode == INPUT
-    if (stream->mode == OUTPUT && stream->device[0] == device) {
-      // We're doing duplex setup here.
-      if (channels < devices[device].minDuplexChannels)
-        device_channels = devices[device].minDuplexChannels;
-    }
-    else {
-      if (channels < devices[device].minInputChannels)
-        device_channels = devices[device].minInputChannels;
-    }
+  if (value > periods) periods = value;
+  err = snd_pcm_hw_params_get_periods_max(hw_params, &value, &dir);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error getting max periods on device (%s): %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
-  stream->nDeviceChannels[mode] = device_channels;
+  if (value < periods) periods = value;
 
-  // Attempt to set the buffer size.  According to OSS, the minimum
-  // number of buffers is two.  The supposed minimum buffer size is 16
-  // bytes, so that will be our lower bound.  The argument to this
-  // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
-  // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
-  // We'll check the actual value used near the end of the setup
-  // procedure.
-  buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels;
-  if (buffer_bytes < 16) buffer_bytes = 16;
-  buffers = numberOfBuffers;
-  if (buffers < 2) buffers = 2;
-  temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
-  if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).",
-            name);
-    goto error;
+  err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error setting periods (%s): %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
-  stream->nBuffers = buffers;
 
-  // Set the data format.
-  temp = device_format;
-  if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS error setting data format for device (%s).",
-            name);
-    goto error;
+  // Set the buffer (or period) size.
+  snd_pcm_uframes_t period_size;
+  err = snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, &dir);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error getting period size (%s): %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
+  if (*bufferSize < (int) period_size) *bufferSize = (int) period_size;
 
-  // Set the number of channels.
-  temp = device_channels;
-  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).",
-            temp, name);
-    goto error;
+  err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error setting period size (%s): %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
 
-  // Set the sample rate.
-  srate = sampleRate;
-  temp = srate;
-  if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).",
-            temp, name);
-    goto error;
+  // If attempting to setup a duplex stream, the bufferSize parameter
+  // MUST be the same in both directions!
+  if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
+    sprintf( message_, "RtApiAlsa: error setting buffer size for duplex stream on device (%s).",
+             name );
+    error(RtError::DEBUG_WARNING);
+    return FAILURE;
   }
 
-  // Verify the sample rate setup worked.
-  if (abs(srate - temp) > 100) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.",
-            name, temp);
-    goto error;
-  }
-  stream->sampleRate = sampleRate;
+  stream_.bufferSize = *bufferSize;
 
-  if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
-    close(fd);
-    sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).",
-            name);
-    goto error;
+  // Install the hardware configuration
+  err = snd_pcm_hw_params(handle, hw_params);
+  if (err < 0) {
+    snd_pcm_close(handle);
+    sprintf(message_, "RtApiAlsa: error installing hardware configuration (%s): %s.",
+            name, snd_strerror(err));
+    error(RtError::WARNING);
+    return FAILURE;
   }
 
-  // Save buffer size (in sample frames).
-  *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels);
-  stream->bufferSize = *bufferSize;
+#if defined(__RTAUDIO_DEBUG__)
+  fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n");
+  snd_pcm_hw_params_dump(hw_params, out);
+#endif
 
-  if (mode == INPUT && stream->mode == OUTPUT &&
-      stream->device[0] == device) {
-    // We're doing duplex setup here.
-    stream->deviceFormat[0] = stream->deviceFormat[1];
-    stream->nDeviceChannels[0] = device_channels;
+  // Allocate the stream handle if necessary and then save.
+  snd_pcm_t **handles;
+  if ( stream_.apiHandle == 0 ) {
+    handles = (snd_pcm_t **) calloc(2, sizeof(snd_pcm_t *));
+    if ( handle == NULL ) {
+      sprintf(message_, "RtApiAlsa: error allocating handle memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
+    stream_.apiHandle = (void *) handles;
+    handles[0] = 0;
+    handles[1] = 0;
+  }
+  else {
+    handles = (snd_pcm_t **) stream_.apiHandle;
   }
+  handles[mode] = handle;
 
   // Set flags for buffer conversion
-  stream->doConvertBuffer[mode] = false;
-  if (stream->userFormat != stream->deviceFormat[mode])
-    stream->doConvertBuffer[mode] = true;
-  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
-    stream->doConvertBuffer[mode] = true;
+  stream_.doConvertBuffer[mode] = false;
+  if (stream_.userFormat != stream_.deviceFormat[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.nUserChannels[mode] > 1 && stream_.deInterleave[mode])
+    stream_.doConvertBuffer[mode] = true;
 
   // Allocate necessary internal buffers
-  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
+  if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
 
     long buffer_bytes;
-    if (stream->nUserChannels[0] >= stream->nUserChannels[1])
-      buffer_bytes = stream->nUserChannels[0];
+    if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
+      buffer_bytes = stream_.nUserChannels[0];
     else
-      buffer_bytes = stream->nUserChannels[1];
-
-    buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
-    if (stream->userBuffer) free(stream->userBuffer);
-    stream->userBuffer = (char *) calloc(buffer_bytes, 1);
-    if (stream->userBuffer == NULL) {
-      close(fd);
-      sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).",
-              name);
+      buffer_bytes = stream_.nUserChannels[1];
+
+    buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
+    if (stream_.userBuffer) free(stream_.userBuffer);
+    stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
+    if (stream_.userBuffer == NULL) {
+      sprintf(message_, "RtApiAlsa: error allocating user buffer memory (%s).",
+              devices_[device].name.c_str());
       goto error;
     }
   }
 
-  if ( stream->doConvertBuffer[mode] ) {
+  if ( stream_.doConvertBuffer[mode] ) {
 
     long buffer_bytes;
     bool makeBuffer = true;
     if ( mode == OUTPUT )
-      buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
     else { // mode == INPUT
-      buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
-      if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
-        long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+        long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
         if ( buffer_bytes < bytes_out ) makeBuffer = false;
       }
     }
 
     if ( makeBuffer ) {
       buffer_bytes *= *bufferSize;
-      if (stream->deviceBuffer) free(stream->deviceBuffer);
-      stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
-      if (stream->deviceBuffer == NULL) {
-        close(fd);
-        free(stream->userBuffer);
-        sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).",
-                name);
+      if (stream_.deviceBuffer) free(stream_.deviceBuffer);
+      stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
+      if (stream_.deviceBuffer == NULL) {
+        sprintf(message_, "RtApiAlsa: error allocating device buffer memory (%s).",
+                devices_[device].name.c_str());
         goto error;
       }
     }
   }
 
-  stream->device[mode] = device;
-  stream->handle[mode] = fd;
-  stream->state = STREAM_STOPPED;
-  if ( stream->mode == OUTPUT && mode == INPUT ) {
-    stream->mode = DUPLEX;
-    if (stream->device[0] == device)
-      stream->handle[0] = fd;
-  }
+  stream_.device[mode] = device;
+  stream_.state = STREAM_STOPPED;
+  if ( stream_.mode == OUTPUT && mode == INPUT )
+    // We had already set up an output stream.
+    stream_.mode = DUPLEX;
   else
-    stream->mode = mode;
+    stream_.mode = mode;
+  stream_.nBuffers = periods;
+  stream_.sampleRate = sampleRate;
 
   return SUCCESS;
 
  error:
-  if (stream->handle[0]) {
-    close(stream->handle[0]);
-    stream->handle[0] = 0;
+  if (handles) {
+    if (handles[0])
+      snd_pcm_close(handles[0]);
+    if (handles[1])
+      snd_pcm_close(handles[1]);
+    free(handles);
+    stream_.apiHandle = 0;
+  }
+
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
   }
+
   error(RtError::WARNING);
   return FAILURE;
 }
 
-void RtAudio :: closeStream(int streamId)
+void RtApiAlsa :: closeStream()
 {
   // We don't want an exception to be thrown here because this
   // function is called by our class destructor.  So, do our own
-  // streamId check.
-  if ( streams.find( streamId ) == streams.end() ) {
-    sprintf(message, "RtAudio: invalid stream identifier!");
+  // stream check.
+  if ( stream_.mode == UNINITIALIZED ) {
+    sprintf(message_, "RtApiAlsa::closeStream(): no open stream to close!");
     error(RtError::WARNING);
     return;
   }
 
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
-
-  if (stream->callbackInfo.usingCallback) {
-    pthread_cancel(stream->callbackInfo.thread);
-    pthread_join(stream->callbackInfo.thread, NULL);
+  snd_pcm_t **handle = (snd_pcm_t **) stream_.apiHandle;
+  if (stream_.state == STREAM_RUNNING) {
+    if (stream_.mode == OUTPUT || stream_.mode == DUPLEX)
+      snd_pcm_drop(handle[0]);
+    if (stream_.mode == INPUT || stream_.mode == DUPLEX)
+      snd_pcm_drop(handle[1]);
+    stream_.state = STREAM_STOPPED;
   }
 
-  if (stream->state == STREAM_RUNNING) {
-    if (stream->mode == OUTPUT || stream->mode == DUPLEX)
-      ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
-    if (stream->mode == INPUT || stream->mode == DUPLEX)
-      ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
+  if (stream_.callbackInfo.usingCallback) {
+    stream_.callbackInfo.usingCallback = false;
+    pthread_join(stream_.callbackInfo.thread, NULL);
   }
 
-  pthread_mutex_destroy(&stream->mutex);
-
-  if (stream->handle[0])
-    close(stream->handle[0]);
-
-  if (stream->handle[1])
-    close(stream->handle[1]);
+  if (handle) {
+    if (handle[0]) snd_pcm_close(handle[0]);
+    if (handle[1]) snd_pcm_close(handle[1]);
+    free(handle);
+    handle = 0;
+  }
 
-  if (stream->userBuffer)
-    free(stream->userBuffer);
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
+  }
 
-  if (stream->deviceBuffer)
-    free(stream->deviceBuffer);
+  if (stream_.deviceBuffer) {
+    free(stream_.deviceBuffer);
+    stream_.deviceBuffer = 0;
+  }
 
-  free(stream);
-  streams.erase(streamId);
+  stream_.mode = UNINITIALIZED;
 }
 
-void RtAudio :: startStream(int streamId)
+void RtApiAlsa :: startStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  // This method calls snd_pcm_prepare if the device isn't already in that state.
 
-  MUTEX_LOCK(&stream->mutex);
+  verifyStream();
+  if (stream_.state == STREAM_RUNNING) return;
 
-  stream->state = STREAM_RUNNING;
+  MUTEX_LOCK(&stream_.mutex);
 
-  // No need to do anything else here ... OSS automatically starts
-  // when fed samples.
+  int err;
+  snd_pcm_state_t state;
+  snd_pcm_t **handle = (snd_pcm_t **) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    state = snd_pcm_state(handle[0]);
+    if (state != SND_PCM_STATE_PREPARED) {
+      err = snd_pcm_prepare(handle[0]);
+      if (err < 0) {
+        sprintf(message_, "RtApiAlsa: error preparing pcm device (%s): %s.",
+                devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
+        MUTEX_UNLOCK(&stream_.mutex);
+        error(RtError::DRIVER_ERROR);
+      }
+    }
+  }
+
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    state = snd_pcm_state(handle[1]);
+    if (state != SND_PCM_STATE_PREPARED) {
+      err = snd_pcm_prepare(handle[1]);
+      if (err < 0) {
+        sprintf(message_, "RtApiAlsa: error preparing pcm device (%s): %s.",
+                devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
+        MUTEX_UNLOCK(&stream_.mutex);
+        error(RtError::DRIVER_ERROR);
+      }
+    }
+  }
+  stream_.state = STREAM_RUNNING;
 
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: stopStream(int streamId)
+void RtApiAlsa :: stopStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-  MUTEX_LOCK(&stream->mutex);
-
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
   int err;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0);
-    if (err < -1) {
-      sprintf(message, "RtAudio: OSS error stopping device (%s).",
-              devices[stream->device[0]].name);
+  snd_pcm_t **handle = (snd_pcm_t **) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    err = snd_pcm_drain(handle[0]);
+    if (err < 0) {
+      sprintf(message_, "RtApiAlsa: error draining pcm device (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
+      MUTEX_UNLOCK(&stream_.mutex);
       error(RtError::DRIVER_ERROR);
     }
   }
-  else {
-    err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0);
-    if (err < -1) {
-      sprintf(message, "RtAudio: OSS error stopping device (%s).",
-              devices[stream->device[1]].name);
+
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    err = snd_pcm_drain(handle[1]);
+    if (err < 0) {
+      sprintf(message_, "RtApiAlsa: error draining pcm device (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
+      MUTEX_UNLOCK(&stream_.mutex);
       error(RtError::DRIVER_ERROR);
     }
   }
-  stream->state = STREAM_STOPPED;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: abortStream(int streamId)
+void RtApiAlsa :: abortStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
   int err;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
-    if (err < -1) {
-      sprintf(message, "RtAudio: OSS error aborting device (%s).",
-              devices[stream->device[0]].name);
+  snd_pcm_t **handle = (snd_pcm_t **) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    err = snd_pcm_drop(handle[0]);
+    if (err < 0) {
+      sprintf(message_, "RtApiAlsa: error draining pcm device (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
+      MUTEX_UNLOCK(&stream_.mutex);
       error(RtError::DRIVER_ERROR);
     }
   }
-  else {
-    err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
-    if (err < -1) {
-      sprintf(message, "RtAudio: OSS error aborting device (%s).",
-              devices[stream->device[1]].name);
+
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    err = snd_pcm_drop(handle[1]);
+    if (err < 0) {
+      sprintf(message_, "RtApiAlsa: error draining pcm device (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
+      MUTEX_UNLOCK(&stream_.mutex);
       error(RtError::DRIVER_ERROR);
     }
   }
-  stream->state = STREAM_STOPPED;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-int RtAudio :: streamWillBlock(int streamId)
+int RtApiAlsa :: streamWillBlock()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return 0;
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
-  int bytes = 0, channels = 0, frames = 0;
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
-
-  audio_buf_info info;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info);
-    bytes = info.bytes;
-    channels = stream->nDeviceChannels[0];
+  int err = 0, frames = 0;
+  snd_pcm_t **handle = (snd_pcm_t **) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    err = snd_pcm_avail_update(handle[0]);
+    if (err < 0) {
+      sprintf(message_, "RtApiAlsa: error getting available frames for device (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
+      MUTEX_UNLOCK(&stream_.mutex);
+      error(RtError::DRIVER_ERROR);
+    }
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info);
-    if (stream->mode == DUPLEX ) {
-      bytes = (bytes < info.bytes) ? bytes : info.bytes;
-      channels = stream->nDeviceChannels[0];
-    }
-    else {
-      bytes = info.bytes;
-      channels = stream->nDeviceChannels[1];
+  frames = err;
+
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    err = snd_pcm_avail_update(handle[1]);
+    if (err < 0) {
+      sprintf(message_, "RtApiAlsa: error getting available frames for device (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
+      MUTEX_UNLOCK(&stream_.mutex);
+      error(RtError::DRIVER_ERROR);
     }
+    if (frames > err) frames = err;
   }
 
-  frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0])));
-  frames -= stream->bufferSize;
+  frames = stream_.bufferSize - frames;
   if (frames < 0) frames = 0;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
   return frames;
 }
 
-void RtAudio :: tickStream(int streamId)
+void RtApiAlsa :: tickStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
 
   int stopStream = 0;
-  if (stream->state == STREAM_STOPPED) {
-    if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
+  if (stream_.state == STREAM_STOPPED) {
+    if (stream_.callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
     return;
   }
-  else if (stream->callbackInfo.usingCallback) {
-    RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
-    stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
+  else if (stream_.callbackInfo.usingCallback) {
+    RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
+    stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData);
   }
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
   // The state might change while waiting on a mutex.
-  if (stream->state == STREAM_STOPPED)
+  if (stream_.state == STREAM_STOPPED)
     goto unlock;
 
-  int result;
+  int err;
   char *buffer;
-  int samples;
-  RTAUDIO_FORMAT format;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
+  int channels;
+  snd_pcm_t **handle;
+  RtAudioFormat format;
+  handle = (snd_pcm_t **) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
 
     // Setup parameters and do buffer conversion if necessary.
-    if (stream->doConvertBuffer[0]) {
-      convertStreamBuffer(stream, OUTPUT);
-      buffer = stream->deviceBuffer;
-      samples = stream->bufferSize * stream->nDeviceChannels[0];
-      format = stream->deviceFormat[0];
+    if (stream_.doConvertBuffer[0]) {
+      convertStreamBuffer(OUTPUT);
+      buffer = stream_.deviceBuffer;
+      channels = stream_.nDeviceChannels[0];
+      format = stream_.deviceFormat[0];
     }
     else {
-      buffer = stream->userBuffer;
-      samples = stream->bufferSize * stream->nUserChannels[0];
-      format = stream->userFormat;
+      buffer = stream_.userBuffer;
+      channels = stream_.nUserChannels[0];
+      format = stream_.userFormat;
     }
 
     // Do byte swapping if necessary.
-    if (stream->doByteSwap[0])
-      byteSwapBuffer(buffer, samples, format);
+    if (stream_.doByteSwap[0])
+      byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
 
-    // Write samples to device.
-    result = write(stream->handle[0], buffer, samples * formatBytes(format));
+    // Write samples to device in interleaved/non-interleaved format.
+    if (stream_.deInterleave[0]) {
+      void *bufs[channels];
+      size_t offset = stream_.bufferSize * formatBytes(format);
+      for (int i=0; i<channels; i++)
+        bufs[i] = (void *) (buffer + (i * offset));
+      err = snd_pcm_writen(handle[0], bufs, stream_.bufferSize);
+    }
+    else
+      err = snd_pcm_writei(handle[0], buffer, stream_.bufferSize);
 
-    if (result == -1) {
-      // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
-      sprintf(message, "RtAudio: OSS audio write error for device (%s).",
-              devices[stream->device[0]].name);
-      error(RtError::DRIVER_ERROR);
+    if (err < stream_.bufferSize) {
+      // Either an error or underrun occured.
+      if (err == -EPIPE) {
+        snd_pcm_state_t state = snd_pcm_state(handle[0]);
+        if (state == SND_PCM_STATE_XRUN) {
+          sprintf(message_, "RtApiAlsa: underrun detected.");
+          error(RtError::WARNING);
+          err = snd_pcm_prepare(handle[0]);
+          if (err < 0) {
+            sprintf(message_, "RtApiAlsa: error preparing handle after underrun: %s.",
+                    snd_strerror(err));
+            MUTEX_UNLOCK(&stream_.mutex);
+            error(RtError::DRIVER_ERROR);
+          }
+        }
+        else {
+          sprintf(message_, "RtApiAlsa: tickStream() error, current state is %s.",
+                  snd_pcm_state_name(state));
+          MUTEX_UNLOCK(&stream_.mutex);
+          error(RtError::DRIVER_ERROR);
+        }
+        goto unlock;
+      }
+      else {
+        sprintf(message_, "RtApiAlsa: audio write error for device (%s): %s.",
+                devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
+        MUTEX_UNLOCK(&stream_.mutex);
+        error(RtError::DRIVER_ERROR);
+      }
     }
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
 
     // Setup parameters.
-    if (stream->doConvertBuffer[1]) {
-      buffer = stream->deviceBuffer;
-      samples = stream->bufferSize * stream->nDeviceChannels[1];
-      format = stream->deviceFormat[1];
+    if (stream_.doConvertBuffer[1]) {
+      buffer = stream_.deviceBuffer;
+      channels = stream_.nDeviceChannels[1];
+      format = stream_.deviceFormat[1];
     }
     else {
-      buffer = stream->userBuffer;
-      samples = stream->bufferSize * stream->nUserChannels[1];
-      format = stream->userFormat;
+      buffer = stream_.userBuffer;
+      channels = stream_.nUserChannels[1];
+      format = stream_.userFormat;
     }
 
-    // Read samples from device.
-    result = read(stream->handle[1], buffer, samples * formatBytes(format));
+    // Read samples from device in interleaved/non-interleaved format.
+    if (stream_.deInterleave[1]) {
+      void *bufs[channels];
+      size_t offset = stream_.bufferSize * formatBytes(format);
+      for (int i=0; i<channels; i++)
+        bufs[i] = (void *) (buffer + (i * offset));
+      err = snd_pcm_readn(handle[1], bufs, stream_.bufferSize);
+    }
+    else
+      err = snd_pcm_readi(handle[1], buffer, stream_.bufferSize);
 
-    if (result == -1) {
-      // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
-      sprintf(message, "RtAudio: OSS audio read error for device (%s).",
-              devices[stream->device[1]].name);
-      error(RtError::DRIVER_ERROR);
+    if (err < stream_.bufferSize) {
+      // Either an error or underrun occured.
+      if (err == -EPIPE) {
+        snd_pcm_state_t state = snd_pcm_state(handle[1]);
+        if (state == SND_PCM_STATE_XRUN) {
+          sprintf(message_, "RtApiAlsa: overrun detected.");
+          error(RtError::WARNING);
+          err = snd_pcm_prepare(handle[1]);
+          if (err < 0) {
+            sprintf(message_, "RtApiAlsa: error preparing handle after overrun: %s.",
+                    snd_strerror(err));
+            MUTEX_UNLOCK(&stream_.mutex);
+            error(RtError::DRIVER_ERROR);
+          }
+        }
+        else {
+          sprintf(message_, "RtApiAlsa: tickStream() error, current state is %s.",
+                  snd_pcm_state_name(state));
+          MUTEX_UNLOCK(&stream_.mutex);
+          error(RtError::DRIVER_ERROR);
+        }
+        goto unlock;
+      }
+      else {
+        sprintf(message_, "RtApiAlsa: audio read error for device (%s): %s.",
+                devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
+        MUTEX_UNLOCK(&stream_.mutex);
+        error(RtError::DRIVER_ERROR);
+      }
     }
 
     // Do byte swapping if necessary.
-    if (stream->doByteSwap[1])
-      byteSwapBuffer(buffer, samples, format);
+    if (stream_.doByteSwap[1])
+      byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
 
     // Do buffer conversion if necessary.
-    if (stream->doConvertBuffer[1])
-      convertStreamBuffer(stream, INPUT);
+    if (stream_.doConvertBuffer[1])
+      convertStreamBuffer(INPUT);
   }
 
  unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 
-  if (stream->callbackInfo.usingCallback && stopStream)
-    this->stopStream(streamId);
+  if (stream_.callbackInfo.usingCallback && stopStream)
+    this->stopStream();
 }
 
-extern "C" void *callbackHandler(void *ptr)
+void RtApiAlsa :: setStreamCallback(RtAudioCallback callback, void *userData)
+{
+  verifyStream();
+
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+  if ( info->usingCallback ) {
+    sprintf(message_, "RtApiAlsa: A callback is already set for this stream!");
+    error(RtError::WARNING);
+    return;
+  }
+
+  info->callback = (void *) callback;
+  info->userData = userData;
+  info->usingCallback = true;
+  info->object = (void *) this;
+
+  // Set the thread attributes for joinable and realtime scheduling
+  // priority.  The higher priority will only take affect if the
+  // program is run as root or suid.
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+  pthread_attr_setschedpolicy(&attr, SCHED_RR);
+
+  int err = pthread_create(&info->thread, &attr, alsaCallbackHandler, &stream_.callbackInfo);
+  pthread_attr_destroy(&attr);
+  if (err) {
+    info->usingCallback = false;
+    sprintf(message_, "RtApiAlsa: error starting callback thread!");
+    error(RtError::THREAD_ERROR);
+  }
+}
+
+void RtApiAlsa :: cancelStreamCallback()
+{
+  verifyStream();
+
+  if (stream_.callbackInfo.usingCallback) {
+
+    if (stream_.state == STREAM_RUNNING)
+      stopStream();
+
+    MUTEX_LOCK(&stream_.mutex);
+
+    stream_.callbackInfo.usingCallback = false;
+    pthread_join(stream_.callbackInfo.thread, NULL);
+    stream_.callbackInfo.thread = 0;
+    stream_.callbackInfo.callback = NULL;
+    stream_.callbackInfo.userData = NULL;
+
+    MUTEX_UNLOCK(&stream_.mutex);
+  }
+}
+
+extern "C" void *alsaCallbackHandler(void *ptr)
 {
-  CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
-  RtAudio *object = (RtAudio *) info->object;
-  int stream = info->streamId;
+  CallbackInfo *info = (CallbackInfo *) ptr;
+  RtApiAlsa *object = (RtApiAlsa *) info->object;
   bool *usingCallback = &info->usingCallback;
 
   while ( *usingCallback ) {
-    pthread_testcancel();
     try {
-      object->tickStream(stream);
+      object->tickStream();
     }
     catch (RtError &exception) {
-      fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
-              exception.getMessage());
+      fprintf(stderr, "\nRtApiAlsa: callback thread error (%s) ... closing thread.\n\n",
+              exception.getMessageString());
       break;
     }
   }
 
-  return 0;
+  pthread_exit(NULL);
 }
 
+//******************** End of __LINUX_ALSA__ *********************//
+#endif
 
-//******************** End of __LINUX_OSS__ *********************//
-
-#elif defined(__WINDOWS_ASIO__) // ASIO API on Windows
+#if defined(__WINDOWS_ASIO__) // ASIO API on Windows
 
 // The ASIO API is designed around a callback scheme, so this
-// implementation is similar to that used for OS X CoreAudio.  The
-// primary constraint with ASIO is that it only allows access to a
-// single driver at a time.  Thus, it is not possible to have more
-// than one simultaneous RtAudio stream.
+// implementation is similar to that used for OS-X CoreAudio and Linux
+// Jack.  The primary constraint with ASIO is that it only allows
+// access to a single driver at a time.  Thus, it is not possible to
+// have more than one simultaneous RtAudio stream.
 //
 // This implementation also requires a number of external ASIO files
 // and a few global variables.  The ASIO callback scheme does not
 // allow for the passing of user data, so we must create a global
 // pointer to our callbackInfo structure.
+//
+// On unix systems, we make use of a pthread condition variable.
+// Since there is no equivalent in Windows, I hacked something based
+// on information found in
+// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
 
 #include "asio/asiosys.h"
 #include "asio/asio.h"
@@ -3429,60 +4363,72 @@ extern "C" void *callbackHandler(void *ptr)
 
 AsioDrivers drivers;
 ASIOCallbacks asioCallbacks;
-CALLBACK_INFO *asioCallbackInfo;
 ASIODriverInfo driverInfo;
+CallbackInfo *asioCallbackInfo;
+
+struct AsioHandle {
+  bool stopStream;
+  ASIOBufferInfo *bufferInfos;
+  HANDLE condition;
+
+  AsioHandle()
+    :stopStream(false), bufferInfos(0) {}
+};
 
-void RtAudio :: initialize(void)
+RtApiAsio :: RtApiAsio()
 {
-  nDevices = drivers.asioGetNumDev();
-  if (nDevices <= 0) return;
+  this->initialize();
 
-  //  Allocate the RTAUDIO_DEVICE structures.
-  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
-  if (devices == NULL) {
-    sprintf(message, "RtAudio: memory allocation error!");
-    error(RtError::MEMORY_ERROR);
+  if (nDevices_ <= 0) {
+    sprintf(message_, "RtApiAsio: no Windows ASIO audio drivers found!");
+    error(RtError::NO_DEVICES_FOUND);
   }
+}
 
-  // Write device driver names to device structures and then probe the
-  // device capabilities.
-  for (int i=0; i<nDevices; i++) {
-    if ( drivers.asioGetDriverName( i, devices[i].name, 128 ) == 0 )
-      //probeDeviceInfo(&devices[i]);
-      ;
+RtApiAsio :: ~RtApiAsio()
+{
+  if ( stream_.mode != UNINITIALIZED ) closeStream();
+}
+
+void RtApiAsio :: initialize(void)
+{
+  nDevices_ = drivers.asioGetNumDev();
+  if (nDevices_ <= 0) return;
+
+  // Create device structures and write device driver names to each.
+  RtApiDevice device;
+  char name[128];
+  for (int i=0; i<nDevices_; i++) {
+    if ( drivers.asioGetDriverName( i, name, 128 ) == 0 ) {
+      device.name.erase();
+      device.name.append( (const char *)name, strlen(name)+1);
+      devices_.push_back(device);
+    }
     else {
-      sprintf(message, "RtAudio: error getting ASIO driver name for device index %d!", i);
+      sprintf(message_, "RtApiAsio: error getting driver name for device index %d!", i);
       error(RtError::WARNING);
     }
   }
 
+  nDevices_ = (int) devices_.size();
+
   drivers.removeCurrentDriver();
   driverInfo.asioVersion = 2;
   // See note in DirectSound implementation about GetDesktopWindow().
   driverInfo.sysRef = GetForegroundWindow();
 }
 
-int RtAudio :: getDefaultInputDevice(void)
-{
-  return 0;
-}
-
-int RtAudio :: getDefaultOutputDevice(void)
-{
-  return 0;
-}
-
-void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
+void RtApiAsio :: probeDeviceInfo(RtApiDevice *info)
 {
   // Don't probe if a stream is already open.
-  if ( streams.size() > 0 ) {
-    sprintf(message, "RtAudio: unable to probe ASIO driver while a stream is open.");
+  if ( stream_.mode != UNINITIALIZED ) {
+    sprintf(message_, "RtApiAsio: unable to probe driver while a stream is open.");
     error(RtError::DEBUG_WARNING);
     return;
   }
 
-  if ( !drivers.loadDriver( info->name ) ) {
-    sprintf(message, "RtAudio: ASIO error loading driver (%s).", info->name);
+  if ( !drivers.loadDriver( (char *)info->name.c_str() ) ) {
+    sprintf(message_, "RtApiAsio: error loading driver (%s).", info->name.c_str());
     error(RtError::DEBUG_WARNING);
     return;
   }
@@ -3498,7 +4444,7 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
       sprintf(details, "driver/hardware not present");
     else
       sprintf(details, "unspecified");
-    sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, info->name);
+    sprintf(message_, "RtApiAsio: error (%s) initializing driver (%s).", details, info->name.c_str());
     error(RtError::DEBUG_WARNING);
     return;
   }
@@ -3508,7 +4454,7 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   result = ASIOGetChannels( &inputChannels, &outputChannels );
   if ( result != ASE_OK ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).", info->name);
+    sprintf(message_, "RtApiAsio: error getting input/output channel count (%s).", info->name.c_str());
     error(RtError::DEBUG_WARNING);
     return;
   }
@@ -3529,16 +4475,16 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   }
 
   // Determine the supported sample rates.
-  info->nSampleRates = 0;
-  for (int i=0; i<MAX_SAMPLE_RATES; i++) {
+  info->sampleRates.clear();
+  for (unsigned int i=0; i<MAX_SAMPLE_RATES; i++) {
     result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
     if ( result == ASE_OK )
-      info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
+      info->sampleRates.push_back( SAMPLE_RATES[i] );
   }
 
-  if (info->nSampleRates == 0) {
+  if (info->sampleRates.size() == 0) {
     drivers.removeCurrentDriver();
-    sprintf( message, "RtAudio: No supported sample rates found for ASIO driver (%s).", info->name );
+    sprintf( message_, "RtApiAsio: No supported sample rates found for driver (%s).", info->name.c_str() );
     error(RtError::DEBUG_WARNING);
     return;
   }
@@ -3551,7 +4497,7 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   result = ASIOGetChannelInfo( &channelInfo );
   if ( result != ASE_OK ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO error getting driver (%s) channel information.", info->name);
+    sprintf(message_, "RtApiAsio: error getting driver (%s) channel information.", info->name.c_str());
     error(RtError::DEBUG_WARNING);
     return;
   }
@@ -3568,8 +4514,8 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
        // Check that we have at least one supported format.
   if (info->nativeFormats == 0) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
-            info->name);
+    sprintf(message_, "RtApiAsio: driver (%s) data format not supported by RtAudio.",
+            info->name.c_str());
     error(RtError::DEBUG_WARNING);
     return;
   }
@@ -3580,12 +4526,12 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
 
 void bufferSwitch(long index, ASIOBool processNow)
 {
-  RtAudio *object = (RtAudio *) asioCallbackInfo->object;
+  RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;
   try {
-    object->callbackEvent( asioCallbackInfo->streamId, index, (void *)NULL, (void *)NULL );
+    object->callbackEvent( index );
   }
   catch (RtError &exception) {
-    fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
+    fprintf(stderr, "\nRtApiAsio: callback handler error (%s)!\n\n", exception.getMessageString());
     return;
   }
 
@@ -3602,14 +4548,14 @@ void sampleRateChanged(ASIOSampleRate sRate)
 
   RtAudio *object = (RtAudio *) asioCallbackInfo->object;
   try {
-    object->stopStream( asioCallbackInfo->streamId );
+    object->stopStream();
   }
   catch (RtError &exception) {
-    fprintf(stderr, "\nRtAudio: sampleRateChanged() error (%s)!\n\n", exception.getMessage());
+    fprintf(stderr, "\nRtApiAsio: sampleRateChanged() error (%s)!\n\n", exception.getMessageString());
     return;
   }
 
-  fprintf(stderr, "\nRtAudio: ASIO driver reports sample rate changed to %d ... stream stopped!!!", (int) sRate);
+  fprintf(stderr, "\nRtApiAsio: driver reports sample rate changed to %d ... stream stopped!!!", (int) sRate);
 }
 
 long asioMessages(long selector, long value, void* message, double* opt)
@@ -3635,7 +4581,7 @@ long asioMessages(long selector, long value, void* message, double* opt)
     // done by completely destruct is. I.e. ASIOStop(),
     // ASIODisposeBuffers(), Destruction Afterwards you initialize the
     // driver again.
-    fprintf(stderr, "\nRtAudio: ASIO driver reset requested!!!");
+    fprintf(stderr, "\nRtApiAsio: driver reset requested!!!");
     ret = 1L;
     break;
   case kAsioResyncRequest:
@@ -3646,7 +4592,7 @@ long asioMessages(long selector, long value, void* message, double* opt)
     // which could lose data because the Mutex was held too long by
     // another thread.  However a driver can issue it in other
     // situations, too.
-    fprintf(stderr, "\nRtAudio: ASIO driver resync requested!!!");
+    fprintf(stderr, "\nRtApiAsio: driver resync requested!!!");
     ret = 1L;
     break;
   case kAsioLatenciesChanged:
@@ -3654,7 +4600,7 @@ long asioMessages(long selector, long value, void* message, double* opt)
     // latencies changed.  Beware, it this does not mean that the
     // buffer sizes have changed!  You might need to update internal
     // delay data.
-    fprintf(stderr, "\nRtAudio: ASIO driver latency may have changed!!!");
+    fprintf(stderr, "\nRtApiAsio: driver latency may have changed!!!");
     ret = 1L;
     break;
   case kAsioEngineVersion:
@@ -3680,30 +4626,22 @@ long asioMessages(long selector, long value, void* message, double* opt)
   return ret;
 }
 
-bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
-                                STREAM_MODE mode, int channels, 
-                                int sampleRate, RTAUDIO_FORMAT format,
-                                int *bufferSize, int numberOfBuffers)
+bool RtApiAsio :: probeDeviceOpen(int device, StreamMode mode, int channels, 
+                                  int sampleRate, RtAudioFormat format,
+                                  int *bufferSize, int numberOfBuffers)
 {
-  // Don't attempt to load another driver if a stream is already open.
-  if ( streams.size() > 0 ) {
-    sprintf(message, "RtAudio: unable to load ASIO driver while a stream is open.");
-    error(RtError::WARNING);
-    return FAILURE;
-  }
-
   // For ASIO, a duplex stream MUST use the same driver.
-  if ( mode == INPUT && stream->mode == OUTPUT && stream->device[0] != device ) {
-    sprintf(message, "RtAudio: ASIO duplex stream must use the same device for input and output.");
+  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) {
+    sprintf(message_, "RtApiAsio: duplex stream must use the same device for input and output.");
     error(RtError::WARNING);
     return FAILURE;
   }
 
   // Only load the driver once for duplex stream.
   ASIOError result;
-  if ( mode != INPUT || stream->mode != OUTPUT ) {
-    if ( !drivers.loadDriver( devices[device].name ) ) {
-      sprintf(message, "RtAudio: ASIO error loading driver (%s).", devices[device].name);
+  if ( mode != INPUT || stream_.mode != OUTPUT ) {
+    if ( !drivers.loadDriver( (char *)devices_[device].name.c_str() ) ) {
+      sprintf(message_, "RtApiAsio: error loading driver (%s).", devices_[device].name.c_str());
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
@@ -3719,7 +4657,7 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
         sprintf(details, "driver/hardware not present");
       else
         sprintf(details, "unspecified");
-      sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, devices[device].name);
+      sprintf(message_, "RtApiAsio: error (%s) initializing driver (%s).", details, devices_[device].name.c_str());
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
@@ -3730,8 +4668,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   result = ASIOGetChannels( &inputChannels, &outputChannels );
   if ( result != ASE_OK ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).",
-            devices[device].name);
+    sprintf(message_, "RtApiAsio: error getting input/output channel count (%s).",
+            devices_[device].name.c_str());
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -3739,20 +4677,20 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   if ( ( mode == OUTPUT && channels > outputChannels) ||
        ( mode == INPUT && channels > inputChannels) ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO driver (%s) does not support requested channel count (%d).",
-            devices[device].name, channels);
+    sprintf(message_, "RtApiAsio: driver (%s) does not support requested channel count (%d).",
+            devices_[device].name.c_str(), channels);
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
-  stream->nDeviceChannels[mode] = channels;
-  stream->nUserChannels[mode] = channels;
+  stream_.nDeviceChannels[mode] = channels;
+  stream_.nUserChannels[mode] = channels;
 
   // Verify the sample rate is supported.
   result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
   if ( result != ASE_OK ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO driver (%s) does not support requested sample rate (%d).",
-            devices[device].name, sampleRate);
+    sprintf(message_, "RtApiAsio: driver (%s) does not support requested sample rate (%d).",
+            devices_[device].name.c_str(), sampleRate);
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -3761,8 +4699,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
   if ( result != ASE_OK ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO driver (%s) error setting sample rate (%d).",
-            devices[device].name, sampleRate);
+    sprintf(message_, "RtApiAsio: driver (%s) error setting sample rate (%d).",
+            devices_[device].name.c_str(), sampleRate);
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -3775,37 +4713,37 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   result = ASIOGetChannelInfo( &channelInfo );
   if ( result != ASE_OK ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO driver (%s) error getting data format.",
-            devices[device].name);
+    sprintf(message_, "RtApiAsio: driver (%s) error getting data format.",
+            devices_[device].name.c_str());
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
 
   // Assuming WINDOWS host is always little-endian.
-  stream->doByteSwap[mode] = false;
-  stream->userFormat = format;
-  stream->deviceFormat[mode] = 0;
+  stream_.doByteSwap[mode] = false;
+  stream_.userFormat = format;
+  stream_.deviceFormat[mode] = 0;
   if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
-    stream->deviceFormat[mode] = RTAUDIO_SINT16;
-    if ( channelInfo.type == ASIOSTInt16MSB ) stream->doByteSwap[mode] = true;
+    stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+    if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true;
   }
   else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
-    stream->deviceFormat[mode] = RTAUDIO_SINT32;
-    if ( channelInfo.type == ASIOSTInt32MSB ) stream->doByteSwap[mode] = true;
+    stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+    if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true;
   }
   else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
-    stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
-    if ( channelInfo.type == ASIOSTFloat32MSB ) stream->doByteSwap[mode] = true;
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
+    if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true;
   }
   else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
-    stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
-    if ( channelInfo.type == ASIOSTFloat64MSB ) stream->doByteSwap[mode] = true;
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
+    if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true;
   }
 
-  if ( stream->deviceFormat[mode] == 0 ) {
+  if ( stream_.deviceFormat[mode] == 0 ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
-            devices[device].name);
+    sprintf(message_, "RtApiAsio: driver (%s) data format not supported by RtAudio.",
+            devices_[device].name.c_str());
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -3817,8 +4755,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
   if ( result != ASE_OK ) {
     drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO driver (%s) error getting buffer size.",
-            devices[device].name);
+    sprintf(message_, "RtApiAsio: driver (%s) error getting buffer size.",
+            devices_[device].name.c_str());
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -3827,51 +4765,67 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
   else if ( granularity == -1 ) {
     // Make sure bufferSize is a power of two.
-    double power = log10( *bufferSize ) / log10( 2.0 );
-    *bufferSize = pow( 2.0, floor(power+0.5) );
+    double power = log10( (double) *bufferSize ) / log10( 2.0 );
+    *bufferSize = (int) pow( 2.0, floor(power+0.5) );
     if ( *bufferSize < minSize ) *bufferSize = minSize;
     else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
     else *bufferSize = preferSize;
   }
 
-  if ( mode == INPUT && stream->mode == OUTPUT && stream->bufferSize != *bufferSize )
-    cout << "possible input/output buffersize discrepancy" << endl;
+  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize )
+    std::cerr << "Possible input/output buffersize discrepancy!" << std::endl;
 
-  stream->bufferSize = *bufferSize;
-  stream->nBuffers = 2;
+  stream_.bufferSize = *bufferSize;
+  stream_.nBuffers = 2;
 
   // ASIO always uses deinterleaved channels.
-  stream->deInterleave[mode] = true;
+  stream_.deInterleave[mode] = true;
 
-  // Create the ASIO internal buffers.  Since RtAudio sets up input
-  // and output separately, we'll have to dispose of previously
-  // created output buffers for a duplex stream.
-  if ( mode == INPUT && stream->mode == OUTPUT ) {
-    free(stream->callbackInfo.buffers);
-    result = ASIODisposeBuffers();
-    if ( result != ASE_OK ) {
+  // Allocate, if necessary, our AsioHandle structure for the stream.
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+  if ( handle == 0 ) {
+    handle = (AsioHandle *) calloc(1, sizeof(AsioHandle));
+    if ( handle == NULL ) {
       drivers.removeCurrentDriver();
-      sprintf(message, "RtAudio: ASIO driver (%s) error disposing previously allocated buffers.",
-              devices[device].name);
+      sprintf(message_, "RtApiAsio: error allocating AsioHandle memory (%s).",
+              devices_[device].name.c_str());
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
+    handle->bufferInfos = 0;
+    // Create a manual-reset event.
+    handle->condition = CreateEvent(NULL,  // no security
+                                    TRUE,  // manual-reset
+                                    FALSE, // non-signaled initially
+                                    NULL); // unnamed
+    stream_.apiHandle = (void *) handle;
+  }
+
+  // Create the ASIO internal buffers.  Since RtAudio sets up input
+  // and output separately, we'll have to dispose of previously
+  // created output buffers for a duplex stream.
+  if ( mode == INPUT && stream_.mode == OUTPUT ) {
+    ASIODisposeBuffers();
+    if ( handle->bufferInfos ) free( handle->bufferInfos );
   }
 
   // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
-  int i, nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
-  stream->callbackInfo.buffers = 0;
-  ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
-  stream->callbackInfo.buffers = (void *) bufferInfos;
-  ASIOBufferInfo *infos = bufferInfos;
-  for ( i=0; i<stream->nDeviceChannels[1]; i++, infos++ ) {
-    infos->isInput = ASIOTrue;
+  int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
+  handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
+  if (handle->bufferInfos == NULL) {
+    sprintf(message_, "RtApiAsio: error allocating bufferInfo memory (%s).",
+            devices_[device].name.c_str());
+    goto error;
+  }
+  ASIOBufferInfo *infos;
+  infos = handle->bufferInfos;
+  for ( i=0; i<stream_.nDeviceChannels[0]; i++, infos++ ) {
+    infos->isInput = ASIOFalse;
     infos->channelNum = i;
     infos->buffers[0] = infos->buffers[1] = 0;
   }
-
-  for ( i=0; i<stream->nDeviceChannels[0]; i++, infos++ ) {
-    infos->isInput = ASIOFalse;
+  for ( i=0; i<stream_.nDeviceChannels[1]; i++, infos++ ) {
+    infos->isInput = ASIOTrue;
     infos->channelNum = i;
     infos->buffers[0] = infos->buffers[1] = 0;
   }
@@ -3881,342 +4835,368 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   asioCallbacks.sampleRateDidChange = &sampleRateChanged;
   asioCallbacks.asioMessage = &asioMessages;
   asioCallbacks.bufferSwitchTimeInfo = NULL;
-  result = ASIOCreateBuffers( bufferInfos, nChannels, stream->bufferSize, &asioCallbacks);
+  result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks);
   if ( result != ASE_OK ) {
-    drivers.removeCurrentDriver();
-    sprintf(message, "RtAudio: ASIO driver (%s) error creating buffers.",
-            devices[device].name);
-    error(RtError::DEBUG_WARNING);
-    return FAILURE;
+    sprintf(message_, "RtApiAsio: driver (%s) error creating buffers.",
+            devices_[device].name.c_str());
+    goto error;
   }
 
   // Set flags for buffer conversion.
-  stream->doConvertBuffer[mode] = false;
-  if (stream->userFormat != stream->deviceFormat[mode])
-    stream->doConvertBuffer[mode] = true;
-  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
-    stream->doConvertBuffer[mode] = true;
-  if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
-    stream->doConvertBuffer[mode] = true;
+  stream_.doConvertBuffer[mode] = false;
+  if (stream_.userFormat != stream_.deviceFormat[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.nUserChannels[mode] > 1 && stream_.deInterleave[mode])
+    stream_.doConvertBuffer[mode] = true;
 
   // Allocate necessary internal buffers
-  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
+  if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
 
     long buffer_bytes;
-    if (stream->nUserChannels[0] >= stream->nUserChannels[1])
-      buffer_bytes = stream->nUserChannels[0];
+    if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
+      buffer_bytes = stream_.nUserChannels[0];
     else
-      buffer_bytes = stream->nUserChannels[1];
-
-    buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
-    if (stream->userBuffer) free(stream->userBuffer);
-    stream->userBuffer = (char *) calloc(buffer_bytes, 1);
-    if (stream->userBuffer == NULL)
-      goto memory_error;
+      buffer_bytes = stream_.nUserChannels[1];
+
+    buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
+    if (stream_.userBuffer) free(stream_.userBuffer);
+    stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
+    if (stream_.userBuffer == NULL) {
+      sprintf(message_, "RtApiAsio: error allocating user buffer memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
   }
 
-  if ( stream->doConvertBuffer[mode] ) {
+  if ( stream_.doConvertBuffer[mode] ) {
 
     long buffer_bytes;
     bool makeBuffer = true;
     if ( mode == OUTPUT )
-      buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
     else { // mode == INPUT
-      buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
-      if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
-        long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+        long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
         if ( buffer_bytes < bytes_out ) makeBuffer = false;
       }
     }
 
     if ( makeBuffer ) {
       buffer_bytes *= *bufferSize;
-      if (stream->deviceBuffer) free(stream->deviceBuffer);
-      stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
-      if (stream->deviceBuffer == NULL)
-        goto memory_error;
+      if (stream_.deviceBuffer) free(stream_.deviceBuffer);
+      stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
+      if (stream_.deviceBuffer == NULL) {
+        sprintf(message_, "RtApiAsio: error allocating device buffer memory (%s).",
+                devices_[device].name.c_str());
+        goto error;
+      }
     }
   }
 
-  stream->device[mode] = device;
-  stream->state = STREAM_STOPPED;
-  if ( stream->mode == OUTPUT && mode == INPUT )
+  stream_.device[mode] = device;
+  stream_.state = STREAM_STOPPED;
+  if ( stream_.mode == OUTPUT && mode == INPUT )
     // We had already set up an output stream.
-    stream->mode = DUPLEX;
+    stream_.mode = DUPLEX;
   else
-    stream->mode = mode;
-  stream->sampleRate = sampleRate;
-  asioCallbackInfo = &stream->callbackInfo;
-  stream->callbackInfo.object = (void *) this;
-  stream->callbackInfo.waitTime = (unsigned long) (200.0 * stream->bufferSize / stream->sampleRate);
+    stream_.mode = mode;
+  stream_.sampleRate = sampleRate;
+  asioCallbackInfo = &stream_.callbackInfo;
+  stream_.callbackInfo.object = (void *) this;
 
   return SUCCESS;
 
memory_error:
+ error:
   ASIODisposeBuffers();
   drivers.removeCurrentDriver();
 
-  if (stream->callbackInfo.buffers)
-    free(stream->callbackInfo.buffers);
-  stream->callbackInfo.buffers = 0;
+  if ( handle ) {
+    CloseHandle( handle->condition );
+    if ( handle->bufferInfos )
+      free( handle->bufferInfos );
+    free( handle );
+    stream_.apiHandle = 0;
+  }
 
-  if (stream->userBuffer) {
-    free(stream->userBuffer);
-    stream->userBuffer = 0;
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
   }
-  sprintf(message, "RtAudio: error allocating buffer memory (%s).",
-          devices[device].name);
+
   error(RtError::WARNING);
   return FAILURE;
 }
 
-void RtAudio :: cancelStreamCallback(int streamId)
+void RtApiAsio :: closeStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  // We don't want an exception to be thrown here because this
+  // function is called by our class destructor.  So, do our own
+  // streamId check.
+  if ( stream_.mode == UNINITIALIZED ) {
+    sprintf(message_, "RtApiAsio::closeStream(): no open stream to close!");
+    error(RtError::WARNING);
+    return;
+  }
 
-  if (stream->callbackInfo.usingCallback) {
+  if (stream_.state == STREAM_RUNNING)
+    ASIOStop();
 
-    if (stream->state == STREAM_RUNNING)
-      stopStream( streamId );
+  ASIODisposeBuffers();
+  drivers.removeCurrentDriver();
 
-    MUTEX_LOCK(&stream->mutex);
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+  if ( handle ) {
+    CloseHandle( handle->condition );
+    if ( handle->bufferInfos )
+      free( handle->bufferInfos );
+    free( handle );
+    stream_.apiHandle = 0;
+  }
 
-    stream->callbackInfo.usingCallback = false;
-    stream->callbackInfo.userData = NULL;
-    stream->state = STREAM_STOPPED;
-    stream->callbackInfo.callback = NULL;
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
+  }
 
-    MUTEX_UNLOCK(&stream->mutex);
+  if (stream_.deviceBuffer) {
+    free(stream_.deviceBuffer);
+    stream_.deviceBuffer = 0;
   }
+
+  stream_.mode = UNINITIALIZED;
 }
 
-void RtAudio :: closeStream(int streamId)
+void RtApiAsio :: setStreamCallback(RtAudioCallback callback, void *userData)
 {
-  // We don't want an exception to be thrown here because this
-  // function is called by our class destructor.  So, do our own
-  // streamId check.
-  if ( streams.find( streamId ) == streams.end() ) {
-    sprintf(message, "RtAudio: invalid stream identifier!");
+  verifyStream();
+
+  if ( stream_.callbackInfo.usingCallback ) {
+    sprintf(message_, "RtApiAsio: A callback is already set for this stream!");
     error(RtError::WARNING);
     return;
   }
 
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
-
-  if (stream->state == STREAM_RUNNING)
-    ASIOStop();
+  stream_.callbackInfo.callback = (void *) callback;
+  stream_.callbackInfo.userData = userData;
+  stream_.callbackInfo.usingCallback = true;
+}
 
-  ASIODisposeBuffers();
-  //ASIOExit();
-  drivers.removeCurrentDriver();
+void RtApiAsio :: cancelStreamCallback()
+{
+  verifyStream();
 
-  DeleteCriticalSection(&stream->mutex);
+  if (stream_.callbackInfo.usingCallback) {
 
-  if (stream->callbackInfo.buffers)
-    free(stream->callbackInfo.buffers);
+    if (stream_.state == STREAM_RUNNING)
+      stopStream();
 
-  if (stream->userBuffer)
-    free(stream->userBuffer);
+    MUTEX_LOCK(&stream_.mutex);
 
-  if (stream->deviceBuffer)
-    free(stream->deviceBuffer);
+    stream_.callbackInfo.usingCallback = false;
+    stream_.callbackInfo.userData = NULL;
+    stream_.state = STREAM_STOPPED;
+    stream_.callbackInfo.callback = NULL;
 
-  free(stream);
-  streams.erase(streamId);
+    MUTEX_UNLOCK(&stream_.mutex);
+  }
 }
 
-void RtAudio :: startStream(int streamId)
+void RtApiAsio :: startStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
+  verifyStream();
+  if (stream_.state == STREAM_RUNNING) return;
 
-  if (stream->state == STREAM_RUNNING) {
-    MUTEX_UNLOCK(&stream->mutex);
-    return;
-  }
+  MUTEX_LOCK(&stream_.mutex);
 
-  stream->callbackInfo.blockTick = true;
-  stream->callbackInfo.stopStream = false;
-  stream->callbackInfo.streamId = streamId;
   ASIOError result = ASIOStart();
   if ( result != ASE_OK ) {
-    sprintf(message, "RtAudio: ASIO error starting device (%s).",
-              devices[stream->device[0]].name);
-    MUTEX_UNLOCK(&stream->mutex);
+    sprintf(message_, "RtApiAsio: error starting device (%s).",
+              devices_[stream_.device[0]].name.c_str());
+    MUTEX_UNLOCK(&stream_.mutex);
     error(RtError::DRIVER_ERROR);
   }
-  stream->state = STREAM_RUNNING;
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+  handle->stopStream = false;
+  stream_.state = STREAM_RUNNING;
 
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: stopStream(int streamId)
+void RtApiAsio :: stopStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-  MUTEX_LOCK(&stream->mutex);
-
-  if (stream->state == STREAM_STOPPED) {
-    MUTEX_UNLOCK(&stream->mutex);
-    return;
-  }
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
   ASIOError result = ASIOStop();
   if ( result != ASE_OK ) {
-    sprintf(message, "RtAudio: ASIO error stopping device (%s).",
-              devices[stream->device[0]].name);
-    MUTEX_UNLOCK(&stream->mutex);
+    sprintf(message_, "RtApiAsio: error stopping device (%s).",
+              devices_[stream_.device[0]].name.c_str());
+    MUTEX_UNLOCK(&stream_.mutex);
     error(RtError::DRIVER_ERROR);
   }
-  stream->state = STREAM_STOPPED;
-
-  MUTEX_UNLOCK(&stream->mutex);
-}
 
-void RtAudio :: abortStream(int streamId)
-{
-  stopStream( streamId );
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-// I don't know how this function can be implemented.
-int RtAudio :: streamWillBlock(int streamId)
+void RtApiAsio :: abortStream()
 {
-  sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for ASIO.");
-  error(RtError::WARNING);
-  return 0;
+  stopStream();
 }
 
-void RtAudio :: tickStream(int streamId)
+void RtApiAsio :: tickStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
 
-  if (stream->state == STREAM_STOPPED)
+  if (stream_.state == STREAM_STOPPED)
     return;
 
-  if (stream->callbackInfo.usingCallback) {
-    sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
+  if (stream_.callbackInfo.usingCallback) {
+    sprintf(message_, "RtApiAsio: tickStream() should not be used when a callback function is set!");
     error(RtError::WARNING);
     return;
   }
 
-  // Block waiting here until the user data is processed in callbackEvent().
-  while ( stream->callbackInfo.blockTick )
-    Sleep(stream->callbackInfo.waitTime);
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
-  stream->callbackInfo.blockTick = true;
-
-  MUTEX_UNLOCK(&stream->mutex);
+  // Release the stream_mutex here and wait for the event
+  // to become signaled by the callback process.
+  MUTEX_UNLOCK(&stream_.mutex);
+  WaitForMultipleObjects(1, &handle->condition, FALSE, INFINITE);
+  ResetEvent( handle->condition );
 }
 
-void RtAudio :: callbackEvent(int streamId, int bufferIndex, void *inData, void *outData)
+void RtApiAsio :: callbackEvent(long bufferIndex)
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+
+  if (stream_.state == STREAM_STOPPED) return;
 
-  CALLBACK_INFO *info = asioCallbackInfo;
-  if ( !info->usingCallback ) {
-    // Block waiting here until we get new user data in tickStream().
-    while ( !info->blockTick )
-      Sleep(info->waitTime);
-  }
-  else if ( info->stopStream ) {
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+  if ( info->usingCallback && handle->stopStream ) {
     // Check if the stream should be stopped (via the previous user
     // callback return value).  We stop the stream here, rather than
     // after the function call, so that output data can first be
     // processed.
-    this->stopStream(asioCallbackInfo->streamId);
+    this->stopStream();
     return;
   }
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
   // Invoke user callback first, to get fresh output data.
   if ( info->usingCallback ) {
-    RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
-    if ( callback(stream->userBuffer, stream->bufferSize, info->userData) )
-      info->stopStream = true;
+    RtAudioCallback callback = (RtAudioCallback) info->callback;
+    if ( callback(stream_.userBuffer, stream_.bufferSize, info->userData) )
+      handle->stopStream = true;
   }
 
-  int nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
-  int bufferBytes;
-  ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) info->buffers;
-  if ( stream->mode == OUTPUT || stream->mode == DUPLEX ) {
+  int bufferBytes, j;
+  int nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
+  if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
 
-    bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[0]);
-    if (stream->doConvertBuffer[0]) {
+    bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[0]);
+    if (stream_.doConvertBuffer[0]) {
 
-      convertStreamBuffer(stream, OUTPUT);
-      if ( stream->doByteSwap[0] )
-        byteSwapBuffer(stream->deviceBuffer,
-                       stream->bufferSize * stream->nDeviceChannels[0],
-                       stream->deviceFormat[0]);
+      convertStreamBuffer(OUTPUT);
+      if ( stream_.doByteSwap[0] )
+        byteSwapBuffer(stream_.deviceBuffer,
+                       stream_.bufferSize * stream_.nDeviceChannels[0],
+                       stream_.deviceFormat[0]);
 
       // Always de-interleave ASIO output data.
-      for ( int i=0; i<stream->nDeviceChannels[0]; i++, bufferInfos++ ) {
-        memcpy(bufferInfos->buffers[bufferIndex],
-               &stream->deviceBuffer[i*bufferBytes], bufferBytes );
+      j = 0;
+      for ( int i=0; i<nChannels; i++ ) {
+        if ( handle->bufferInfos[i].isInput != ASIOTrue )
+          memcpy(handle->bufferInfos[i].buffers[bufferIndex],
+                 &stream_.deviceBuffer[j++*bufferBytes], bufferBytes );
       }
     }
     else { // single channel only
 
-      if (stream->doByteSwap[0])
-        byteSwapBuffer(stream->userBuffer,
-                       stream->bufferSize * stream->nUserChannels[0],
-                       stream->userFormat);
+      if (stream_.doByteSwap[0])
+        byteSwapBuffer(stream_.userBuffer,
+                       stream_.bufferSize * stream_.nUserChannels[0],
+                       stream_.userFormat);
 
-      memcpy(bufferInfos->buffers[bufferIndex], stream->userBuffer, bufferBytes );
+      for ( int i=0; i<nChannels; i++ ) {
+        if ( handle->bufferInfos[i].isInput != ASIOTrue ) {
+          memcpy(handle->bufferInfos[i].buffers[bufferIndex], stream_.userBuffer, bufferBytes );
+          break;
+        }
+      }
     }
   }
 
-  if ( stream->mode == INPUT || stream->mode == DUPLEX ) {
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
 
-    bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[1]);
-    if (stream->doConvertBuffer[1]) {
+    bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]);
+    if (stream_.doConvertBuffer[1]) {
 
       // Always interleave ASIO input data.
-      for ( int i=0; i<stream->nDeviceChannels[1]; i++, bufferInfos++ )
-        memcpy(&stream->deviceBuffer[i*bufferBytes], bufferInfos->buffers[bufferIndex], bufferBytes );
+      j = 0;
+      for ( int i=0; i<nChannels; i++ ) {
+        if ( handle->bufferInfos[i].isInput == ASIOTrue )
+          memcpy(&stream_.deviceBuffer[j++*bufferBytes],
+                 handle->bufferInfos[i].buffers[bufferIndex],
+                 bufferBytes );
+      }
 
-      if ( stream->doByteSwap[1] )
-        byteSwapBuffer(stream->deviceBuffer,
-                       stream->bufferSize * stream->nDeviceChannels[1],
-                       stream->deviceFormat[1]);
-      convertStreamBuffer(stream, INPUT);
+      if ( stream_.doByteSwap[1] )
+        byteSwapBuffer(stream_.deviceBuffer,
+                       stream_.bufferSize * stream_.nDeviceChannels[1],
+                       stream_.deviceFormat[1]);
+      convertStreamBuffer(INPUT);
 
     }
     else { // single channel only
-      memcpy(stream->userBuffer, bufferInfos->buffers[bufferIndex], bufferBytes );
+      for ( int i=0; i<nChannels; i++ ) {
+        if ( handle->bufferInfos[i].isInput == ASIOTrue ) {
+          memcpy(stream_.userBuffer,
+                 handle->bufferInfos[i].buffers[bufferIndex],
+                 bufferBytes );
+          break;
+        }
+      }
 
-      if (stream->doByteSwap[1])
-        byteSwapBuffer(stream->userBuffer,
-                       stream->bufferSize * stream->nUserChannels[1],
-                       stream->userFormat);
+      if (stream_.doByteSwap[1])
+        byteSwapBuffer(stream_.userBuffer,
+                       stream_.bufferSize * stream_.nUserChannels[1],
+                       stream_.userFormat);
     }
   }
 
   if ( !info->usingCallback )
-    info->blockTick = false;
-
-  MUTEX_UNLOCK(&stream->mutex);
-}
+    SetEvent( handle->condition );
 
-void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
-{
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  stream->callbackInfo.callback = (void *) callback;
-  stream->callbackInfo.userData = userData;
-  stream->callbackInfo.usingCallback = true;
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
 //******************** End of __WINDOWS_ASIO__ *********************//
+#endif
 
-#elif defined(__WINDOWS_DS__) // Windows DirectSound API
+#if defined(__WINDOWS_DS__) // Windows DirectSound API
 
 #include <dsound.h>
 
+// A structure to hold various information related to the DirectSound
+// API implementation.
+struct DsHandle {
+  void *object;
+  void *buffer;
+  UINT bufferPointer;  
+};
+
 // Declarations for utility functions, callbacks, and structures
 // specific to the DirectSound implementation.
 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
@@ -4241,6 +5221,8 @@ static bool CALLBACK deviceIdCallback(LPGUID lpguid,
 
 static char* getErrorString(int code);
 
+extern "C" unsigned __stdcall callbackHandler(void *ptr);
+
 struct enum_info {
   char name[64];
   LPGUID id;
@@ -4248,7 +5230,22 @@ struct enum_info {
   bool isValid;
 };
 
-int RtAudio :: getDefaultInputDevice(void)
+RtApiDs :: RtApiDs()
+{
+  this->initialize();
+
+  if (nDevices_ <= 0) {
+    sprintf(message_, "RtApiDs: no Windows DirectSound audio devices found!");
+    error(RtError::NO_DEVICES_FOUND);
+ }
+}
+
+RtApiDs :: ~RtApiDs()
+{
+  if ( stream_.mode != UNINITIALIZED ) closeStream();
+}
+
+int RtApiDs :: getDefaultInputDevice(void)
 {
   enum_info info;
   info.name[0] = '\0';
@@ -4256,19 +5253,21 @@ int RtAudio :: getDefaultInputDevice(void)
   // Enumerate through devices to find the default output.
   HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Error performing default input device enumeration: %s.",
+    sprintf(message_, "RtApiDs: Error performing default input device enumeration: %s.",
             getErrorString(result));
     error(RtError::WARNING);
     return 0;
   }
 
-  for ( int i=0; i<nDevices; i++ )
-    if ( strncmp( devices[i].name, info.name, 64 ) == 0 ) return i;
+  for ( int i=0; i<nDevices_; i++ ) {
+    if ( strncmp( info.name, devices_[i].name.c_str(), 64 ) == 0 ) return i;
+  }
+
 
   return 0;
 }
 
-int RtAudio :: getDefaultOutputDevice(void)
+int RtApiDs :: getDefaultOutputDevice(void)
 {
   enum_info info;
   info.name[0] = '\0';
@@ -4276,28 +5275,28 @@ int RtAudio :: getDefaultOutputDevice(void)
   // Enumerate through devices to find the default output.
   HRESULT result = DirectSoundEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Error performing default output device enumeration: %s.",
+    sprintf(message_, "RtApiDs: Error performing default output device enumeration: %s.",
             getErrorString(result));
     error(RtError::WARNING);
     return 0;
   }
 
-  for ( int i=0; i<nDevices; i++ )
-    if ( strncmp(devices[i].name, info.name, 64 ) == 0 ) return i;
+  for ( int i=0; i<nDevices_; i++ )
+    if ( strncmp( info.name, devices_[i].name.c_str(), 64 ) == 0 ) return i;
 
   return 0;
 }
 
-void RtAudio :: initialize(void)
+void RtApiDs :: initialize(void)
 {
   int i, ins = 0, outs = 0, count = 0;
   HRESULT result;
-  nDevices = 0;
+  nDevices_ = 0;
 
   // Count DirectSound devices.
   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
+    sprintf(message_, "RtApiDs: Unable to enumerate through sound playback devices: %s.",
             getErrorString(result));
     error(RtError::DRIVER_ERROR);
   }
@@ -4305,7 +5304,7 @@ void RtAudio :: initialize(void)
   // Count DirectSoundCapture devices.
   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
+    sprintf(message_, "RtApiDs: Unable to enumerate through sound capture devices: %s.",
             getErrorString(result));
     error(RtError::DRIVER_ERROR);
   }
@@ -4323,7 +5322,7 @@ void RtAudio :: initialize(void)
   // Get playback device info and check capabilities.
   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
+    sprintf(message_, "RtApiDs: Unable to enumerate through sound playback devices: %s.",
             getErrorString(result));
     error(RtError::DRIVER_ERROR);
   }
@@ -4331,49 +5330,39 @@ void RtAudio :: initialize(void)
   // Get capture device info and check capabilities.
   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
+    sprintf(message_, "RtApiDs: Unable to enumerate through sound capture devices: %s.",
             getErrorString(result));
     error(RtError::DRIVER_ERROR);
   }
 
-  // Parse the devices and check validity.  Devices are considered
-  // invalid if they cannot be opened, they report < 1 supported
-  // channels, or they report no supported data (capture only).
-  for (i=0; i<count; i++)
-    if ( info[i].isValid ) nDevices++;
-
-  if (nDevices == 0) return;
-
-  //  Allocate the RTAUDIO_DEVICE structures.
-  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
-  if (devices == NULL) {
-    sprintf(message, "RtAudio: memory allocation error!");
-    error(RtError::MEMORY_ERROR);
-  }
-
-  // Copy the names to our devices structures.
+  // Create device structures for valid devices and write device names
+  // to each.  Devices are considered invalid if they cannot be
+  // opened, they report < 1 supported channels, or they report no
+  // supported data (capture only).
+  RtApiDevice device;
   int index = 0;
   for (i=0; i<count; i++) {
-    if ( info[i].isValid )
-      strncpy(devices[index++].name, info[i].name, 64);
+    if ( info[i].isValid ) {
+      device.name.erase();
+      device.name.append( (const char *)info[i].name, strlen(info[i].name)+1);
+      devices_.push_back(device);
+    }
   }
 
-  //for (i=0;i<nDevices; i++)
-  //probeDeviceInfo(&devices[i]);
-
+  nDevices_ = devices_.size();
   return;
 }
 
-void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
+void RtApiDs :: probeDeviceInfo(RtApiDevice *info)
 {
   enum_info dsinfo;
-  strncpy( dsinfo.name, info->name, 64 );
+  strncpy( dsinfo.name, info->name.c_str(), 64 );
   dsinfo.isValid = false;
 
   // Enumerate through input devices to find the id (if it exists).
   HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
+    sprintf(message_, "RtApiDs: Error performing input device id enumeration: %s.",
             getErrorString(result));
     error(RtError::WARNING);
     return;
@@ -4386,8 +5375,8 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   LPDIRECTSOUNDCAPTURE  input;
   result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL );
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
-            info->name, getErrorString(result));
+    sprintf(message_, "RtApiDs: Could not create capture object (%s): %s.",
+            info->name.c_str(), getErrorString(result));
     error(RtError::WARNING);
     goto playback_probe;
   }
@@ -4397,8 +5386,8 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   result = input->GetCaps( &in_caps );
   if ( FAILED(result) ) {
     input->Release();
-    sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.",
-            info->name, getErrorString(result));
+    sprintf(message_, "RtApiDs: Could not get capture capabilities (%s): %s.",
+            info->name.c_str(), getErrorString(result));
     error(RtError::WARNING);
     goto playback_probe;
   }
@@ -4408,6 +5397,7 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   info->maxInputChannels = in_caps.dwChannels;
 
   // Get sample rate and format information.
+  info->sampleRates.clear();
   if( in_caps.dwChannels == 2 ) {
     if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
     if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
@@ -4417,14 +5407,14 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
     if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
 
     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
-      if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025;
-      if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050;
-      if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100;
+      if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates.push_back( 11025 );
+      if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates.push_back( 22050 );
+      if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates.push_back( 44100 );
     }
     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
-      if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025;
-      if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050;
-      if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100;
+      if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates.push_back( 11025 );
+      if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates.push_back( 22050 );
+      if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates.push_back( 44100 );
     }
   }
   else if ( in_caps.dwChannels == 1 ) {
@@ -4436,14 +5426,14 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
     if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
 
     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
-      if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025;
-      if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050;
-      if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100;
+      if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates.push_back( 11025 );
+      if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates.push_back( 22050 );
+      if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates.push_back( 44100 );
     }
     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
-      if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025;
-      if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050;
-      if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100;
+      if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates.push_back( 11025 );
+      if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates.push_back( 22050 );
+      if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates.push_back( 44100 );
     }
   }
   else info->minInputChannels = 0; // technically, this would be an error
@@ -4457,7 +5447,7 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   // Enumerate through output devices to find the id (if it exists).
   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
+    sprintf(message_, "RtApiDs: Error performing output device id enumeration: %s.",
             getErrorString(result));
     error(RtError::WARNING);
     return;
@@ -4471,8 +5461,8 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   DSCAPS out_caps;
   result = DirectSoundCreate( dsinfo.id, &output, NULL );
   if ( FAILED(result) ) {
-    sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
-            info->name, getErrorString(result));
+    sprintf(message_, "RtApiDs: Could not create playback object (%s): %s.",
+            info->name.c_str(), getErrorString(result));
     error(RtError::WARNING);
     goto check_parameters;
   }
@@ -4481,8 +5471,8 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   result = output->GetCaps( &out_caps );
   if ( FAILED(result) ) {
     output->Release();
-    sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.",
-            info->name, getErrorString(result));
+    sprintf(message_, "RtApiDs: Could not get playback capabilities (%s): %s.",
+            info->name.c_str(), getErrorString(result));
     error(RtError::WARNING);
     goto check_parameters;
   }
@@ -4493,49 +5483,19 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
 
   // Get sample rate information.  Use capture device rate information
   // if it exists.
-  if ( info->nSampleRates == 0 ) {
-    info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate;
-    info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate;
-    if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE )
-      info->nSampleRates = -1;
-    else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) {
-      if ( out_caps.dwMinSecondarySampleRate == 0 ) {
-        // This is a bogus driver report ... fake the range and cross
-        // your fingers.
-        info->sampleRates[0] = 11025;
-                               info->sampleRates[1] = 48000;
-        info->nSampleRates = -1; /* continuous range */
-        sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).",
-                info->name);
-        error(RtError::DEBUG_WARNING);
-      }
-      else {
-        info->nSampleRates = 1;
-                       }
-    }
-    else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) &&
-              (out_caps.dwMaxSecondarySampleRate > 50000.0) ) {
-      // This is a bogus driver report ... support for only two
-      // distant rates.  We'll assume this is a range.
-      info->nSampleRates = -1;
-      sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).",
-              info->name);
-      error(RtError::WARNING);
-    }
-    else info->nSampleRates = 2;
+  if ( info->sampleRates.size() == 0 ) {
+    info->sampleRates.push_back( (int) out_caps.dwMinSecondarySampleRate );
+    info->sampleRates.push_back( (int) out_caps.dwMaxSecondarySampleRate );
   }
   else {
-    // Check input rates against output rate range
-    for ( int i=info->nSampleRates-1; i>=0; i-- ) {
-      if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate )
-        break;
-      info->nSampleRates--;
+    // Check input rates against output rate range.
+    for ( unsigned int i=info->sampleRates.size()-1; i>=0; i-- ) {
+      if ( (unsigned int) info->sampleRates[i] > out_caps.dwMaxSecondarySampleRate )
+        info->sampleRates.erase( info->sampleRates.begin() + i );
     }
-    while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) {
-      info->nSampleRates--;
-      for ( int i=0; i<info->nSampleRates; i++)
-        info->sampleRates[i] = info->sampleRates[i+1];
-      if ( info->nSampleRates <= 0 ) break;
+    while ( info->sampleRates.size() > 0 &&
+            ((unsigned int) info->sampleRates[0] < out_caps.dwMinSecondarySampleRate) ) {
+      info->sampleRates.erase( info->sampleRates.begin() );
     }
   }
 
@@ -4546,10 +5506,18 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   output->Release();
 
  check_parameters:
-  if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
+  if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 ) {
+    sprintf(message_, "RtApiDs: no reported input or output channels for device (%s).",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
     return;
-  if ( info->nSampleRates == 0 || info->nativeFormats == 0 )
+  }
+  if ( info->sampleRates.size() == 0 || info->nativeFormats == 0 ) {
+    sprintf(message_, "RtApiDs: no reported sample rates or data formats for device (%s).",
+            info->name.c_str());
+    error(RtError::DEBUG_WARNING);
     return;
+  }
 
   // Determine duplex status.
   if (info->maxInputChannels < info->maxOutputChannels)
@@ -4569,13 +5537,13 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   return;
 }
 
-bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
-                                STREAM_MODE mode, int channels, 
-                                int sampleRate, RTAUDIO_FORMAT format,
-                                int *bufferSize, int numberOfBuffers)
+bool RtApiDs :: probeDeviceOpen( int device, StreamMode mode, int channels, 
+                                 int sampleRate, RtAudioFormat format,
+                                 int *bufferSize, int numberOfBuffers)
 {
   HRESULT result;
   HWND hWnd = GetForegroundWindow();
+
   // According to a note in PortAudio, using GetDesktopWindow()
   // instead of GetForegroundWindow() is supposed to avoid problems
   // that occur when the application's window is not the foreground
@@ -4603,23 +5571,23 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
 
   // Determine the data format.
-  if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support
+  if ( devices_[device].nativeFormats ) { // 8-bit and/or 16-bit support
     if ( format == RTAUDIO_SINT8 ) {
-      if ( devices[device].nativeFormats & RTAUDIO_SINT8 )
+      if ( devices_[device].nativeFormats & RTAUDIO_SINT8 )
         waveFormat.wBitsPerSample = 8;
       else
         waveFormat.wBitsPerSample = 16;
     }
     else {
-      if ( devices[device].nativeFormats & RTAUDIO_SINT16 )
+      if ( devices_[device].nativeFormats & RTAUDIO_SINT16 )
         waveFormat.wBitsPerSample = 16;
       else
         waveFormat.wBitsPerSample = 8;
     }
   }
   else {
-    sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).",
-            devices[device].name);
+    sprintf(message_, "RtApiDs: no reported data formats for device (%s).",
+            devices_[device].name.c_str());
     error(RtError::DEBUG_WARNING);
     return FAILURE;
   }
@@ -4628,24 +5596,29 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
 
   enum_info dsinfo;
-  strncpy( dsinfo.name, devices[device].name, 64 );
+  void *ohandle = 0, *bhandle = 0;
+  strncpy( dsinfo.name, devices_[device].name.c_str(), 64 );
   dsinfo.isValid = false;
   if ( mode == OUTPUT ) {
 
-    if ( devices[device].maxOutputChannels < channels )
+    if ( devices_[device].maxOutputChannels < channels ) {
+      sprintf(message_, "RtApiDs: requested channels (%d) > than supported (%d) by device (%s).",
+              channels, devices_[device].maxOutputChannels, devices_[device].name.c_str());
+      error(RtError::DEBUG_WARNING);
       return FAILURE;
+    }
 
     // Enumerate through output devices to find the id (if it exists).
     result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
+      sprintf(message_, "RtApiDs: Error performing output device id enumeration: %s.",
               getErrorString(result));
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
 
     if ( dsinfo.isValid == false ) {
-      sprintf(message, "RtAudio: DS output device (%s) id not found!", devices[device].name);
+      sprintf(message_, "RtApiDs: output device (%s) id not found!", devices_[device].name.c_str());
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
@@ -4657,8 +5630,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     
     result = DirectSoundCreate( id, &object, NULL );
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
-              devices[device].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Could not create playback object (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
@@ -4667,16 +5640,16 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
     if ( FAILED(result) ) {
       object->Release();
-      sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.",
-              devices[device].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to set cooperative level (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
 
     // Even though we will write to the secondary buffer, we need to
-    // access the primary buffer to set the correct output format.
-    // The default is 8-bit, 22 kHz!
-    // Setup the DS primary buffer description.
+    // access the primary buffer to set the correct output format
+    // (since the default is 8-bit, 22 kHz!).  Setup the DS primary
+    // buffer description.
     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
     bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
@@ -4684,8 +5657,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
     if ( FAILED(result) ) {
       object->Release();
-      sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.",
-              devices[device].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to access primary buffer (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
@@ -4694,8 +5667,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = buffer->SetFormat(&waveFormat);
     if ( FAILED(result) ) {
       object->Release();
-      sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.",
-              devices[device].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to set primary buffer format (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
@@ -4720,8 +5693,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
       result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
       if ( FAILED(result) ) {
         object->Release();
-        sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.",
-                devices[device].name, getErrorString(result));
+        sprintf(message_, "RtApiDs: Unable to create secondary DS buffer (%s): %s.",
+                devices_[device].name.c_str(), getErrorString(result));
         error(RtError::WARNING);
         return FAILURE;
       }
@@ -4737,8 +5710,9 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
     if ( FAILED(result) ) {
       object->Release();
-      sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
-              devices[device].name, getErrorString(result));
+      buffer->Release();
+      sprintf(message_, "RtApiDs: Unable to lock buffer (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
@@ -4750,33 +5724,34 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
     if ( FAILED(result) ) {
       object->Release();
-      sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.",
-              devices[device].name, getErrorString(result));
+      buffer->Release();
+      sprintf(message_, "RtApiDs: Unable to unlock buffer(%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
 
-    stream->handle[0].object = (void *) object;
-    stream->handle[0].buffer = (void *) buffer;
-    stream->nDeviceChannels[0] = channels;
+    ohandle = (void *) object;
+    bhandle = (void *) buffer;
+    stream_.nDeviceChannels[0] = channels;
   }
 
   if ( mode == INPUT ) {
 
-    if ( devices[device].maxInputChannels < channels )
+    if ( devices_[device].maxInputChannels < channels )
       return FAILURE;
 
     // Enumerate through input devices to find the id (if it exists).
     result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
+      sprintf(message_, "RtApiDs: Error performing input device id enumeration: %s.",
               getErrorString(result));
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
 
     if ( dsinfo.isValid == false ) {
-      sprintf(message, "RtAudio: DS input device (%s) id not found!", devices[device].name);
+      sprintf(message_, "RtAudioDS: input device (%s) id not found!", devices_[device].name.c_str());
       error(RtError::DEBUG_WARNING);
       return FAILURE;
     }
@@ -4788,8 +5763,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
 
     result = DirectSoundCaptureCreate( id, &object, NULL );
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
-              devices[device].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Could not create capture object (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
@@ -4807,8 +5782,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
     if ( FAILED(result) ) {
       object->Release();
-      sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.",
-              devices[device].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to create capture buffer (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
@@ -4817,8 +5792,9 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
     if ( FAILED(result) ) {
       object->Release();
-      sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
-              devices[device].name, getErrorString(result));
+      buffer->Release();
+      sprintf(message_, "RtApiDs: Unable to lock capture buffer (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
@@ -4830,233 +5806,285 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
     if ( FAILED(result) ) {
       object->Release();
-      sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
-              devices[device].name, getErrorString(result));
+      buffer->Release();
+      sprintf(message_, "RtApiDs: Unable to unlock capture buffer (%s): %s.",
+              devices_[device].name.c_str(), getErrorString(result));
       error(RtError::WARNING);
       return FAILURE;
     }
 
-    stream->handle[1].object = (void *) object;
-    stream->handle[1].buffer = (void *) buffer;
-    stream->nDeviceChannels[1] = channels;
+    ohandle = (void *) object;
+    bhandle = (void *) buffer;
+    stream_.nDeviceChannels[1] = channels;
   }
 
-  stream->userFormat = format;
+  stream_.userFormat = format;
   if ( waveFormat.wBitsPerSample == 8 )
-    stream->deviceFormat[mode] = RTAUDIO_SINT8;
+    stream_.deviceFormat[mode] = RTAUDIO_SINT8;
   else
-    stream->deviceFormat[mode] = RTAUDIO_SINT16;
-  stream->nUserChannels[mode] = channels;
+    stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+  stream_.nUserChannels[mode] = channels;
   *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8);
-  stream->bufferSize = *bufferSize;
+  stream_.bufferSize = *bufferSize;
 
   // Set flags for buffer conversion
-  stream->doConvertBuffer[mode] = false;
-  if (stream->userFormat != stream->deviceFormat[mode])
-    stream->doConvertBuffer[mode] = true;
-  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
-    stream->doConvertBuffer[mode] = true;
+  stream_.doConvertBuffer[mode] = false;
+  if (stream_.userFormat != stream_.deviceFormat[mode])
+    stream_.doConvertBuffer[mode] = true;
+  if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
+    stream_.doConvertBuffer[mode] = true;
 
   // Allocate necessary internal buffers
-  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
+  if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
 
     long buffer_bytes;
-    if (stream->nUserChannels[0] >= stream->nUserChannels[1])
-      buffer_bytes = stream->nUserChannels[0];
+    if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
+      buffer_bytes = stream_.nUserChannels[0];
     else
-      buffer_bytes = stream->nUserChannels[1];
-
-    buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
-    if (stream->userBuffer) free(stream->userBuffer);
-    stream->userBuffer = (char *) calloc(buffer_bytes, 1);
-    if (stream->userBuffer == NULL)
-      goto memory_error;
+      buffer_bytes = stream_.nUserChannels[1];
+
+    buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
+    if (stream_.userBuffer) free(stream_.userBuffer);
+    stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
+    if (stream_.userBuffer == NULL) {
+      sprintf(message_, "RtApiDs: error allocating user buffer memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
   }
 
-  if ( stream->doConvertBuffer[mode] ) {
+  if ( stream_.doConvertBuffer[mode] ) {
 
     long buffer_bytes;
     bool makeBuffer = true;
     if ( mode == OUTPUT )
-      buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
     else { // mode == INPUT
-      buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
-      if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
-        long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+        long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
         if ( buffer_bytes < bytes_out ) makeBuffer = false;
       }
     }
 
     if ( makeBuffer ) {
       buffer_bytes *= *bufferSize;
-      if (stream->deviceBuffer) free(stream->deviceBuffer);
-      stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
-      if (stream->deviceBuffer == NULL)
-        goto memory_error;
+      if (stream_.deviceBuffer) free(stream_.deviceBuffer);
+      stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
+      if (stream_.deviceBuffer == NULL) {
+        sprintf(message_, "RtApiDs: error allocating device buffer memory (%s).",
+                devices_[device].name.c_str());
+        goto error;
+      }
     }
   }
 
-  stream->device[mode] = device;
-  stream->state = STREAM_STOPPED;
-  if ( stream->mode == OUTPUT && mode == INPUT )
+  // Allocate our DsHandle structures for the stream.
+  DsHandle *handles;
+  if ( stream_.apiHandle == 0 ) {
+    handles = (DsHandle *) calloc(2, sizeof(DsHandle));
+    if ( handles == NULL ) {
+      sprintf(message_, "RtApiDs: Error allocating DsHandle memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
+    handles[0].object = 0;
+    handles[1].object = 0;
+    stream_.apiHandle = (void *) handles;
+  }
+  else
+    handles = (DsHandle *) stream_.apiHandle;
+  handles[mode].object = ohandle;
+  handles[mode].buffer = bhandle;
+
+  stream_.device[mode] = device;
+  stream_.state = STREAM_STOPPED;
+  if ( stream_.mode == OUTPUT && mode == INPUT )
     // We had already set up an output stream.
-    stream->mode = DUPLEX;
+    stream_.mode = DUPLEX;
   else
-    stream->mode = mode;
-  stream->nBuffers = nBuffers;
-  stream->sampleRate = sampleRate;
+    stream_.mode = mode;
+  stream_.nBuffers = nBuffers;
+  stream_.sampleRate = sampleRate;
 
   return SUCCESS;
 
memory_error:
-  if (stream->handle[0].object) {
-    LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
-    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
-    if (buffer) {
-      buffer->Release();
-      stream->handle[0].buffer = NULL;
+ error:
+  if (handles) {
+    if (handles[0].object) {
+      LPDIRECTSOUND object = (LPDIRECTSOUND) handles[0].object;
+      LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
+      if (buffer) buffer->Release();
+      object->Release();
     }
-    object->Release();
-    stream->handle[0].object = NULL;
-  }
-  if (stream->handle[1].object) {
-    LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
-    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
-    if (buffer) {
-      buffer->Release();
-      stream->handle[1].buffer = NULL;
+    if (handles[1].object) {
+      LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handles[1].object;
+      LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
+      if (buffer) buffer->Release();
+      object->Release();
     }
-    object->Release();
-    stream->handle[1].object = NULL;
+    free(handles);
+    stream_.apiHandle = 0;
   }
-  if (stream->userBuffer) {
-    free(stream->userBuffer);
-    stream->userBuffer = 0;
+
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
   }
-  sprintf(message, "RtAudio: error allocating buffer memory (%s).",
-          devices[device].name);
+
   error(RtError::WARNING);
   return FAILURE;
 }
 
-void RtAudio :: cancelStreamCallback(int streamId)
+void RtApiDs :: setStreamCallback(RtAudioCallback callback, void *userData)
+{
+  verifyStream();
+
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+  if ( info->usingCallback ) {
+    sprintf(message_, "RtApiDs: A callback is already set for this stream!");
+    error(RtError::WARNING);
+    return;
+  }
+
+  info->callback = (void *) callback;
+  info->userData = userData;
+  info->usingCallback = true;
+  info->object = (void *) this;
+
+  unsigned thread_id;
+  info->thread = _beginthreadex(NULL, 0, &callbackHandler,
+                                &stream_.callbackInfo, 0, &thread_id);
+  if (info->thread == 0) {
+    info->usingCallback = false;
+    sprintf(message_, "RtApiDs: error starting callback thread!");
+    error(RtError::THREAD_ERROR);
+  }
+
+  // When spawning multiple threads in quick succession, it appears to be
+  // necessary to wait a bit for each to initialize ... another windoism!
+  Sleep(1);
+}
+
+void RtApiDs :: cancelStreamCallback()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
 
-  if (stream->callbackInfo.usingCallback) {
+  if (stream_.callbackInfo.usingCallback) {
 
-    if (stream->state == STREAM_RUNNING)
-      stopStream( streamId );
+    if (stream_.state == STREAM_RUNNING)
+      stopStream();
 
-    MUTEX_LOCK(&stream->mutex);
+    MUTEX_LOCK(&stream_.mutex);
 
-    stream->callbackInfo.usingCallback = false;
-    WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
-    CloseHandle( (HANDLE)stream->callbackInfo.thread );
-    stream->callbackInfo.thread = 0;
-    stream->callbackInfo.callback = NULL;
-    stream->callbackInfo.userData = NULL;
+    stream_.callbackInfo.usingCallback = false;
+    WaitForSingleObject( (HANDLE)stream_.callbackInfo.thread, INFINITE );
+    CloseHandle( (HANDLE)stream_.callbackInfo.thread );
+    stream_.callbackInfo.thread = 0;
+    stream_.callbackInfo.callback = NULL;
+    stream_.callbackInfo.userData = NULL;
 
-    MUTEX_UNLOCK(&stream->mutex);
+    MUTEX_UNLOCK(&stream_.mutex);
   }
 }
 
-void RtAudio :: closeStream(int streamId)
+void RtApiDs :: closeStream()
 {
   // We don't want an exception to be thrown here because this
   // function is called by our class destructor.  So, do our own
   // streamId check.
-  if ( streams.find( streamId ) == streams.end() ) {
-    sprintf(message, "RtAudio: invalid stream identifier!");
+  if ( stream_.mode == UNINITIALIZED ) {
+    sprintf(message_, "RtApiDs::closeStream(): no open stream to close!");
     error(RtError::WARNING);
     return;
   }
 
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
-
-  if (stream->callbackInfo.usingCallback) {
-    stream->callbackInfo.usingCallback = false;
-    WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
-    CloseHandle( (HANDLE)stream->callbackInfo.thread );
+  if (stream_.callbackInfo.usingCallback) {
+    stream_.callbackInfo.usingCallback = false;
+    WaitForSingleObject( (HANDLE)stream_.callbackInfo.thread, INFINITE );
+    CloseHandle( (HANDLE)stream_.callbackInfo.thread );
   }
 
-  DeleteCriticalSection(&stream->mutex);
-
-  if (stream->handle[0].object) {
-    LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
-    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
-    if (buffer) {
-      buffer->Stop();
-      buffer->Release();
+  DsHandle *handles = (DsHandle *) stream_.apiHandle;
+  if (handles) {
+    if (handles[0].object) {
+      LPDIRECTSOUND object = (LPDIRECTSOUND) handles[0].object;
+      LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
+      if (buffer) {
+        buffer->Stop();
+        buffer->Release();
+      }
+      object->Release();
     }
-    object->Release();
-  }
 
-  if (stream->handle[1].object) {
-    LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
-    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
-    if (buffer) {
-      buffer->Stop();
-      buffer->Release();
+    if (handles[1].object) {
+      LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handles[1].object;
+      LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
+      if (buffer) {
+        buffer->Stop();
+        buffer->Release();
+      }
+      object->Release();
     }
-    object->Release();
+    free(handles);
+    stream_.apiHandle = 0;
+  }
+    
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
   }
 
-  if (stream->userBuffer)
-    free(stream->userBuffer);
-
-  if (stream->deviceBuffer)
-    free(stream->deviceBuffer);
+  if (stream_.deviceBuffer) {
+    free(stream_.deviceBuffer);
+    stream_.deviceBuffer = 0;
+  }
 
-  free(stream);
-  streams.erase(streamId);
+  stream_.mode = UNINITIALIZED;
 }
 
-void RtAudio :: startStream(int streamId)
+void RtApiDs :: startStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_RUNNING) return;
 
-  MUTEX_LOCK(&stream->mutex);
-
-  if (stream->state == STREAM_RUNNING)
-    goto unlock;
+  MUTEX_LOCK(&stream_.mutex);
 
   HRESULT result;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
+  DsHandle *handles = (DsHandle *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
     result = buffer->Play(0, 0, DSBPLAY_LOOPING );
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.",
-              devices[stream->device[0]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to start buffer (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
     result = buffer->Start(DSCBSTART_LOOPING );
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to start capture buffer (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
   }
-  stream->state = STREAM_RUNNING;
+  stream_.state = STREAM_RUNNING;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: stopStream(int streamId)
+void RtApiDs :: stopStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-  if (stream->state == STREAM_STOPPED) {
-    MUTEX_UNLOCK(&stream->mutex);
-    return;
-  }
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
   // There is no specific DirectSound API call to "drain" a buffer
   // before stopping.  We can hack this for playback by writing zeroes
@@ -5069,24 +6097,25 @@ void RtAudio :: stopStream(int streamId)
   LPVOID buffer2 = NULL;
   DWORD bufferSize1 = 0;
   DWORD bufferSize2 = 0;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
+  DsHandle *handles = (DsHandle *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
 
     DWORD currentPos, safePos;
-    long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
-    buffer_bytes *= formatBytes(stream->deviceFormat[0]);
+    long buffer_bytes = stream_.bufferSize * stream_.nDeviceChannels[0];
+    buffer_bytes *= formatBytes(stream_.deviceFormat[0]);
 
-    LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
-    UINT nextWritePos = stream->handle[0].bufferPointer;
-    dsBufferSize = buffer_bytes * stream->nBuffers;
+    LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
+    UINT nextWritePos = handles[0].bufferPointer;
+    dsBufferSize = buffer_bytes * stream_.nBuffers;
 
     // Write zeroes for nBuffer counts.
-    for (int i=0; i<stream->nBuffers; i++) {
+    for (int i=0; i<stream_.nBuffers; i++) {
 
       // Find out where the read and "safe write" pointers are.
       result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
       if ( FAILED(result) ) {
-        sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
-                devices[stream->device[0]].name, getErrorString(result));
+        sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
+                devices_[stream_.device[0]].name.c_str(), getErrorString(result));
         error(RtError::DRIVER_ERROR);
       }
 
@@ -5095,16 +6124,16 @@ void RtAudio :: stopStream(int streamId)
 
       // Check whether the entire write region is behind the play pointer.
       while ( currentPos < endWrite ) {
-        float millis = (endWrite - currentPos) * 900.0;
-        millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
+        double millis = (endWrite - currentPos) * 900.0;
+        millis /= ( formatBytes(stream_.deviceFormat[0]) * stream_.sampleRate);
         if ( millis < 1.0 ) millis = 1.0;
         Sleep( (DWORD) millis );
 
         // Wake up, find out where we are now
         result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
         if ( FAILED(result) ) {
-          sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
-                  devices[stream->device[0]].name, getErrorString(result));
+          sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
+                  devices_[stream_.device[0]].name.c_str(), getErrorString(result));
           error(RtError::DRIVER_ERROR);
         }
         if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
@@ -5114,8 +6143,8 @@ void RtAudio :: stopStream(int streamId)
       result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
                                &bufferSize1, &buffer2, &bufferSize2, 0);
       if ( FAILED(result) ) {
-        sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
-                devices[stream->device[0]].name, getErrorString(result));
+        sprintf(message_, "RtApiDs: Unable to lock buffer during playback (%s): %s.",
+                devices_[stream_.device[0]].name.c_str(), getErrorString(result));
         error(RtError::DRIVER_ERROR);
       }
 
@@ -5126,39 +6155,39 @@ void RtAudio :: stopStream(int streamId)
       // Update our buffer offset and unlock sound buffer
       dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
       if ( FAILED(result) ) {
-        sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
-                devices[stream->device[0]].name, getErrorString(result));
+        sprintf(message_, "RtApiDs: Unable to unlock buffer during playback (%s): %s.",
+                devices_[stream_.device[0]].name.c_str(), getErrorString(result));
         error(RtError::DRIVER_ERROR);
       }
       nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
-      stream->handle[0].bufferPointer = nextWritePos;
+      handles[0].bufferPointer = nextWritePos;
     }
 
     // If we play again, start at the beginning of the buffer.
-    stream->handle[0].bufferPointer = 0;
+    handles[0].bufferPointer = 0;
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
     buffer1 = NULL;
     bufferSize1 = 0;
 
     result = buffer->Stop();
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to stop capture buffer (%s): %s",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
-    dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
-    dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
+    dsBufferSize = stream_.bufferSize * stream_.nDeviceChannels[1];
+    dsBufferSize *= formatBytes(stream_.deviceFormat[1]) * stream_.nBuffers;
 
     // Lock the buffer and clear it so that if we start to play again,
     // we won't have old data playing.
     result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to lock capture buffer (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
@@ -5168,50 +6197,51 @@ void RtAudio :: stopStream(int streamId)
     // Unlock the DS buffer
     result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to unlock capture buffer (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
     // If we start recording again, we must begin at beginning of buffer.
-    stream->handle[1].bufferPointer = 0;
+    handles[1].bufferPointer = 0;
   }
-  stream->state = STREAM_STOPPED;
 
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: abortStream(int streamId)
+void RtApiDs :: abortStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-  MUTEX_LOCK(&stream->mutex);
-
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
   HRESULT result;
   long dsBufferSize;
   LPVOID audioPtr;
   DWORD dataLen;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
+  DsHandle *handles = (DsHandle *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
     result = buffer->Stop();
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s",
-              devices[stream->device[0]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to stop buffer (%s): %s",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
-    dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0];
-    dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
+    dsBufferSize = stream_.bufferSize * stream_.nDeviceChannels[0];
+    dsBufferSize *= formatBytes(stream_.deviceFormat[0]) * stream_.nBuffers;
 
     // Lock the buffer and clear it so that if we start to play again,
     // we won't have old data playing.
     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
-              devices[stream->device[0]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to lock buffer (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
@@ -5221,36 +6251,36 @@ void RtAudio :: abortStream(int streamId)
     // Unlock the DS buffer
     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.",
-              devices[stream->device[0]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to unlock buffer (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
     // If we start playing again, we must begin at beginning of buffer.
-    stream->handle[0].bufferPointer = 0;
+    handles[0].bufferPointer = 0;
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
     audioPtr = NULL;
     dataLen = 0;
 
     result = buffer->Stop();
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to stop capture buffer (%s): %s",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
-    dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
-    dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
+    dsBufferSize = stream_.bufferSize * stream_.nDeviceChannels[1];
+    dsBufferSize *= formatBytes(stream_.deviceFormat[1]) * stream_.nBuffers;
 
     // Lock the buffer and clear it so that if we start to play again,
     // we won't have old data playing.
     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to lock capture buffer (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
@@ -5260,112 +6290,108 @@ void RtAudio :: abortStream(int streamId)
     // Unlock the DS buffer
     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to unlock capture buffer (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
     // If we start recording again, we must begin at beginning of buffer.
-    stream->handle[1].bufferPointer = 0;
+    handles[1].bufferPointer = 0;
   }
-  stream->state = STREAM_STOPPED;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-int RtAudio :: streamWillBlock(int streamId)
+int RtApiDs :: streamWillBlock()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return 0;
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
   int channels;
   int frames = 0;
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
-
   HRESULT result;
   DWORD currentPos, safePos;
   channels = 1;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
+  DsHandle *handles = (DsHandle *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
 
-    LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
-    UINT nextWritePos = stream->handle[0].bufferPointer;
-    channels = stream->nDeviceChannels[0];
-    DWORD dsBufferSize = stream->bufferSize * channels;
-    dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
+    LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
+    UINT nextWritePos = handles[0].bufferPointer;
+    channels = stream_.nDeviceChannels[0];
+    DWORD dsBufferSize = stream_.bufferSize * channels;
+    dsBufferSize *= formatBytes(stream_.deviceFormat[0]) * stream_.nBuffers;
 
     // Find out where the read and "safe write" pointers are.
     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
-              devices[stream->device[0]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
     if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
     frames = currentPos - nextWritePos;
-    frames /= channels * formatBytes(stream->deviceFormat[0]);
+    frames /= channels * formatBytes(stream_.deviceFormat[0]);
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
 
-    LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
-    UINT nextReadPos = stream->handle[1].bufferPointer;
-    channels = stream->nDeviceChannels[1];
-    DWORD dsBufferSize = stream->bufferSize * channels;
-    dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
+    LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
+    UINT nextReadPos = handles[1].bufferPointer;
+    channels = stream_.nDeviceChannels[1];
+    DWORD dsBufferSize = stream_.bufferSize * channels;
+    dsBufferSize *= formatBytes(stream_.deviceFormat[1]) * stream_.nBuffers;
 
     // Find out where the write and "safe read" pointers are.
     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to get current capture position (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
     if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
 
-    if (stream->mode == DUPLEX ) {
+    if (stream_.mode == DUPLEX ) {
       // Take largest value of the two.
       int temp = safePos - nextReadPos;
-      temp /= channels * formatBytes(stream->deviceFormat[1]);
+      temp /= channels * formatBytes(stream_.deviceFormat[1]);
       frames = ( temp > frames ) ? temp : frames;
     }
     else {
       frames = safePos - nextReadPos;
-      frames /= channels * formatBytes(stream->deviceFormat[1]);
+      frames /= channels * formatBytes(stream_.deviceFormat[1]);
     }
   }
 
-  frames = stream->bufferSize - frames;
+  frames = stream_.bufferSize - frames;
   if (frames < 0) frames = 0;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
   return frames;
 }
 
-void RtAudio :: tickStream(int streamId)
+void RtApiDs :: tickStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
 
   int stopStream = 0;
-  if (stream->state == STREAM_STOPPED) {
-    if (stream->callbackInfo.usingCallback) Sleep(50); // sleep 50 milliseconds
+  if (stream_.state == STREAM_STOPPED) {
+    if (stream_.callbackInfo.usingCallback) Sleep(50); // sleep 50 milliseconds
     return;
   }
-  else if (stream->callbackInfo.usingCallback) {
-    RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
-    stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
+  else if (stream_.callbackInfo.usingCallback) {
+    RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
+    stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData);
   }
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
   // The state might change while waiting on a mutex.
-  if (stream->state == STREAM_STOPPED) {
-    MUTEX_UNLOCK(&stream->mutex);
+  if (stream_.state == STREAM_STOPPED) {
+    MUTEX_UNLOCK(&stream_.mutex);
     return;
   }
 
@@ -5377,32 +6403,33 @@ void RtAudio :: tickStream(int streamId)
   DWORD bufferSize2 = 0;
   char *buffer;
   long buffer_bytes;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
+  DsHandle *handles = (DsHandle *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
 
     // Setup parameters and do buffer conversion if necessary.
-    if (stream->doConvertBuffer[0]) {
-      convertStreamBuffer(stream, OUTPUT);
-      buffer = stream->deviceBuffer;
-      buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
-      buffer_bytes *= formatBytes(stream->deviceFormat[0]);
+    if (stream_.doConvertBuffer[0]) {
+      convertStreamBuffer(OUTPUT);
+      buffer = stream_.deviceBuffer;
+      buffer_bytes = stream_.bufferSize * stream_.nDeviceChannels[0];
+      buffer_bytes *= formatBytes(stream_.deviceFormat[0]);
     }
     else {
-      buffer = stream->userBuffer;
-      buffer_bytes = stream->bufferSize * stream->nUserChannels[0];
-      buffer_bytes *= formatBytes(stream->userFormat);
+      buffer = stream_.userBuffer;
+      buffer_bytes = stream_.bufferSize * stream_.nUserChannels[0];
+      buffer_bytes *= formatBytes(stream_.userFormat);
     }
 
     // No byte swapping necessary in DirectSound implementation.
 
-    LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
-    UINT nextWritePos = stream->handle[0].bufferPointer;
-    DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
+    LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
+    UINT nextWritePos = handles[0].bufferPointer;
+    DWORD dsBufferSize = buffer_bytes * stream_.nBuffers;
 
     // Find out where the read and "safe write" pointers are.
     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
-              devices[stream->device[0]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
@@ -5420,16 +6447,16 @@ void RtAudio :: tickStream(int streamId)
       // A "fudgefactor" less than 1 is used because it was found
       // that sleeping too long was MUCH worse than sleeping for
       // several shorter periods.
-      float millis = (endWrite - currentPos) * 900.0;
-      millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
+      double millis = (endWrite - currentPos) * 900.0;
+      millis /= ( formatBytes(stream_.deviceFormat[0]) * stream_.sampleRate);
       if ( millis < 1.0 ) millis = 1.0;
       Sleep( (DWORD) millis );
 
       // Wake up, find out where we are now
       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
       if ( FAILED(result) ) {
-        sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
-              devices[stream->device[0]].name, getErrorString(result));
+        sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
         error(RtError::DRIVER_ERROR);
       }
       if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
@@ -5439,8 +6466,8 @@ void RtAudio :: tickStream(int streamId)
     result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
                              &bufferSize1, &buffer2, &bufferSize2, 0);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
-              devices[stream->device[0]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to lock buffer during playback (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
@@ -5451,37 +6478,37 @@ void RtAudio :: tickStream(int streamId)
     // Update our buffer offset and unlock sound buffer
     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
-              devices[stream->device[0]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to unlock buffer during playback (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
     nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
-    stream->handle[0].bufferPointer = nextWritePos;
+    handles[0].bufferPointer = nextWritePos;
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
 
     // Setup parameters.
-    if (stream->doConvertBuffer[1]) {
-      buffer = stream->deviceBuffer;
-      buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1];
-      buffer_bytes *= formatBytes(stream->deviceFormat[1]);
+    if (stream_.doConvertBuffer[1]) {
+      buffer = stream_.deviceBuffer;
+      buffer_bytes = stream_.bufferSize * stream_.nDeviceChannels[1];
+      buffer_bytes *= formatBytes(stream_.deviceFormat[1]);
     }
     else {
-      buffer = stream->userBuffer;
-      buffer_bytes = stream->bufferSize * stream->nUserChannels[1];
-      buffer_bytes *= formatBytes(stream->userFormat);
+      buffer = stream_.userBuffer;
+      buffer_bytes = stream_.bufferSize * stream_.nUserChannels[1];
+      buffer_bytes *= formatBytes(stream_.userFormat);
     }
 
-    LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
-    UINT nextReadPos = stream->handle[1].bufferPointer;
-    DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
+    LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
+    UINT nextReadPos = handles[1].bufferPointer;
+    DWORD dsBufferSize = buffer_bytes * stream_.nBuffers;
 
     // Find out where the write and "safe read" pointers are.
     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to get current capture position (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
@@ -5491,16 +6518,16 @@ void RtAudio :: tickStream(int streamId)
     // Check whether the entire write region is behind the play pointer.
     while ( safePos < endRead ) {
       // See comments for playback.
-      float millis = (endRead - safePos) * 900.0;
-      millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate);
+      double millis = (endRead - safePos) * 900.0;
+      millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.sampleRate);
       if ( millis < 1.0 ) millis = 1.0;
       Sleep( (DWORD) millis );
 
       // Wake up, find out where we are now
       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
       if ( FAILED(result) ) {
-        sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
-                devices[stream->device[1]].name, getErrorString(result));
+        sprintf(message_, "RtApiDs: Unable to get current capture position (%s): %s.",
+                devices_[stream_.device[1]].name.c_str(), getErrorString(result));
         error(RtError::DRIVER_ERROR);
       }
       
@@ -5511,8 +6538,8 @@ void RtAudio :: tickStream(int streamId)
     result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
                              &bufferSize1, &buffer2, &bufferSize2, 0);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to lock buffer during capture (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
 
@@ -5524,23 +6551,23 @@ void RtAudio :: tickStream(int streamId)
     nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
     if ( FAILED(result) ) {
-      sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.",
-              devices[stream->device[1]].name, getErrorString(result));
+      sprintf(message_, "RtApiDs: Unable to unlock buffer during capture (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), getErrorString(result));
       error(RtError::DRIVER_ERROR);
     }
-    stream->handle[1].bufferPointer = nextReadPos;
+    handles[1].bufferPointer = nextReadPos;
 
     // No byte swapping necessary in DirectSound implementation.
 
     // Do buffer conversion if necessary.
-    if (stream->doConvertBuffer[1])
-      convertStreamBuffer(stream, INPUT);
+    if (stream_.doConvertBuffer[1])
+      convertStreamBuffer(INPUT);
   }
 
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 
-  if (stream->callbackInfo.usingCallback && stopStream)
-    this->stopStream(streamId);
+  if (stream_.callbackInfo.usingCallback && stopStream)
+    this->stopStream();
 }
 
 // Definitions for utility functions and callbacks
@@ -5548,18 +6575,17 @@ void RtAudio :: tickStream(int streamId)
 
 extern "C" unsigned __stdcall callbackHandler(void *ptr)
 {
-  CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
-  RtAudio *object = (RtAudio *) info->object;
-  int stream = info->streamId;
+  CallbackInfo *info = (CallbackInfo *) ptr;
+  RtApiDs *object = (RtApiDs *) info->object;
   bool *usingCallback = &info->usingCallback;
 
   while ( *usingCallback ) {
     try {
-      object->tickStream(stream);
+      object->tickStream();
     }
     catch (RtError &exception) {
-      fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
-              exception.getMessage());
+      fprintf(stderr, "\nRtApiDs: callback thread error (%s) ... closing thread.\n\n",
+              exception.getMessageString());
       break;
     }
   }
@@ -5568,37 +6594,6 @@ extern "C" unsigned __stdcall callbackHandler(void *ptr)
   return 0;
 }
 
-void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
-{
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
-  if ( info->usingCallback ) {
-    sprintf(message, "RtAudio: A callback is already set for this stream!");
-    error(RtError::WARNING);
-    return;
-  }
-
-  info->callback = (void *) callback;
-  info->userData = userData;
-  info->usingCallback = true;
-  info->object = (void *) this;
-  info->streamId = streamId;
-
-  unsigned thread_id;
-  info->thread = _beginthreadex(NULL, 0, &callbackHandler,
-                                &stream->callbackInfo, 0, &thread_id);
-  if (info->thread == 0) {
-    info->usingCallback = false;
-    sprintf(message, "RtAudio: error starting callback thread!");
-    error(RtError::THREAD_ERROR);
-  }
-
-  // When spawning multiple threads in quick succession, it appears to be
-  // necessary to wait a bit for each to initialize ... another windoism!
-  Sleep(1);
-}
-
 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
                                          LPCSTR lpcstrDescription,
                                          LPCSTR lpcstrModule,
@@ -5742,133 +6737,174 @@ static char* getErrorString(int code)
 }
 
 //******************** End of __WINDOWS_DS__ *********************//
+#endif
 
-#elif defined(__IRIX_AL__) // SGI's AL API for IRIX
+#if defined(__IRIX_AL__) // SGI's AL API for IRIX
 
+#include <dmedia/audio.h>
 #include <unistd.h>
 #include <errno.h>
 
-void RtAudio :: initialize(void)
+extern "C" void *callbackHandler(void * ptr);
+
+RtApiAl :: RtApiAl()
+{
+  this->initialize();
+
+  if (nDevices_ <= 0) {
+    sprintf(message_, "RtApiAl: no Irix AL audio devices found!");
+    error(RtError::NO_DEVICES_FOUND);
+ }
+}
+
+RtApiAl :: ~RtApiAl()
+{
+  // The subclass destructor gets called before the base class
+  // destructor, so close any existing streams before deallocating
+  // apiDeviceId memory.
+  if ( stream_.mode != UNINITIALIZED ) closeStream();
+
+  // Free our allocated apiDeviceId memory.
+  long *id;
+  for ( unsigned int i=0; i<devices_.size(); i++ ) {
+    id = (long *) devices_[i].apiDeviceId;
+    if (id) free(id);
+  }
+}
+
+void RtApiAl :: initialize(void)
 {
   // Count cards and devices
-  nDevices = 0;
+  nDevices_ = 0;
 
   // Determine the total number of input and output devices.
-  nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
-  if (nDevices < 0) {
-    sprintf(message, "RtAudio: AL error counting devices: %s.",
+  nDevices_ = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
+  if (nDevices_ < 0) {
+    sprintf(message_, "RtApiAl: error counting devices: %s.",
             alGetErrorString(oserror()));
     error(RtError::DRIVER_ERROR);
   }
 
-  if (nDevices <= 0) return;
+  if (nDevices_ <= 0) return;
 
-  ALvalue *vls = (ALvalue *) new ALvalue[nDevices];
+  ALvalue *vls = (ALvalue *) new ALvalue[nDevices_];
 
-  //  Allocate the RTAUDIO_DEVICE structures.
-  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
-  if (devices == NULL) {
-    sprintf(message, "RtAudio: memory allocation error!");
-    error(RtError::MEMORY_ERROR);
-  }
-
-  // Write device ascii identifiers and resource ids to device info
-  // structure.
-  char name[32];
+  // Create our list of devices and write their ascii identifiers and resource ids.
+  char name[64];
   int outs, ins, i;
   ALpv pvs[1];
   pvs[0].param = AL_NAME;
   pvs[0].value.ptr = name;
-  pvs[0].sizeIn = 32;
+  pvs[0].sizeIn = 64;
+  RtApiDevice device;
+  long *id;
 
-  outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices, 0, 0);
+  outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices_, 0, 0);
   if (outs < 0) {
-    sprintf(message, "RtAudio: AL error getting output devices: %s.",
+    delete [] vls;
+    sprintf(message_, "RtApiAl: error getting output devices: %s.",
             alGetErrorString(oserror()));
     error(RtError::DRIVER_ERROR);
   }
 
   for (i=0; i<outs; i++) {
     if (alGetParams(vls[i].i, pvs, 1) < 0) {
-      sprintf(message, "RtAudio: AL error querying output devices: %s.",
+      delete [] vls;
+      sprintf(message_, "RtApiAl: error querying output devices: %s.",
               alGetErrorString(oserror()));
       error(RtError::DRIVER_ERROR);
     }
-    strncpy(devices[i].name, name, 32);
-    devices[i].id[0] = vls[i].i;
+    device.name.erase();
+    device.name.append( (const char *)name, strlen(name)+1);
+    devices_.push_back(device);
+    id = (long *) calloc(2, sizeof(long));
+    id[0] = vls[i].i;
+    devices_[i].apiDeviceId = (void *) id;
   }
 
-  ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs, 0, 0);
+  ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices_-outs, 0, 0);
   if (ins < 0) {
-    sprintf(message, "RtAudio: AL error getting input devices: %s.",
+    delete [] vls;
+    sprintf(message_, "RtApiAl: error getting input devices: %s.",
             alGetErrorString(oserror()));
     error(RtError::DRIVER_ERROR);
   }
 
   for (i=outs; i<ins+outs; i++) {
     if (alGetParams(vls[i].i, pvs, 1) < 0) {
-      sprintf(message, "RtAudio: AL error querying input devices: %s.",
+      delete [] vls;
+      sprintf(message_, "RtApiAl: error querying input devices: %s.",
               alGetErrorString(oserror()));
       error(RtError::DRIVER_ERROR);
     }
-    strncpy(devices[i].name, name, 32);
-    devices[i].id[1] = vls[i].i;
+    device.name.erase();
+    device.name.append( (const char *)name, strlen(name)+1);
+    devices_.push_back(device);
+    id = (long *) calloc(2, sizeof(long));
+    id[1] = vls[i].i;
+    devices_[i].apiDeviceId = (void *) id;
   }
 
   delete [] vls;
-
-  return;
 }
 
-int RtAudio :: getDefaultInputDevice(void)
+int RtApiAl :: getDefaultInputDevice(void)
 {
   ALvalue value;
+  long *id;
   int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
   if (result < 0) {
-    sprintf(message, "RtAudio: AL error getting default input device id: %s.",
+    sprintf(message_, "RtApiAl: error getting default input device id: %s.",
             alGetErrorString(oserror()));
     error(RtError::WARNING);
   }
   else {
-    for ( int i=0; i<nDevices; i++ )
-      if ( devices[i].id[1] == value.i ) return i;
+    for ( unsigned int i=0; i<devices_.size(); i++ ) {
+      id = (long *) devices_[i].apiDeviceId;
+      if ( id[1] == value.i ) return i;
+    }
   }
 
   return 0;
 }
 
-int RtAudio :: getDefaultOutputDevice(void)
+int RtApiAl :: getDefaultOutputDevice(void)
 {
   ALvalue value;
+  long *id;
   int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
   if (result < 0) {
-    sprintf(message, "RtAudio: AL error getting default output device id: %s.",
+    sprintf(message_, "RtApiAl: error getting default output device id: %s.",
             alGetErrorString(oserror()));
     error(RtError::WARNING);
   }
   else {
-    for ( int i=0; i<nDevices; i++ )
-      if ( devices[i].id[0] == value.i ) return i;
+    for ( unsigned int i=0; i<devices_.size(); i++ ) {
+      id = (long *) devices_[i].apiDeviceId;
+      if ( id[0] == value.i ) return i;
+    }
   }
 
   return 0;
 }
 
-void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
+void RtApiAl :: probeDeviceInfo(RtApiDevice *info)
 {
-  int resource, result, i;
+  int result;
+  long resource;
   ALvalue value;
   ALparamInfo pinfo;
 
   // Get output resource ID if it exists.
-  resource = info->id[0];
+  long *id = (long *) info->apiDeviceId;
+  resource = id[0];
   if (resource > 0) {
 
     // Probe output device parameters.
     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
     if (result < 0) {
-      sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
-              info->name, alGetErrorString(oserror()));
+      sprintf(message_, "RtApiAl: error getting device (%s) channels: %s.",
+              info->name.c_str(), alGetErrorString(oserror()));
       error(RtError::WARNING);
     }
     else {
@@ -5878,33 +6914,31 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
 
     result = alGetParamInfo(resource, AL_RATE, &pinfo);
     if (result < 0) {
-      sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
-              info->name, alGetErrorString(oserror()));
+      sprintf(message_, "RtApiAl: error getting device (%s) rates: %s.",
+              info->name.c_str(), alGetErrorString(oserror()));
       error(RtError::WARNING);
     }
     else {
-      info->nSampleRates = 0;
-      for (i=0; i<MAX_SAMPLE_RATES; i++) {
-        if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
-          info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
-          info->nSampleRates++;
-        }
+      info->sampleRates.clear();
+      for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) {
+        if ( SAMPLE_RATES[k] >= pinfo.min.i && SAMPLE_RATES[k] <= pinfo.max.i )
+          info->sampleRates.push_back( SAMPLE_RATES[k] );
       }
     }
 
     // The AL library supports all our formats, except 24-bit and 32-bit ints.
-    info->nativeFormats = (RTAUDIO_FORMAT) 51;
+    info->nativeFormats = (RtAudioFormat) 51;
   }
 
   // Now get input resource ID if it exists.
-  resource = info->id[1];
+  resource = id[1];
   if (resource > 0) {
 
     // Probe input device parameters.
     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
     if (result < 0) {
-      sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
-              info->name, alGetErrorString(oserror()));
+      sprintf(message_, "RtApiAl: error getting device (%s) channels: %s.",
+              info->name.c_str(), alGetErrorString(oserror()));
       error(RtError::WARNING);
     }
     else {
@@ -5914,8 +6948,8 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
 
     result = alGetParamInfo(resource, AL_RATE, &pinfo);
     if (result < 0) {
-      sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
-              info->name, alGetErrorString(oserror()));
+      sprintf(message_, "RtApiAl: error getting device (%s) rates: %s.",
+              info->name.c_str(), alGetErrorString(oserror()));
       error(RtError::WARNING);
     }
     else {
@@ -5923,22 +6957,20 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
       // overwrite the rates determined for the output device.  Since
       // the input device is most likely to be more limited than the
       // output device, this is ok.
-      info->nSampleRates = 0;
-      for (i=0; i<MAX_SAMPLE_RATES; i++) {
-        if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
-          info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
-          info->nSampleRates++;
-        }
+      info->sampleRates.clear();
+      for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) {
+        if ( SAMPLE_RATES[k] >= pinfo.min.i && SAMPLE_RATES[k] <= pinfo.max.i )
+          info->sampleRates.push_back( SAMPLE_RATES[k] );
       }
     }
 
     // The AL library supports all our formats, except 24-bit and 32-bit ints.
-    info->nativeFormats = (RTAUDIO_FORMAT) 51;
+    info->nativeFormats = (RtAudioFormat) 51;
   }
 
   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
     return;
-  if ( info->nSampleRates == 0 )
+  if ( info->sampleRates.size() == 0 )
     return;
 
   // Determine duplex status.
@@ -5959,20 +6991,21 @@ void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
   return;
 }
 
-bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
-                                STREAM_MODE mode, int channels, 
-                                int sampleRate, RTAUDIO_FORMAT format,
+bool RtApiAl :: probeDeviceOpen(int device, StreamMode mode, int channels, 
+                                int sampleRate, RtAudioFormat format,
                                 int *bufferSize, int numberOfBuffers)
 {
-  int result, resource, nBuffers;
+  int result, nBuffers;
+  long resource;
   ALconfig al_config;
   ALport port;
   ALpv pvs[2];
+  long *id = (long *) devices_[device].apiDeviceId;
 
   // Get a new ALconfig structure.
   al_config = alNewConfig();
   if ( !al_config ) {
-    sprintf(message,"RtAudio: can't get AL config: %s.",
+    sprintf(message_,"RtApiAl: can't get AL config: %s.",
             alGetErrorString(oserror()));
     error(RtError::WARNING);
     return FAILURE;
@@ -5981,7 +7014,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   // Set the channels.
   result = alSetChannels(al_config, channels);
   if ( result < 0 ) {
-    sprintf(message,"RtAudio: can't set %d channels in AL config: %s.",
+    alFreeConfig(al_config);
+    sprintf(message_,"RtApiAl: can't set %d channels in AL config: %s.",
             channels, alGetErrorString(oserror()));
     error(RtError::WARNING);
     return FAILURE;
@@ -6002,7 +7036,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     buffer_size = alGetQueueSize(al_config);
     result = alSetQueueSize(al_config, buffer_size);
     if ( result < 0 ) {
-      sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.",
+      alFreeConfig(al_config);
+      sprintf(message_,"RtApiAl: can't set buffer size (%ld) in AL config: %s.",
               buffer_size, alGetErrorString(oserror()));
       error(RtError::WARNING);
       return FAILURE;
@@ -6011,8 +7046,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
   }
 
   // Set the data format.
-  stream->userFormat = format;
-  stream->deviceFormat[mode] = format;
+  stream_.userFormat = format;
+  stream_.deviceFormat[mode] = format;
   if (format == RTAUDIO_SINT8) {
     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
     result = alSetWidth(al_config, AL_SAMPLE_8);
@@ -6026,13 +7061,13 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     // The AL library uses the lower 3 bytes, so we'll need to do our
     // own conversion.
     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
-    stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
   }
   else if (format == RTAUDIO_SINT32) {
     // The AL library doesn't seem to support the 32-bit integer
     // format, so we'll need to do our own conversion.
     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
-    stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
+    stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
   }
   else if (format == RTAUDIO_FLOAT32)
     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
@@ -6040,7 +7075,8 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
 
   if ( result == -1 ) {
-    sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.",
+    alFreeConfig(al_config);
+    sprintf(message_,"RtApiAl: error setting sample format in AL config: %s.",
             alGetErrorString(oserror()));
     error(RtError::WARNING);
     return FAILURE;
@@ -6052,19 +7088,21 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     if (device == 0)
       resource = AL_DEFAULT_OUTPUT;
     else
-      resource = devices[device].id[0];
+      resource = id[0];
     result = alSetDevice(al_config, resource);
     if ( result == -1 ) {
-      sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
-              devices[device].name, alGetErrorString(oserror()));
+      alFreeConfig(al_config);
+      sprintf(message_,"RtApiAl: error setting device (%s) in AL config: %s.",
+              devices_[device].name.c_str(), alGetErrorString(oserror()));
       error(RtError::WARNING);
       return FAILURE;
     }
 
     // Open the port.
-    port = alOpenPort("RtAudio Output Port", "w", al_config);
+    port = alOpenPort("RtApiAl Output Port", "w", al_config);
     if( !port ) {
-      sprintf(message,"RtAudio: AL error opening output port: %s.",
+      alFreeConfig(al_config);
+      sprintf(message_,"RtApiAl: error opening output port: %s.",
               alGetErrorString(oserror()));
       error(RtError::WARNING);
       return FAILURE;
@@ -6078,8 +7116,9 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = alSetParams(resource, pvs, 2);
     if ( result < 0 ) {
       alClosePort(port);
-      sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
-              sampleRate, devices[device].name, alGetErrorString(oserror()));
+      alFreeConfig(al_config);
+      sprintf(message_,"RtApiAl: error setting sample rate (%d) for device (%s): %s.",
+              sampleRate, devices_[device].name.c_str(), alGetErrorString(oserror()));
       error(RtError::WARNING);
       return FAILURE;
     }
@@ -6090,19 +7129,21 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     if (device == 0)
       resource = AL_DEFAULT_INPUT;
     else
-      resource = devices[device].id[1];
+      resource = id[1];
     result = alSetDevice(al_config, resource);
     if ( result == -1 ) {
-      sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
-              devices[device].name, alGetErrorString(oserror()));
+      alFreeConfig(al_config);
+      sprintf(message_,"RtApiAl: error setting device (%s) in AL config: %s.",
+              devices_[device].name.c_str(), alGetErrorString(oserror()));
       error(RtError::WARNING);
       return FAILURE;
     }
 
     // Open the port.
-    port = alOpenPort("RtAudio Output Port", "r", al_config);
+    port = alOpenPort("RtApiAl Input Port", "r", al_config);
     if( !port ) {
-      sprintf(message,"RtAudio: AL error opening input port: %s.",
+      alFreeConfig(al_config);
+      sprintf(message_,"RtApiAl: error opening input port: %s.",
               alGetErrorString(oserror()));
       error(RtError::WARNING);
       return FAILURE;
@@ -6116,8 +7157,9 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
     result = alSetParams(resource, pvs, 2);
     if ( result < 0 ) {
       alClosePort(port);
-      sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
-              sampleRate, devices[device].name, alGetErrorString(oserror()));
+      alFreeConfig(al_config);
+      sprintf(message_,"RtApiAl: error setting sample rate (%d) for device (%s): %s.",
+              sampleRate, devices_[device].name.c_str(), alGetErrorString(oserror()));
       error(RtError::WARNING);
       return FAILURE;
     }
@@ -6125,324 +7167,407 @@ bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
 
   alFreeConfig(al_config);
 
-  stream->nUserChannels[mode] = channels;
-  stream->nDeviceChannels[mode] = channels;
+  stream_.nUserChannels[mode] = channels;
+  stream_.nDeviceChannels[mode] = channels;
+
+  // Save stream handle.
+  ALport *handle = (ALport *) stream_.apiHandle;
+  if ( handle == 0 ) {
+    handle = (ALport *) calloc(2, sizeof(ALport));
+    if ( handle == NULL ) {
+      sprintf(message_, "RtApiAl: Irix Al error allocating handle memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
+    stream_.apiHandle = (void *) handle;
+    handle[0] = 0;
+    handle[1] = 0;
+  }
+  handle[mode] = port;
 
-  // Set handle and flags for buffer conversion
-  stream->handle[mode] = port;
-  stream->doConvertBuffer[mode] = false;
-  if (stream->userFormat != stream->deviceFormat[mode])
-    stream->doConvertBuffer[mode] = true;
+  // Set flags for buffer conversion
+  stream_.doConvertBuffer[mode] = false;
+  if (stream_.userFormat != stream_.deviceFormat[mode])
+    stream_.doConvertBuffer[mode] = true;
 
   // Allocate necessary internal buffers
-  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
+  if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
 
     long buffer_bytes;
-    if (stream->nUserChannels[0] >= stream->nUserChannels[1])
-      buffer_bytes = stream->nUserChannels[0];
+    if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
+      buffer_bytes = stream_.nUserChannels[0];
     else
-      buffer_bytes = stream->nUserChannels[1];
-
-    buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
-    if (stream->userBuffer) free(stream->userBuffer);
-    stream->userBuffer = (char *) calloc(buffer_bytes, 1);
-    if (stream->userBuffer == NULL)
-      goto memory_error;
+      buffer_bytes = stream_.nUserChannels[1];
+
+    buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
+    if (stream_.userBuffer) free(stream_.userBuffer);
+    stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
+    if (stream_.userBuffer == NULL) {
+      sprintf(message_, "RtApiAl: error allocating user buffer memory (%s).",
+              devices_[device].name.c_str());
+      goto error;
+    }
   }
 
-  if ( stream->doConvertBuffer[mode] ) {
+  if ( stream_.doConvertBuffer[mode] ) {
 
     long buffer_bytes;
     bool makeBuffer = true;
     if ( mode == OUTPUT )
-      buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
     else { // mode == INPUT
-      buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
-      if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
-        long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
+      buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+        long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
         if ( buffer_bytes < bytes_out ) makeBuffer = false;
       }
     }
 
     if ( makeBuffer ) {
       buffer_bytes *= *bufferSize;
-      if (stream->deviceBuffer) free(stream->deviceBuffer);
-      stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
-      if (stream->deviceBuffer == NULL)
-        goto memory_error;
+      if (stream_.deviceBuffer) free(stream_.deviceBuffer);
+      stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
+      if (stream_.deviceBuffer == NULL) {
+        sprintf(message_, "RtApiAl: error allocating device buffer memory (%s).",
+                devices_[device].name.c_str());
+        goto error;
+      }
     }
   }
 
-  stream->device[mode] = device;
-  stream->state = STREAM_STOPPED;
-  if ( stream->mode == OUTPUT && mode == INPUT )
+  stream_.device[mode] = device;
+  stream_.state = STREAM_STOPPED;
+  if ( stream_.mode == OUTPUT && mode == INPUT )
     // We had already set up an output stream.
-    stream->mode = DUPLEX;
+    stream_.mode = DUPLEX;
   else
-    stream->mode = mode;
-  stream->nBuffers = nBuffers;
-  stream->bufferSize = *bufferSize;
-  stream->sampleRate = sampleRate;
+    stream_.mode = mode;
+  stream_.nBuffers = nBuffers;
+  stream_.bufferSize = *bufferSize;
+  stream_.sampleRate = sampleRate;
 
   return SUCCESS;
 
memory_error:
-  if (stream->handle[0]) {
-    alClosePort(stream->handle[0]);
-    stream->handle[0] = 0;
-  }
-  if (stream->handle[1]) {
-    alClosePort(stream->handle[1]);
-    stream->handle[1] = 0;
+ error:
+  if (handle) {
+    if (handle[0])
+      alClosePort(handle[0]);
+    if (handle[1])
+      alClosePort(handle[1]);
+    free(handle);
+    stream_.apiHandle = 0;
   }
-  if (stream->userBuffer) {
-    free(stream->userBuffer);
-    stream->userBuffer = 0;
+
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
   }
-  sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).",
-          devices[device].name);
+
   error(RtError::WARNING);
   return FAILURE;
 }
 
-void RtAudio :: closeStream(int streamId)
+void RtApiAl :: closeStream()
 {
   // We don't want an exception to be thrown here because this
   // function is called by our class destructor.  So, do our own
   // streamId check.
-  if ( streams.find( streamId ) == streams.end() ) {
-    sprintf(message, "RtAudio: invalid stream identifier!");
+  if ( stream_.mode == UNINITIALIZED ) {
+    sprintf(message_, "RtApiAl::closeStream(): no open stream to close!");
     error(RtError::WARNING);
     return;
   }
 
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
-
-  if (stream->callbackInfo.usingCallback) {
-    pthread_cancel(stream->callbackInfo.thread);
-    pthread_join(stream->callbackInfo.thread, NULL);
+  ALport *handle = (ALport *) stream_.apiHandle;
+  if (stream_.state == STREAM_RUNNING) {
+    int buffer_size = stream_.bufferSize * stream_.nBuffers;
+    if (stream_.mode == OUTPUT || stream_.mode == DUPLEX)
+      alDiscardFrames(handle[0], buffer_size);
+    if (stream_.mode == INPUT || stream_.mode == DUPLEX)
+      alDiscardFrames(handle[1], buffer_size);
+    stream_.state = STREAM_STOPPED;
   }
 
-  pthread_mutex_destroy(&stream->mutex);
-
-  if (stream->handle[0])
-    alClosePort(stream->handle[0]);
+  if (stream_.callbackInfo.usingCallback) {
+    stream_.callbackInfo.usingCallback = false;
+    pthread_join(stream_.callbackInfo.thread, NULL);
+  }
 
-  if (stream->handle[1])
-    alClosePort(stream->handle[1]);
+  if (handle) {
+    if (handle[0]) alClosePort(handle[0]);
+    if (handle[1]) alClosePort(handle[1]);
+    free(handle);
+    stream_.apiHandle = 0;
+  }
 
-  if (stream->userBuffer)
-    free(stream->userBuffer);
+  if (stream_.userBuffer) {
+    free(stream_.userBuffer);
+    stream_.userBuffer = 0;
+  }
 
-  if (stream->deviceBuffer)
-    free(stream->deviceBuffer);
+  if (stream_.deviceBuffer) {
+    free(stream_.deviceBuffer);
+    stream_.deviceBuffer = 0;
+  }
 
-  free(stream);
-  streams.erase(streamId);
+  stream_.mode = UNINITIALIZED;
 }
 
-void RtAudio :: startStream(int streamId)
+void RtApiAl :: startStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
+  if (stream_.state == STREAM_RUNNING) return;
 
-  if (stream->state == STREAM_RUNNING)
-    return;
+  MUTEX_LOCK(&stream_.mutex);
 
   // The AL port is ready as soon as it is opened.
-  stream->state = STREAM_RUNNING;
+  stream_.state = STREAM_RUNNING;
+
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: stopStream(int streamId)
+void RtApiAl :: stopStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
-  int result;
-  int buffer_size = stream->bufferSize * stream->nBuffers;
+  int result, buffer_size = stream_.bufferSize * stream_.nBuffers;
+  ALport *handle = (ALport *) stream_.apiHandle;
 
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX)
-    alZeroFrames(stream->handle[0], buffer_size);
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX)
+    alZeroFrames(handle[0], buffer_size);
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    result = alDiscardFrames(stream->handle[1], buffer_size);
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    result = alDiscardFrames(handle[1], buffer_size);
     if (result == -1) {
-      sprintf(message, "RtAudio: AL error draining stream device (%s): %s.",
-              devices[stream->device[1]].name, alGetErrorString(oserror()));
+      sprintf(message_, "RtApiAl: error draining stream device (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), alGetErrorString(oserror()));
       error(RtError::DRIVER_ERROR);
     }
   }
-  stream->state = STREAM_STOPPED;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-void RtAudio :: abortStream(int streamId)
+void RtApiAl :: abortStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
-
-  MUTEX_LOCK(&stream->mutex);
+  verifyStream();
+  if (stream_.state == STREAM_STOPPED) return;
 
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
+  // Change the state before the lock to improve shutdown response
+  // when using a callback.
+  stream_.state = STREAM_STOPPED;
+  MUTEX_LOCK(&stream_.mutex);
 
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
+  ALport *handle = (ALport *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
 
-    int buffer_size = stream->bufferSize * stream->nBuffers;
-    int result = alDiscardFrames(stream->handle[0], buffer_size);
+    int buffer_size = stream_.bufferSize * stream_.nBuffers;
+    int result = alDiscardFrames(handle[0], buffer_size);
     if (result == -1) {
-      sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.",
-              devices[stream->device[0]].name, alGetErrorString(oserror()));
+      sprintf(message_, "RtApiAl: error aborting stream device (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), alGetErrorString(oserror()));
       error(RtError::DRIVER_ERROR);
     }
   }
 
   // There is no clear action to take on the input stream, since the
   // port will continue to run in any event.
-  stream->state = STREAM_STOPPED;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
 }
 
-int RtAudio :: streamWillBlock(int streamId)
+int RtApiAl :: streamWillBlock()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
 
-  MUTEX_LOCK(&stream->mutex);
+  if (stream_.state == STREAM_STOPPED) return 0;
 
-  int frames = 0;
-  if (stream->state == STREAM_STOPPED)
-    goto unlock;
+  MUTEX_LOCK(&stream_.mutex);
 
+  int frames = 0;
   int err = 0;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
-    err = alGetFillable(stream->handle[0]);
+  ALport *handle = (ALport *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
+    err = alGetFillable(handle[0]);
     if (err < 0) {
-      sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
-              devices[stream->device[0]].name, alGetErrorString(oserror()));
+      sprintf(message_, "RtApiAl: error getting available frames for stream (%s): %s.",
+              devices_[stream_.device[0]].name.c_str(), alGetErrorString(oserror()));
       error(RtError::DRIVER_ERROR);
     }
   }
 
   frames = err;
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
-    err = alGetFilled(stream->handle[1]);
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
+    err = alGetFilled(handle[1]);
     if (err < 0) {
-      sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
-              devices[stream->device[1]].name, alGetErrorString(oserror()));
+      sprintf(message_, "RtApiAl: error getting available frames for stream (%s): %s.",
+              devices_[stream_.device[1]].name.c_str(), alGetErrorString(oserror()));
       error(RtError::DRIVER_ERROR);
     }
     if (frames > err) frames = err;
   }
 
-  frames = stream->bufferSize - frames;
+  frames = stream_.bufferSize - frames;
   if (frames < 0) frames = 0;
 
- unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
   return frames;
 }
 
-void RtAudio :: tickStream(int streamId)
+void RtApiAl :: tickStream()
 {
-  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
+  verifyStream();
 
   int stopStream = 0;
-  if (stream->state == STREAM_STOPPED) {
-    if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
+  if (stream_.state == STREAM_STOPPED) {
+    if (stream_.callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
     return;
   }
-  else if (stream->callbackInfo.usingCallback) {
-    RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
-    stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
+  else if (stream_.callbackInfo.usingCallback) {
+    RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
+    stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData);
   }
 
-  MUTEX_LOCK(&stream->mutex);
+  MUTEX_LOCK(&stream_.mutex);
 
   // The state might change while waiting on a mutex.
-  if (stream->state == STREAM_STOPPED)
+  if (stream_.state == STREAM_STOPPED)
     goto unlock;
 
   char *buffer;
   int channels;
-  RTAUDIO_FORMAT format;
-  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
+  RtAudioFormat format;
+  ALport *handle = (ALport *) stream_.apiHandle;
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
 
     // Setup parameters and do buffer conversion if necessary.
-    if (stream->doConvertBuffer[0]) {
-      convertStreamBuffer(stream, OUTPUT);
-      buffer = stream->deviceBuffer;
-      channels = stream->nDeviceChannels[0];
-      format = stream->deviceFormat[0];
+    if (stream_.doConvertBuffer[0]) {
+      convertStreamBuffer(OUTPUT);
+      buffer = stream_.deviceBuffer;
+      channels = stream_.nDeviceChannels[0];
+      format = stream_.deviceFormat[0];
     }
     else {
-      buffer = stream->userBuffer;
-      channels = stream->nUserChannels[0];
-      format = stream->userFormat;
+      buffer = stream_.userBuffer;
+      channels = stream_.nUserChannels[0];
+      format = stream_.userFormat;
     }
 
     // Do byte swapping if necessary.
-    if (stream->doByteSwap[0])
-      byteSwapBuffer(buffer, stream->bufferSize * channels, format);
+    if (stream_.doByteSwap[0])
+      byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
 
     // Write interleaved samples to device.
-    alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
+    alWriteFrames(handle[0], buffer, stream_.bufferSize);
   }
 
-  if (stream->mode == INPUT || stream->mode == DUPLEX) {
+  if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
 
     // Setup parameters.
-    if (stream->doConvertBuffer[1]) {
-      buffer = stream->deviceBuffer;
-      channels = stream->nDeviceChannels[1];
-      format = stream->deviceFormat[1];
+    if (stream_.doConvertBuffer[1]) {
+      buffer = stream_.deviceBuffer;
+      channels = stream_.nDeviceChannels[1];
+      format = stream_.deviceFormat[1];
     }
     else {
-      buffer = stream->userBuffer;
-      channels = stream->nUserChannels[1];
-      format = stream->userFormat;
+      buffer = stream_.userBuffer;
+      channels = stream_.nUserChannels[1];
+      format = stream_.userFormat;
     }
 
     // Read interleaved samples from device.
-    alReadFrames(stream->handle[1], buffer, stream->bufferSize);
+    alReadFrames(handle[1], buffer, stream_.bufferSize);
 
     // Do byte swapping if necessary.
-    if (stream->doByteSwap[1])
-      byteSwapBuffer(buffer, stream->bufferSize * channels, format);
+    if (stream_.doByteSwap[1])
+      byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
 
     // Do buffer conversion if necessary.
-    if (stream->doConvertBuffer[1])
-      convertStreamBuffer(stream, INPUT);
+    if (stream_.doConvertBuffer[1])
+      convertStreamBuffer(INPUT);
   }
 
  unlock:
-  MUTEX_UNLOCK(&stream->mutex);
+  MUTEX_UNLOCK(&stream_.mutex);
+
+  if (stream_.callbackInfo.usingCallback && stopStream)
+    this->stopStream();
+}
+
+void RtApiAl :: setStreamCallback(RtAudioCallback callback, void *userData)
+{
+  verifyStream();
+
+  CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+  if ( info->usingCallback ) {
+    sprintf(message_, "RtApiAl: A callback is already set for this stream!");
+    error(RtError::WARNING);
+    return;
+  }
+
+  info->callback = (void *) callback;
+  info->userData = userData;
+  info->usingCallback = true;
+  info->object = (void *) this;
+
+  // Set the thread attributes for joinable and realtime scheduling
+  // priority.  The higher priority will only take affect if the
+  // program is run as root or suid.
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+  pthread_attr_setschedpolicy(&attr, SCHED_RR);
+
+  int err = pthread_create(&info->thread, &attr, callbackHandler, &stream_.callbackInfo);
+  pthread_attr_destroy(&attr);
+  if (err) {
+    info->usingCallback = false;
+    sprintf(message_, "RtApiAl: error starting callback thread!");
+    error(RtError::THREAD_ERROR);
+  }
+}
+
+void RtApiAl :: cancelStreamCallback()
+{
+  verifyStream();
+
+  if (stream_.callbackInfo.usingCallback) {
 
-  if (stream->callbackInfo.usingCallback && stopStream)
-    this->stopStream(streamId);
+    if (stream_.state == STREAM_RUNNING)
+      stopStream();
+
+    MUTEX_LOCK(&stream_.mutex);
+
+    stream_.callbackInfo.usingCallback = false;
+    pthread_join(stream_.callbackInfo.thread, NULL);
+    stream_.callbackInfo.thread = 0;
+    stream_.callbackInfo.callback = NULL;
+    stream_.callbackInfo.userData = NULL;
+
+    MUTEX_UNLOCK(&stream_.mutex);
+  }
 }
 
 extern "C" void *callbackHandler(void *ptr)
 {
-  CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
-  RtAudio *object = (RtAudio *) info->object;
-  int stream = info->streamId;
+  CallbackInfo *info = (CallbackInfo *) ptr;
+  RtApiAl *object = (RtApiAl *) info->object;
   bool *usingCallback = &info->usingCallback;
 
   while ( *usingCallback ) {
-    pthread_testcancel();
     try {
-      object->tickStream(stream);
+      object->tickStream();
     }
     catch (RtError &exception) {
-      fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
-              exception.getMessage());
+      fprintf(stderr, "\nRtApiAl: callback thread error (%s) ... closing thread.\n\n",
+              exception.getMessageString());
       break;
     }
   }
@@ -6451,46 +7576,44 @@ extern "C" void *callbackHandler(void *ptr)
 }
 
 //******************** End of __IRIX_AL__ *********************//
-
 #endif
 
 
 // *************************************************** //
 //
-// Private common (OS-independent) RtAudio methods.
+// Protected common (OS-independent) RtAudio methods.
 //
 // *************************************************** //
 
 // This method can be modified to control the behavior of error
 // message reporting and throwing.
-void RtAudio :: error(RtError::TYPE type)
+void RtApi :: error(RtError::Type type)
 {
   if (type == RtError::WARNING) {
-    fprintf(stderr, "\n%s\n\n", message);
+    fprintf(stderr, "\n%s\n\n", message_);
   }
   else if (type == RtError::DEBUG_WARNING) {
 #if defined(__RTAUDIO_DEBUG__)
-    fprintf(stderr, "\n%s\n\n", message);
+    fprintf(stderr, "\n%s\n\n", message_);
 #endif
   }
   else {
-    fprintf(stderr, "\n%s\n\n", message);
-    throw RtError(message, type);
+#if defined(__RTAUDIO_DEBUG__)
+    fprintf(stderr, "\n%s\n\n", message_);
+#endif
+    throw RtError(std::string(message_), type);
   }
 }
 
-void *RtAudio :: verifyStream(int streamId)
+void RtApi :: verifyStream()
 {
-  // Verify the stream key.
-  if ( streams.find( streamId ) == streams.end() ) {
-    sprintf(message, "RtAudio: invalid stream identifier!");
+  if ( stream_.mode == UNINITIALIZED ) {
+    sprintf(message_, "RtAudio: a stream was not previously opened!");
     error(RtError::INVALID_STREAM);
   }
-
-  return streams[streamId];
 }
 
-void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
+void RtApi :: clearDeviceInfo(RtApiDevice *info)
 {
   // Don't clear the name or DEVICE_ID fields here ... they are
   // typically set prior to a call of this function.
@@ -6502,13 +7625,30 @@ void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
   info->minInputChannels = 0;
   info->minDuplexChannels = 0;
   info->hasDuplexSupport = false;
-  info->nSampleRates = 0;
-  for (int i=0; i<MAX_SAMPLE_RATES; i++)
-    info->sampleRates[i] = 0;
+  info->sampleRates.clear();
   info->nativeFormats = 0;
 }
 
-int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
+void RtApi :: clearStreamInfo()
+{
+  stream_.mode = UNINITIALIZED;
+  stream_.state = STREAM_STOPPED;
+  stream_.sampleRate = 0;
+  stream_.bufferSize = 0;
+  stream_.nBuffers = 0;
+  stream_.userFormat = 0;
+  for ( int i=0; i<2; i++ ) {
+    stream_.device[i] = 0;
+    stream_.doConvertBuffer[i] = false;
+    stream_.deInterleave[i] = false;
+    stream_.doByteSwap[i] = false;
+    stream_.nUserChannels[i] = 0;
+    stream_.nDeviceChannels[i] = 0;
+    stream_.deviceFormat[i] = 0;
+  }
+}
+
+int RtApi :: formatBytes(RtAudioFormat format)
 {
   if (format == RTAUDIO_SINT16)
     return 2;
@@ -6520,42 +7660,42 @@ int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
   else if (format == RTAUDIO_SINT8)
     return 1;
 
-  sprintf(message,"RtAudio: undefined format in formatBytes().");
+  sprintf(message_,"RtApi: undefined format in formatBytes().");
   error(RtError::WARNING);
 
   return 0;
 }
 
-void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
+void RtApi :: convertStreamBuffer( StreamMode mode )
 {
   // This method does format conversion, input/output channel compensation, and
   // data interleaving/deinterleaving.  24-bit integers are assumed to occupy
   // the upper three bytes of a 32-bit integer.
 
   int j, jump_in, jump_out, channels;
-  RTAUDIO_FORMAT format_in, format_out;
+  RtAudioFormat format_in, format_out;
   char *input, *output;
 
   if (mode == INPUT) { // convert device to user buffer
-    input = stream->deviceBuffer;
-    output = stream->userBuffer;
-    jump_in = stream->nDeviceChannels[1];
-    jump_out = stream->nUserChannels[1];
-    format_in = stream->deviceFormat[1];
-    format_out = stream->userFormat;
+    input = stream_.deviceBuffer;
+    output = stream_.userBuffer;
+    jump_in = stream_.nDeviceChannels[1];
+    jump_out = stream_.nUserChannels[1];
+    format_in = stream_.deviceFormat[1];
+    format_out = stream_.userFormat;
   }
   else { // convert user to device buffer
-    input = stream->userBuffer;
-    output = stream->deviceBuffer;
-    jump_in = stream->nUserChannels[0];
-    jump_out = stream->nDeviceChannels[0];
-    format_in = stream->userFormat;
-    format_out = stream->deviceFormat[0];
+    input = stream_.userBuffer;
+    output = stream_.deviceBuffer;
+    jump_in = stream_.nUserChannels[0];
+    jump_out = stream_.nDeviceChannels[0];
+    format_in = stream_.userFormat;
+    format_out = stream_.deviceFormat[0];
 
     // clear our device buffer when in/out duplex device channels are different
-    if ( stream->mode == DUPLEX &&
-         stream->nDeviceChannels[0] != stream->nDeviceChannels[1] )
-      memset(output, 0, stream->bufferSize * jump_out * formatBytes(format_out));
+    if ( stream_.mode == DUPLEX &&
+         stream_.nDeviceChannels[0] != stream_.nDeviceChannels[1] )
+      memset(output, 0, stream_.bufferSize * jump_out * formatBytes(format_out));
   }
 
   channels = (jump_in < jump_out) ? jump_in : jump_out;
@@ -6563,17 +7703,17 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
   // Set up the interleave/deinterleave offsets
   std::vector<int> offset_in(channels);
   std::vector<int> offset_out(channels);
-  if (mode == INPUT && stream->deInterleave[1]) {
+  if (mode == INPUT && stream_.deInterleave[1]) {
     for (int k=0; k<channels; k++) {
-      offset_in[k] = k * stream->bufferSize;
+      offset_in[k] = k * stream_.bufferSize;
       offset_out[k] = k;
       jump_in = 1;
     }
   }
-  else if (mode == OUTPUT && stream->deInterleave[0]) {
+  else if (mode == OUTPUT && stream_.deInterleave[0]) {
     for (int k=0; k<channels; k++) {
       offset_in[k] = k;
-      offset_out[k] = k * stream->bufferSize;
+      offset_out[k] = k * stream_.bufferSize;
       jump_out = 1;
     }
   }
@@ -6585,15 +7725,15 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
   }
 
   if (format_out == RTAUDIO_FLOAT64) {
-    FLOAT64 scale;
-    FLOAT64 *out = (FLOAT64 *)output;
+    Float64 scale;
+    Float64 *out = (Float64 *)output;
 
     if (format_in == RTAUDIO_SINT8) {
       signed char *in = (signed char *)input;
       scale = 1.0 / 128.0;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
+          out[offset_out[j]] = (Float64) in[offset_in[j]];
           out[offset_out[j]] *= scale;
         }
         in += jump_in;
@@ -6601,11 +7741,11 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT16) {
-      INT16 *in = (INT16 *)input;
+      Int16 *in = (Int16 *)input;
       scale = 1.0 / 32768.0;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
+          out[offset_out[j]] = (Float64) in[offset_in[j]];
           out[offset_out[j]] *= scale;
         }
         in += jump_in;
@@ -6613,11 +7753,11 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT24) {
-      INT32 *in = (INT32 *)input;
+      Int32 *in = (Int32 *)input;
       scale = 1.0 / 2147483648.0;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00);
+          out[offset_out[j]] = (Float64) (in[offset_in[j]] & 0xffffff00);
           out[offset_out[j]] *= scale;
         }
         in += jump_in;
@@ -6625,11 +7765,11 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT32) {
-      INT32 *in = (INT32 *)input;
+      Int32 *in = (Int32 *)input;
       scale = 1.0 / 2147483648.0;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
+          out[offset_out[j]] = (Float64) in[offset_in[j]];
           out[offset_out[j]] *= scale;
         }
         in += jump_in;
@@ -6637,10 +7777,10 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_FLOAT32) {
-      FLOAT32 *in = (FLOAT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float32 *in = (Float32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
+          out[offset_out[j]] = (Float64) in[offset_in[j]];
         }
         in += jump_in;
         out += jump_out;
@@ -6648,8 +7788,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
     else if (format_in == RTAUDIO_FLOAT64) {
       // Channel compensation and/or (de)interleaving only.
-      FLOAT64 *in = (FLOAT64 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float64 *in = (Float64 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = in[offset_in[j]];
         }
@@ -6659,15 +7799,15 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
   }
   else if (format_out == RTAUDIO_FLOAT32) {
-    FLOAT32 scale;
-    FLOAT32 *out = (FLOAT32 *)output;
+    Float32 scale;
+    Float32 *out = (Float32 *)output;
 
     if (format_in == RTAUDIO_SINT8) {
       signed char *in = (signed char *)input;
       scale = 1.0 / 128.0;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
+          out[offset_out[j]] = (Float32) in[offset_in[j]];
           out[offset_out[j]] *= scale;
         }
         in += jump_in;
@@ -6675,11 +7815,11 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT16) {
-      INT16 *in = (INT16 *)input;
+      Int16 *in = (Int16 *)input;
       scale = 1.0 / 32768.0;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
+          out[offset_out[j]] = (Float32) in[offset_in[j]];
           out[offset_out[j]] *= scale;
         }
         in += jump_in;
@@ -6687,11 +7827,11 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT24) {
-      INT32 *in = (INT32 *)input;
+      Int32 *in = (Int32 *)input;
       scale = 1.0 / 2147483648.0;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00);
+          out[offset_out[j]] = (Float32) (in[offset_in[j]] & 0xffffff00);
           out[offset_out[j]] *= scale;
         }
         in += jump_in;
@@ -6699,11 +7839,11 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT32) {
-      INT32 *in = (INT32 *)input;
+      Int32 *in = (Int32 *)input;
       scale = 1.0 / 2147483648.0;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
+          out[offset_out[j]] = (Float32) in[offset_in[j]];
           out[offset_out[j]] *= scale;
         }
         in += jump_in;
@@ -6712,8 +7852,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
     else if (format_in == RTAUDIO_FLOAT32) {
       // Channel compensation and/or (de)interleaving only.
-      FLOAT32 *in = (FLOAT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float32 *in = (Float32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = in[offset_in[j]];
         }
@@ -6722,10 +7862,10 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_FLOAT64) {
-      FLOAT64 *in = (FLOAT64 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float64 *in = (Float64 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
+          out[offset_out[j]] = (Float32) in[offset_in[j]];
         }
         in += jump_in;
         out += jump_out;
@@ -6733,12 +7873,12 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
   }
   else if (format_out == RTAUDIO_SINT32) {
-    INT32 *out = (INT32 *)output;
+    Int32 *out = (Int32 *)output;
     if (format_in == RTAUDIO_SINT8) {
       signed char *in = (signed char *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) in[offset_in[j]];
+          out[offset_out[j]] = (Int32) in[offset_in[j]];
           out[offset_out[j]] <<= 24;
         }
         in += jump_in;
@@ -6746,10 +7886,10 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT16) {
-      INT16 *in = (INT16 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int16 *in = (Int16 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) in[offset_in[j]];
+          out[offset_out[j]] = (Int32) in[offset_in[j]];
           out[offset_out[j]] <<= 16;
         }
         in += jump_in;
@@ -6757,10 +7897,10 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT24) {
-      INT32 *in = (INT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int32 *in = (Int32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) in[offset_in[j]];
+          out[offset_out[j]] = (Int32) in[offset_in[j]];
         }
         in += jump_in;
         out += jump_out;
@@ -6768,8 +7908,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
     else if (format_in == RTAUDIO_SINT32) {
       // Channel compensation and/or (de)interleaving only.
-      INT32 *in = (INT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int32 *in = (Int32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = in[offset_in[j]];
         }
@@ -6778,20 +7918,20 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_FLOAT32) {
-      FLOAT32 *in = (FLOAT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float32 *in = (Float32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
+          out[offset_out[j]] = (Int32) (in[offset_in[j]] * 2147483647.0);
         }
         in += jump_in;
         out += jump_out;
       }
     }
     else if (format_in == RTAUDIO_FLOAT64) {
-      FLOAT64 *in = (FLOAT64 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float64 *in = (Float64 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
+          out[offset_out[j]] = (Int32) (in[offset_in[j]] * 2147483647.0);
         }
         in += jump_in;
         out += jump_out;
@@ -6799,12 +7939,12 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
   }
   else if (format_out == RTAUDIO_SINT24) {
-    INT32 *out = (INT32 *)output;
+    Int32 *out = (Int32 *)output;
     if (format_in == RTAUDIO_SINT8) {
       signed char *in = (signed char *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) in[offset_in[j]];
+          out[offset_out[j]] = (Int32) in[offset_in[j]];
           out[offset_out[j]] <<= 24;
         }
         in += jump_in;
@@ -6812,10 +7952,10 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT16) {
-      INT16 *in = (INT16 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int16 *in = (Int16 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) in[offset_in[j]];
+          out[offset_out[j]] = (Int32) in[offset_in[j]];
           out[offset_out[j]] <<= 16;
         }
         in += jump_in;
@@ -6824,8 +7964,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
     else if (format_in == RTAUDIO_SINT24) {
       // Channel compensation and/or (de)interleaving only.
-      INT32 *in = (INT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int32 *in = (Int32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = in[offset_in[j]];
         }
@@ -6834,30 +7974,30 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT32) {
-      INT32 *in = (INT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int32 *in = (Int32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00);
+          out[offset_out[j]] = (Int32) (in[offset_in[j]] & 0xffffff00);
         }
         in += jump_in;
         out += jump_out;
       }
     }
     else if (format_in == RTAUDIO_FLOAT32) {
-      FLOAT32 *in = (FLOAT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float32 *in = (Float32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
+          out[offset_out[j]] = (Int32) (in[offset_in[j]] * 2147483647.0);
         }
         in += jump_in;
         out += jump_out;
       }
     }
     else if (format_in == RTAUDIO_FLOAT64) {
-      FLOAT64 *in = (FLOAT64 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float64 *in = (Float64 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
+          out[offset_out[j]] = (Int32) (in[offset_in[j]] * 2147483647.0);
         }
         in += jump_in;
         out += jump_out;
@@ -6865,12 +8005,12 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
   }
   else if (format_out == RTAUDIO_SINT16) {
-    INT16 *out = (INT16 *)output;
+    Int16 *out = (Int16 *)output;
     if (format_in == RTAUDIO_SINT8) {
       signed char *in = (signed char *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT16) in[offset_in[j]];
+          out[offset_out[j]] = (Int16) in[offset_in[j]];
           out[offset_out[j]] <<= 8;
         }
         in += jump_in;
@@ -6879,8 +8019,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     }
     else if (format_in == RTAUDIO_SINT16) {
       // Channel compensation and/or (de)interleaving only.
-      INT16 *in = (INT16 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int16 *in = (Int16 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = in[offset_in[j]];
         }
@@ -6889,40 +8029,40 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT24) {
-      INT32 *in = (INT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int32 *in = (Int32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
+          out[offset_out[j]] = (Int16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
         }
         in += jump_in;
         out += jump_out;
       }
     }
     else if (format_in == RTAUDIO_SINT32) {
-      INT32 *in = (INT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int32 *in = (Int32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
+          out[offset_out[j]] = (Int16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
         }
         in += jump_in;
         out += jump_out;
       }
     }
     else if (format_in == RTAUDIO_FLOAT32) {
-      FLOAT32 *in = (FLOAT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float32 *in = (Float32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
+          out[offset_out[j]] = (Int16) (in[offset_in[j]] * 32767.0);
         }
         in += jump_in;
         out += jump_out;
       }
     }
     else if (format_in == RTAUDIO_FLOAT64) {
-      FLOAT64 *in = (FLOAT64 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float64 *in = (Float64 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
-          out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
+          out[offset_out[j]] = (Int16) (in[offset_in[j]] * 32767.0);
         }
         in += jump_in;
         out += jump_out;
@@ -6934,7 +8074,7 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
     if (format_in == RTAUDIO_SINT8) {
       // Channel compensation and/or (de)interleaving only.
       signed char *in = (signed char *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = in[offset_in[j]];
         }
@@ -6943,8 +8083,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     if (format_in == RTAUDIO_SINT16) {
-      INT16 *in = (INT16 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int16 *in = (Int16 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff);
         }
@@ -6953,8 +8093,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT24) {
-      INT32 *in = (INT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int32 *in = (Int32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
         }
@@ -6963,8 +8103,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_SINT32) {
-      INT32 *in = (INT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Int32 *in = (Int32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
         }
@@ -6973,8 +8113,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_FLOAT32) {
-      FLOAT32 *in = (FLOAT32 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float32 *in = (Float32 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
         }
@@ -6983,8 +8123,8 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
       }
     }
     else if (format_in == RTAUDIO_FLOAT64) {
-      FLOAT64 *in = (FLOAT64 *)input;
-      for (int i=0; i<stream->bufferSize; i++) {
+      Float64 *in = (Float64 *)input;
+      for (int i=0; i<stream_.bufferSize; i++) {
         for (j=0; j<channels; j++) {
           out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
         }
@@ -6995,7 +8135,7 @@ void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
   }
 }
 
-void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
+void RtApi :: byteSwapBuffer( char *buffer, int samples, RtAudioFormat format )
 {
   register char val;
   register char *ptr;
@@ -7061,25 +8201,3 @@ void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
     }
   }
 }
-
-
-// *************************************************** //
-//
-// RtError class definition.
-//
-// *************************************************** //
-
-RtError :: RtError(const char *p, TYPE tipe)
-{
-  type = tipe;
-  strncpy(error_message, p, 256);
-}
-
-RtError :: ~RtError()
-{
-}
-
-void RtError :: printMessage()
-{
-  printf("\n%s\n\n", error_message);
-}
index a9a2a9ae79415b905c64536d1c9628082e7193d3..cf39ab426f09a442993b95ffb1454dd5fbae0c2c 100644 (file)
--- a/RtAudio.h
+++ b/RtAudio.h
@@ -1,16 +1,16 @@
 /************************************************************************/
 /*! \class RtAudio
-    \brief Realtime audio i/o C++ class.
+    \brief Realtime audio i/o C++ classes.
 
     RtAudio provides a common API (Application Programming Interface)
-    for realtime audio input/output across Linux (native ALSA and
-    OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound
-    and ASIO) operating systems.
+    for realtime audio input/output across Linux (native ALSA, Jack,
+    and OSS), SGI, Macintosh OS X (CoreAudio), and Windows
+    (DirectSound and ASIO) operating systems.
 
-    RtAudio WWW site: http://www-ccrma.stanford.edu/~gary/rtaudio/
+    RtAudio WWW site: http://music.mcgill.ca/~gary/rtaudio/
 
     RtAudio: a realtime audio i/o C++ class
-    Copyright (c) 2001-2002 Gary P. Scavone
+    Copyright (c) 2001-2004 Gary P. Scavone
 
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation files
 */
 /************************************************************************/
 
-#if !defined(__RTAUDIO_H)
+// RtAudio: Version 3.0, 11 March 2004
+
+#ifndef __RTAUDIO_H
 #define __RTAUDIO_H
 
-#include <map>
+#include "RtError.h"
+#include <string>
+#include <vector>
 
-#if defined(__LINUX_ALSA__)
-  #include <alsa/asoundlib.h>
-  #include <pthread.h>
-  #include <unistd.h>
+// Operating system dependent thread functionality.
+#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
+  #include <windows.h>
+  #include <process.h>
 
-  typedef snd_pcm_t *AUDIO_HANDLE;
-  typedef int DEVICE_ID;
-  typedef pthread_t THREAD_HANDLE;
-  typedef pthread_mutex_t MUTEX;
+  typedef unsigned long ThreadHandle;
+  typedef CRITICAL_SECTION StreamMutex;
 
-#elif defined(__LINUX_OSS__)
+#else // Various unix flavors with pthread support.
   #include <pthread.h>
-  #include <unistd.h>
 
-  typedef int AUDIO_HANDLE;
-  typedef int DEVICE_ID;
-  typedef pthread_t THREAD_HANDLE;
-  typedef pthread_mutex_t MUTEX;
+  typedef pthread_t ThreadHandle;
+  typedef pthread_mutex_t StreamMutex;
 
-#elif defined(__WINDOWS_DS__)
-  #include <windows.h>
-  #include <process.h>
+#endif
 
-  // The following struct is used to hold the extra variables
-  // specific to the DirectSound implementation.
-  typedef struct {
-    void * object;
-    void * buffer;
-    UINT bufferPointer;
-  } AUDIO_HANDLE;
+// This global structure type is used to pass callback information
+// between the private RtAudio stream structure and global callback
+// handling functions.
+struct CallbackInfo {
+  void *object;    // Used as a "this" pointer.
+  ThreadHandle thread;
+  bool usingCallback;
+  void *callback;
+  void *userData;
+  void *apiInfo;   // void pointer for API specific callback information
 
-  typedef LPGUID DEVICE_ID;
-  typedef unsigned long THREAD_HANDLE;
-  typedef CRITICAL_SECTION MUTEX;
+  // Default constructor.
+  CallbackInfo()
+    :object(0), usingCallback(false), callback(0),
+     userData(0), apiInfo(0) {}
+};
 
-#elif defined(__WINDOWS_ASIO__)
-  #include <windows.h>
-  #include <process.h>
+// Support for signed integers and floats.  Audio data fed to/from
+// the tickStream() routine is assumed to ALWAYS be in host
+// byte order.  The internal routines will automatically take care of
+// any necessary byte-swapping between the host format and the
+// soundcard.  Thus, endian-ness is not a concern in the following
+// format definitions.
+typedef unsigned long RtAudioFormat;
+static const RtAudioFormat RTAUDIO_SINT8 = 0x1;    /*!< 8-bit signed integer. */
+static const RtAudioFormat RTAUDIO_SINT16 = 0x2;   /*!< 16-bit signed integer. */
+static const RtAudioFormat RTAUDIO_SINT24 = 0x4;   /*!< Upper 3 bytes of 32-bit signed integer. */
+static const RtAudioFormat RTAUDIO_SINT32 = 0x8;   /*!< 32-bit signed integer. */
+static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; /*!< Normalized between plus/minus 1.0. */
+static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; /*!< Normalized between plus/minus 1.0. */
+
+typedef int (*RtAudioCallback)(char *buffer, int bufferSize, void *userData);
+
+//! The public device information structure for returning queried values.
+struct RtAudioDeviceInfo {
+  std::string name;      /*!< Character string device identifier. */
+  bool probed;          /*!< true if the device capabilities were successfully probed. */
+  int outputChannels;   /*!< Maximum output channels supported by device. */
+  int inputChannels;    /*!< Maximum input channels supported by device. */
+  int duplexChannels;   /*!< Maximum simultaneous input/output channels supported by device. */
+  bool isDefault;       /*!< true if this is the default output or input device. */
+  std::vector<int> sampleRates; /*!< Supported sample rates (queried from list of standard rates). */
+  RtAudioFormat nativeFormats;  /*!< Bit mask of supported data formats. */
+
+  // Default constructor.
+  RtAudioDeviceInfo()
+    :probed(false), outputChannels(0), inputChannels(0),
+       duplexChannels(0), isDefault(false), nativeFormats(0) {}
+};
 
-  typedef int AUDIO_HANDLE;
-  typedef int DEVICE_ID;
-  typedef unsigned long THREAD_HANDLE;
-  typedef CRITICAL_SECTION MUTEX;
+// **************************************************************** //
+//
+// RtApi class declaration.
+//
+// Note that RtApi is an abstract base class and cannot be
+// explicitly instantiated.  The class RtAudio will create an
+// instance of an RtApi subclass (RtApiOss, RtApiAlsa,
+// RtApiJack, RtApiCore, RtApiAl, RtApiDs, or RtApiAsio).
+//
+// **************************************************************** //
 
-#elif defined(__IRIX_AL__)
-  #include <dmedia/audio.h>
-  #include <pthread.h>
-  #include <unistd.h>
+class RtApi
+{
+public:
 
-  typedef ALport AUDIO_HANDLE;
-  typedef long DEVICE_ID;
-  typedef pthread_t THREAD_HANDLE;
-  typedef pthread_mutex_t MUTEX;
+  RtApi();
+  virtual ~RtApi();
+  void openStream( int outputDevice, int outputChannels,
+                   int inputDevice, int inputChannels,
+                   RtAudioFormat format, int sampleRate,
+                   int *bufferSize, int numberOfBuffers );
+  virtual void setStreamCallback( RtAudioCallback callback, void *userData ) = 0;
+  virtual void cancelStreamCallback() = 0;
+  int getDeviceCount(void);
+  RtAudioDeviceInfo getDeviceInfo( int device );
+  char * const getStreamBuffer();
+  virtual void tickStream() = 0;
+  virtual void closeStream();
+  virtual void startStream() = 0;
+  virtual void stopStream() = 0;
+  virtual void abortStream() = 0;
 
-#elif defined(__MACOSX_CORE__)
+protected:
 
-  #include <CoreAudio/AudioHardware.h>
-  #include <pthread.h>
+  static const unsigned int MAX_SAMPLE_RATES;
+  static const unsigned int SAMPLE_RATES[];
 
-  typedef unsigned int AUDIO_HANDLE;
-  typedef AudioDeviceID DEVICE_ID;
-  typedef pthread_t THREAD_HANDLE;
-  typedef pthread_mutex_t MUTEX;
+  enum { FAILURE, SUCCESS };
 
-#endif
+  enum StreamMode {
+    OUTPUT,
+    INPUT,
+    DUPLEX,
+    UNINITIALIZED = -75
+  };
 
+  enum StreamState {
+    STREAM_STOPPED,
+    STREAM_RUNNING
+  };
 
-/************************************************************************/
-/*! \class RtError
-    \brief Exception handling class for RtAudio.
-
-    The RtError class is quite simple but it does allow errors to be
-    "caught" by RtError::TYPE. Almost all RtAudio methods can "throw"
-    an RtError, most typically if an invalid stream identifier is
-    supplied to a method or a driver error occurs. There are a number
-    of cases within RtAudio where warning messages may be displayed
-    but an exception is not thrown. There is a private RtAudio method,
-    error(), which can be modified to globally control how these
-    messages are handled and reported.
-*/
-/************************************************************************/
+  // A protected structure for audio streams.
+  struct RtApiStream {
+    int device[2];          // Playback and record, respectively.
+    void *apiHandle;        // void pointer for API specific stream handle information
+    StreamMode mode;         // OUTPUT, INPUT, or DUPLEX.
+    StreamState state;       // STOPPED or RUNNING
+    char *userBuffer;
+    char *deviceBuffer;
+    bool doConvertBuffer[2]; // Playback and record, respectively.
+    bool deInterleave[2];    // Playback and record, respectively.
+    bool doByteSwap[2];      // Playback and record, respectively.
+    int sampleRate;
+    int bufferSize;
+    int nBuffers;
+    int nUserChannels[2];    // Playback and record, respectively.
+    int nDeviceChannels[2];  // Playback and record channels, respectively.
+    RtAudioFormat userFormat;
+    RtAudioFormat deviceFormat[2]; // Playback and record, respectively.
+    StreamMutex mutex;
+    CallbackInfo callbackInfo;
+
+    RtApiStream()
+      :apiHandle(0), userBuffer(0), deviceBuffer(0) {}
+    //      :apiHandle(0), mode(UNINITIALIZED), state(STREAM_STOPPED),
+    //       userBuffer(0), deviceBuffer(0) {}
+  };
 
-class RtError
-{
-public:
-  //! Defined RtError types.
-  enum TYPE {
-    WARNING,
-    DEBUG_WARNING,
-    UNSPECIFIED,
-    NO_DEVICES_FOUND,
-    INVALID_DEVICE,
-    INVALID_STREAM,
-    MEMORY_ERROR,
-    INVALID_PARAMETER,
-    DRIVER_ERROR,
-    SYSTEM_ERROR,
-    THREAD_ERROR
+  // A protected device structure for audio devices.
+  struct RtApiDevice {
+    std::string name;      /*!< Character string device identifier. */
+    bool probed;           /*!< true if the device capabilities were successfully probed. */
+    void *apiDeviceId;     // void pointer for API specific device information
+    int maxOutputChannels; /*!< Maximum output channels supported by device. */
+    int maxInputChannels;  /*!< Maximum input channels supported by device. */
+    int maxDuplexChannels; /*!< Maximum simultaneous input/output channels supported by device. */
+    int minOutputChannels; /*!< Minimum output channels supported by device. */
+    int minInputChannels;  /*!< Minimum input channels supported by device. */
+    int minDuplexChannels; /*!< Minimum simultaneous input/output channels supported by device. */
+    bool hasDuplexSupport; /*!< true if device supports duplex mode. */
+    bool isDefault;        /*!< true if this is the default output or input device. */
+    std::vector<int> sampleRates; /*!< Supported sample rates. */
+    RtAudioFormat nativeFormats;  /*!< Bit mask of supported data formats. */
+
+    // Default constructor.
+    RtApiDevice()
+      :probed(false), apiDeviceId(0), maxOutputChannels(0), maxInputChannels(0),
+       maxDuplexChannels(0), minOutputChannels(0), minInputChannels(0),
+       minDuplexChannels(0), isDefault(false), nativeFormats(0) {}
   };
 
-protected:
-  char error_message[256];
-  TYPE type;
+  typedef signed short Int16;
+  typedef signed int Int32;
+  typedef float Float32;
+  typedef double Float64;
 
-public:
-  //! The constructor.
-  RtError(const char *p, TYPE tipe = RtError::UNSPECIFIED);
+  char message_[256];
+  int nDevices_;
+  std::vector<RtApiDevice> devices_;
+  RtApiStream stream_;
 
-  //! The destructor.
-  virtual ~RtError(void);
+  /*!
+    Protected, api-specific method to count and identify the system
+    audio devices.  This function MUST be implemented by all subclasses.
+  */
+  virtual void initialize(void) = 0;
 
-  //! Prints "thrown" error message to stdout.
-  virtual void printMessage(void);
+  /*!
+    Protected, api-specific method which attempts to fill an
+    RtAudioDevice structure for a given device.  This function MUST be
+    implemented by all subclasses.  If an error is encountered during
+    the probe, a "warning" message is reported and the value of
+    "probed" remains false (no exception is thrown).  A successful
+    probe is indicated by probed = true.
+  */
+  virtual void probeDeviceInfo( RtApiDevice *info );
 
-  //! Returns the "thrown" error message TYPE.
-  virtual const TYPE& getType(void) { return type; }
+  /*!
+    Protected, api-specific method which attempts to open a device
+    with the given parameters.  This function MUST be implemented by
+    all subclasses.  If an error is encountered during the probe, a
+    "warning" message is reported and FAILURE is returned (no
+    exception is thrown). A successful probe is indicated by a return
+    value of SUCCESS.
+  */
+  virtual bool probeDeviceOpen( int device, StreamMode mode, int channels, 
+                                int sampleRate, RtAudioFormat format,
+                                int *bufferSize, int numberOfBuffers );
 
-  //! Returns the "thrown" error message string.
-  virtual const char *getMessage(void) { return error_message; }
-};
+  /*!
+    Protected method which returns the index in the devices array to
+    the default input device.
+  */
+  virtual int getDefaultInputDevice(void);
+
+  /*!
+    Protected method which returns the index in the devices array to
+    the default output device.
+  */
+  virtual int getDefaultOutputDevice(void);
 
+  //! Protected common method to clear an RtApiDevice structure.
+  void clearDeviceInfo( RtApiDevice *info );
 
-// This public structure type is used to pass callback information
-// between the private RtAudio stream structure and global callback
-// handling functions.
-typedef struct {
-  void *object;  // Used as a "this" pointer.
-  int streamId;
-  DEVICE_ID device[2];
-  THREAD_HANDLE thread;
-  void *callback;
-  void *buffers;
-  unsigned long waitTime;
-  bool blockTick;
-  bool stopStream;
-  bool usingCallback;
-  void *userData;
-} CALLBACK_INFO;
+  //! Protected common method to clear an RtApiStream structure.
+  void clearStreamInfo();
 
+  //! Protected common error method to allow global control over error handling.
+  void error( RtError::Type type );
 
-// *************************************************** //
+  /*!
+    Protected common method used to check whether a stream is open.
+    If not, an "invalid identifier" exception is thrown.
+  */
+  void verifyStream();
+
+  /*!
+    Protected method used to perform format, channel number, and/or interleaving
+    conversions between the user and device buffers.
+  */
+  void convertStreamBuffer( StreamMode mode );
+
+  //! Protected common method used to perform byte-swapping on buffers.
+  void byteSwapBuffer( char *buffer, int samples, RtAudioFormat format );
+
+  //! Protected common method which returns the number of bytes for a given format.
+  int formatBytes( RtAudioFormat format );
+};
+
+
+// **************************************************************** //
 //
 // RtAudio class declaration.
 //
-// *************************************************** //
+// RtAudio is a "controller" used to select an available audio i/o
+// interface.  It presents a common API for the user to call but all
+// functionality is implemented by the class RtAudioApi and its
+// subclasses.  RtAudio creates an instance of an RtAudioApi subclass
+// based on the user's API choice.  If no choice is made, RtAudio
+// attempts to make a "logical" API selection.
+//
+// **************************************************************** //
 
 class RtAudio
 {
 public:
 
-  // Support for signed integers and floats.  Audio data fed to/from
-  // the tickStream() routine is assumed to ALWAYS be in host
-  // byte order.  The internal routines will automatically take care of
-  // any necessary byte-swapping between the host format and the
-  // soundcard.  Thus, endian-ness is not a concern in the following
-  // format definitions.
-  typedef unsigned long RTAUDIO_FORMAT;
-  static const RTAUDIO_FORMAT RTAUDIO_SINT8; /*!< 8-bit signed integer. */
-  static const RTAUDIO_FORMAT RTAUDIO_SINT16; /*!< 16-bit signed integer. */
-  static const RTAUDIO_FORMAT RTAUDIO_SINT24; /*!< Upper 3 bytes of 32-bit signed integer. */
-  static const RTAUDIO_FORMAT RTAUDIO_SINT32; /*!< 32-bit signed integer. */
-  static const RTAUDIO_FORMAT RTAUDIO_FLOAT32; /*!< Normalized between plus/minus 1.0. */
-  static const RTAUDIO_FORMAT RTAUDIO_FLOAT64; /*!< Normalized between plus/minus 1.0. */
-
-  //static const int MAX_SAMPLE_RATES = 14;
-  enum { MAX_SAMPLE_RATES = 14 };
-
-  typedef int (*RTAUDIO_CALLBACK)(char *buffer, int bufferSize, void *userData);
-
-  //! The public device information structure for passing queried values.
-  typedef struct {
-    char name[128];    /*!< Character string device identifier. */
-    DEVICE_ID id[2];  /* No value reported by getDeviceInfo(). */
-    bool probed;       /*!< true if the device capabilities were successfully probed. */
-    int maxOutputChannels; /*!< Maximum output channels supported by device. */
-    int maxInputChannels;  /*!< Maximum input channels supported by device. */
-    int maxDuplexChannels; /*!< Maximum simultaneous input/output channels supported by device. */
-    int minOutputChannels; /*!< Minimum output channels supported by device. */
-    int minInputChannels;  /*!< Minimum input channels supported by device. */
-    int minDuplexChannels; /*!< Minimum simultaneous input/output channels supported by device. */
-    bool hasDuplexSupport; /*!< true if device supports duplex mode. */
-    bool isDefault;        /*!< true if this is the default output or input device. */
-    int nSampleRates;      /*!< Number of discrete rates or -1 if range supported. */
-    int sampleRates[MAX_SAMPLE_RATES]; /*!< Supported rates or (min, max) if range. */
-    RTAUDIO_FORMAT nativeFormats;     /*!< Bit mask of supported data formats. */
-  } RTAUDIO_DEVICE;
+  //! Audio API specifier arguments.
+  enum RtAudioApi {
+    UNSPECIFIED,    /*!< Search for a working compiled API. */
+    LINUX_ALSA,     /*!< The Advanced Linux Sound Architecture API. */
+    LINUX_OSS,      /*!< The Linux Open Sound System API. */
+    LINUX_JACK,     /*!< The Linux Jack Low-Latency Audio Server API. */
+    MACOSX_CORE,    /*!< Macintosh OS-X Core Audio API. */
+    IRIX_AL,        /*!< The Irix Audio Library API. */
+    WINDOWS_ASIO,   /*!< The Steinberg Audio Stream I/O API. */
+    WINDOWS_DS      /*!< The Microsoft Direct Sound API. */
+  };
 
-  //! The default constructor.
+  //! The default class constructor.
   /*!
     Probes the system to make sure at least one audio input/output
     device is available and determines the api-specific identifier for
     each device found.  An RtError error can be thrown if no devices
     are found or if a memory allocation error occurs.
+
+    If no API argument is specified and multiple API support has been
+    compiled, the default order of use is JACK, ALSA, OSS (Linux
+    systems) and ASIO, DS (Windows systems).
   */
-  RtAudio();
+  RtAudio( RtAudioApi api=UNSPECIFIED );
 
   //! A constructor which can be used to open a stream during instantiation.
   /*!
@@ -250,23 +346,21 @@ public:
     for the given parameters, if a memory allocation error occurs, or
     if a driver error occurs. \sa openStream()
   */
-  RtAudio(int *streamId,
-          int outputDevice, int outputChannels,
-          int inputDevice, int inputChannels,
-          RTAUDIO_FORMAT format, int sampleRate,
-          int *bufferSize, int numberOfBuffers);
+  RtAudio( int outputDevice, int outputChannels,
+           int inputDevice, int inputChannels,
+           RtAudioFormat format, int sampleRate,
+           int *bufferSize, int numberOfBuffers, RtAudioApi api=UNSPECIFIED );
 
   //! The destructor.
   /*!
-    Stops and closes any open streams and devices and deallocates
+    Stops and closes an open stream and devices and deallocates
     buffer and structure memory.
   */
   ~RtAudio();
 
   //! A public method for opening a stream with the specified parameters.
   /*!
-    If successful, the opened stream ID is returned.  Otherwise, an
-    RtError is thrown.
+    An RtError is thrown if a stream cannot be opened.
 
     \param outputDevice: If equal to 0, the default or first device
            found meeting the given parameters is opened.  Otherwise, the
@@ -280,7 +374,7 @@ public:
            the getDeviceInfo() method.
     \param inputChannels: The desired number of input channels.  If
            equal to zero, the inputDevice identifier is ignored.
-    \param format: An RTAUDIO_FORMAT specifying the desired sample data format.
+    \param format: An RtAudioFormat specifying the desired sample data format.
     \param sampleRate: The desired sample rate (sample frames per second).
     \param *bufferSize: A pointer value indicating the desired internal buffer
            size in sample frames.  The actual value used by the device is
@@ -291,47 +385,47 @@ public:
            though at a cost of greater latency.  A value of zero can be
            specified, in which case the lowest allowable value is used.
   */
-  int openStream(int outputDevice, int outputChannels,
-                 int inputDevice, int inputChannels,
-                 RTAUDIO_FORMAT format, int sampleRate,
-                 int *bufferSize, int numberOfBuffers);
+  void openStream( int outputDevice, int outputChannels,
+                   int inputDevice, int inputChannels,
+                   RtAudioFormat format, int sampleRate,
+                   int *bufferSize, int numberOfBuffers );
 
   //! A public method which sets a user-defined callback function for a given stream.
   /*!
-    This method assigns a callback function to a specific,
-    previously opened stream for non-blocking stream functionality.  A
-    separate process is initiated, though the user function is called
-    only when the stream is "running" (between calls to the
-    startStream() and stopStream() methods, respectively).  The
-    callback process remains active for the duration of the stream and
-    is automatically shutdown when the stream is closed (via the
-    closeStream() method or by object destruction).  The callback
-    process can also be shutdown and the user function de-referenced
-    through an explicit call to the cancelStreamCallback() method.
-    Note that a single stream can use only blocking or callback
-    functionality at the same time, though it is possible to alternate
-    modes on the same stream through the use of the
-    setStreamCallback() and cancelStreamCallback() methods (the
-    blocking tickStream() method can be used before a callback is set
-    and/or after a callback is cancelled).  An RtError will be thrown
-    for an invalid device argument.
+    This method assigns a callback function to a previously opened
+    stream for non-blocking stream functionality.  A separate process
+    is initiated, though the user function is called only when the
+    stream is "running" (between calls to the startStream() and
+    stopStream() methods, respectively).  The callback process remains
+    active for the duration of the stream and is automatically
+    shutdown when the stream is closed (via the closeStream() method
+    or by object destruction).  The callback process can also be
+    shutdown and the user function de-referenced through an explicit
+    call to the cancelStreamCallback() method.  Note that the stream
+    can use only blocking or callback functionality at a particular
+    time, though it is possible to alternate modes on the same stream
+    through the use of the setStreamCallback() and
+    cancelStreamCallback() methods (the blocking tickStream() method
+    can be used before a callback is set and/or after a callback is
+    cancelled).  An RtError will be thrown if called when no stream is
+    open or a thread errors occurs.
   */
-  void setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData);
+  void setStreamCallback(RtAudioCallback callback, void *userData) { rtapi_->setStreamCallback( callback, userData ); };
 
-  //! A public method which cancels a callback process and function for a given stream.
+  //! A public method which cancels a callback process and function for the stream.
   /*!
     This method shuts down a callback process and de-references the
-    user function for a specific stream.  Callback functionality can
+    user function for the stream.  Callback functionality can
     subsequently be restarted on the stream via the
-    setStreamCallback() method.  An RtError will be thrown for an
-    invalid device argument.
+    setStreamCallback() method.  An RtError will be thrown if called
+    when no stream is open.
    */
-  void cancelStreamCallback(int streamId);
+  void cancelStreamCallback() { rtapi_->cancelStreamCallback(); };
 
   //! A public method which returns the number of audio devices found.
-  int getDeviceCount(void);
+  int getDeviceCount(void) { return rtapi_->getDeviceCount(); };
 
-  //! Fill a user-supplied RTAUDIO_DEVICE structure for a specified device number.
+  //! Return an RtAudioDeviceInfo structure for a specified device number.
   /*!
     Any device integer between 1 and getDeviceCount() is valid.  If
     a device is busy or otherwise unavailable, the structure member
@@ -340,185 +434,281 @@ public:
     or output device, the "isDefault" member will have a value of
     "true".  An RtError will be thrown for an invalid device argument.
   */
-  void getDeviceInfo(int device, RTAUDIO_DEVICE *info);
+  RtAudioDeviceInfo getDeviceInfo(int device) { return rtapi_->getDeviceInfo( device ); };
 
   //! A public method which returns a pointer to the buffer for an open stream.
   /*!
     The user should fill and/or read the buffer data in interleaved format
     and then call the tickStream() method.  An RtError will be
-    thrown for an invalid stream identifier.
+    thrown if called when no stream is open.
   */
-  char * const getStreamBuffer(int streamId);
+  char * const getStreamBuffer() { return rtapi_->getStreamBuffer(); };
 
   //! Public method used to trigger processing of input/output data for a stream.
   /*!
     This method blocks until all buffer data is read/written.  An
-    RtError will be thrown for an invalid stream identifier or if
-    a driver error occurs.
+    RtError will be thrown if a driver error occurs or if called when
+    no stream is open.
   */
-  void tickStream(int streamId);
+  void tickStream() { rtapi_->tickStream(); };
 
   //! Public method which closes a stream and frees any associated buffers.
   /*!
-    If an invalid stream identifier is specified, this method
-    issues a warning and returns (an RtError is not thrown).
+    If a stream is not open, this method issues a warning and
+    returns (an RtError is not thrown).
   */
-  void closeStream(int streamId);
+  void closeStream()  { rtapi_->closeStream(); };
 
   //! Public method which starts a stream.
   /*!
-    An RtError will be thrown for an invalid stream identifier
-    or if a driver error occurs.
+    An RtError will be thrown if a driver error occurs or if called
+    when no stream is open.
   */
-  void startStream(int streamId);
+  void startStream() { rtapi_->startStream(); };
 
   //! Stop a stream, allowing any samples remaining in the queue to be played out and/or read in.
   /*!
-    An RtError will be thrown for an invalid stream identifier
-    or if a driver error occurs.
+    An RtError will be thrown if a driver error occurs or if called
+    when no stream is open.
   */
-  void stopStream(int streamId);
+  void stopStream() { rtapi_->stopStream(); };
 
   //! Stop a stream, discarding any samples remaining in the input/output queue.
   /*!
-    An RtError will be thrown for an invalid stream identifier
-    or if a driver error occurs.
+    An RtError will be thrown if a driver error occurs or if called
+    when no stream is open.
   */
-  void abortStream(int streamId);
+  void abortStream() { rtapi_->abortStream(); };
 
-  //! Queries a stream to determine whether a call to the tickStream() method will block.
-  /*!
-    A return value of 0 indicates that the stream will NOT block.  A positive
-    return value indicates the number of sample frames that cannot yet be
-    processed without blocking.
-  */
-  int streamWillBlock(int streamId);
 
-#if (defined(__MACOSX_CORE__) || defined(__WINDOWS_ASIO__))
+ protected:
+
+  void initialize( RtAudioApi api );
+
+  RtApi *rtapi_;
+};
+
+
+// RtApi Subclass prototypes.
+
+#if defined(__LINUX_ALSA__)
+
+class RtApiAlsa: public RtApi
+{
+public:
+
+  RtApiAlsa();
+  ~RtApiAlsa();
+  void tickStream();
+  void closeStream();
+  void startStream();
+  void stopStream();
+  void abortStream();
+  int streamWillBlock();
+  void setStreamCallback( RtAudioCallback callback, void *userData );
+  void cancelStreamCallback();
+
+  private:
+
+  void initialize(void);
+  void probeDeviceInfo( RtApiDevice *info );
+  bool probeDeviceOpen( int device, StreamMode mode, int channels, 
+                        int sampleRate, RtAudioFormat format,
+                        int *bufferSize, int numberOfBuffers );
+};
+
+#endif
+
+#if defined(__LINUX_JACK__)
+
+class RtApiJack: public RtApi
+{
+public:
+
+  RtApiJack();
+  ~RtApiJack();
+  void tickStream();
+  void closeStream();
+  void startStream();
+  void stopStream();
+  void abortStream();
+  void setStreamCallback( RtAudioCallback callback, void *userData );
+  void cancelStreamCallback();
   // This function is intended for internal use only.  It must be
   // public because it is called by the internal callback handler,
   // which is not a member of RtAudio.  External use of this function
   // will most likely produce highly undesireable results!
-  void callbackEvent(int streamId, DEVICE_ID deviceId, void *inData, void *outData);
+  void callbackEvent( unsigned long nframes );
+
+  private:
+
+  void initialize(void);
+  void probeDeviceInfo( RtApiDevice *info );
+  bool probeDeviceOpen( int device, StreamMode mode, int channels, 
+                        int sampleRate, RtAudioFormat format,
+                        int *bufferSize, int numberOfBuffers );
+};
+
 #endif
 
-protected:
+#if defined(__LINUX_OSS__)
 
-private:
+class RtApiOss: public RtApi
+{
+public:
 
-  static const unsigned int SAMPLE_RATES[MAX_SAMPLE_RATES];
+  RtApiOss();
+  ~RtApiOss();
+  void tickStream();
+  void closeStream();
+  void startStream();
+  void stopStream();
+  void abortStream();
+  int streamWillBlock();
+  void setStreamCallback( RtAudioCallback callback, void *userData );
+  void cancelStreamCallback();
 
-  enum { FAILURE, SUCCESS };
+  private:
 
-  enum STREAM_MODE {
-    OUTPUT,
-    INPUT,
-    DUPLEX,
-    UNINITIALIZED = -75
-  };
+  void initialize(void);
+  void probeDeviceInfo( RtApiDevice *info );
+  bool probeDeviceOpen( int device, StreamMode mode, int channels, 
+                        int sampleRate, RtAudioFormat format,
+                        int *bufferSize, int numberOfBuffers );
+};
 
-  enum STREAM_STATE {
-    STREAM_STOPPED,
-    STREAM_RUNNING
-  };
+#endif
 
-  typedef struct {
-    int device[2];          // Playback and record, respectively.
-    STREAM_MODE mode;       // OUTPUT, INPUT, or DUPLEX.
-    AUDIO_HANDLE handle[2]; // Playback and record handles, respectively.
-    STREAM_STATE state;     // STOPPED or RUNNING
-    char *userBuffer;
-    char *deviceBuffer;
-    bool doConvertBuffer[2]; // Playback and record, respectively.
-    bool deInterleave[2];    // Playback and record, respectively.
-    bool doByteSwap[2];      // Playback and record, respectively.
-    int sampleRate;
-    int bufferSize;
-    int nBuffers;
-    int nUserChannels[2];    // Playback and record, respectively.
-    int nDeviceChannels[2];  // Playback and record channels, respectively.
-    RTAUDIO_FORMAT userFormat;
-    RTAUDIO_FORMAT deviceFormat[2]; // Playback and record, respectively.
-    MUTEX mutex;
-    CALLBACK_INFO callbackInfo;
-  } RTAUDIO_STREAM;
+#if defined(__MACOSX_CORE__)
 
-  typedef signed short INT16;
-  typedef signed int INT32;
-  typedef float FLOAT32;
-  typedef double FLOAT64;
+#include <CoreAudio/AudioHardware.h>
 
-  char message[256];
-  int nDevices;
-  RTAUDIO_DEVICE *devices;
+class RtApiCore: public RtApi
+{
+public:
 
-  std::map<int, void *> streams;
+  RtApiCore();
+  ~RtApiCore();
+  int getDefaultOutputDevice(void);
+  int getDefaultInputDevice(void);
+  void tickStream();
+  void closeStream();
+  void startStream();
+  void stopStream();
+  void abortStream();
+  void setStreamCallback( RtAudioCallback callback, void *userData );
+  void cancelStreamCallback();
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  void callbackEvent( AudioDeviceID deviceId, void *inData, void *outData );
 
-  //! Private error method to allow global control over error handling.
-  void error(RtError::TYPE type);
+  private:
 
-  /*!
-    Private method to count the system audio devices, allocate the
-    RTAUDIO_DEVICE structures, and probe the device capabilities.
-  */
   void initialize(void);
+  void probeDeviceInfo( RtApiDevice *info );
+  bool probeDeviceOpen( int device, StreamMode mode, int channels, 
+                        int sampleRate, RtAudioFormat format,
+                        int *bufferSize, int numberOfBuffers );
+};
 
-  /*!
-    Private method which returns the index in the devices array to
-    the default input device.
-  */
-  int getDefaultInputDevice(void);
+#endif
 
-  /*!
-    Private method which returns the index in the devices array to
-    the default output device.
-  */
+#if defined(__WINDOWS_DS__)
+
+class RtApiDs: public RtApi
+{
+public:
+
+  RtApiDs();
+  ~RtApiDs();
   int getDefaultOutputDevice(void);
+  int getDefaultInputDevice(void);
+  void tickStream();
+  void closeStream();
+  void startStream();
+  void stopStream();
+  void abortStream();
+  int streamWillBlock();
+  void setStreamCallback( RtAudioCallback callback, void *userData );
+  void cancelStreamCallback();
 
-  //! Private method to clear an RTAUDIO_DEVICE structure.
-  void clearDeviceInfo(RTAUDIO_DEVICE *info);
+  private:
 
-  /*!
-    Private method which attempts to fill an RTAUDIO_DEVICE
-    structure for a given device.  If an error is encountered during
-    the probe, a "warning" message is reported and the value of
-    "probed" remains false (no exception is thrown).  A successful
-    probe is indicated by probed = true.
-  */
-  void probeDeviceInfo(RTAUDIO_DEVICE *info);
+  void initialize(void);
+  void probeDeviceInfo( RtApiDevice *info );
+  bool probeDeviceOpen( int device, StreamMode mode, int channels, 
+                        int sampleRate, RtAudioFormat format,
+                        int *bufferSize, int numberOfBuffers );
+};
 
-  /*!
-    Private method which attempts to open a device with the given parameters.
-    If an error is encountered during the probe, a "warning" message is
-    reported and FAILURE is returned (no exception is thrown). A
-    successful probe is indicated by a return value of SUCCESS.
-  */
-  bool probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
-                       STREAM_MODE mode, int channels, 
-                       int sampleRate, RTAUDIO_FORMAT format,
-                       int *bufferSize, int numberOfBuffers);
+#endif
 
-  /*!
-    Private common method used to check validity of a user-passed
-    stream ID.  When the ID is valid, this method returns a pointer to
-    an RTAUDIO_STREAM structure (in the form of a void pointer).
-    Otherwise, an "invalid identifier" exception is thrown.
-  */
-  void *verifyStream(int streamId);
+#if defined(__WINDOWS_ASIO__)
 
-  /*!
-    Private method used to perform format, channel number, and/or interleaving
-    conversions between the user and device buffers.
-  */
-  void convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode);
+class RtApiAsio: public RtApi
+{
+public:
+
+  RtApiAsio();
+  ~RtApiAsio();
+  void tickStream();
+  void closeStream();
+  void startStream();
+  void stopStream();
+  void abortStream();
+  void setStreamCallback( RtAudioCallback callback, void *userData );
+  void cancelStreamCallback();
+
+  // This function is intended for internal use only.  It must be
+  // public because it is called by the internal callback handler,
+  // which is not a member of RtAudio.  External use of this function
+  // will most likely produce highly undesireable results!
+  void callbackEvent( long bufferIndex );
+
+  private:
+
+  void initialize(void);
+  void probeDeviceInfo( RtApiDevice *info );
+  bool probeDeviceOpen( int device, StreamMode mode, int channels, 
+                        int sampleRate, RtAudioFormat format,
+                        int *bufferSize, int numberOfBuffers );
+};
+
+#endif
+
+#if defined(__IRIX_AL__)
+
+class RtApiAl: public RtApi
+{
+public:
+
+  RtApiAl();
+  ~RtApiAl();
+  int getDefaultOutputDevice(void);
+  int getDefaultInputDevice(void);
+  void tickStream();
+  void closeStream();
+  void startStream();
+  void stopStream();
+  void abortStream();
+  int streamWillBlock();
+  void setStreamCallback( RtAudioCallback callback, void *userData );
+  void cancelStreamCallback();
 
-  //! Private method used to perform byte-swapping on buffers.
-  void byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format);
+  private:
 
-  //! Private method which returns the number of bytes for a given format.
-  int formatBytes(RTAUDIO_FORMAT format);
+  void initialize(void);
+  void probeDeviceInfo( RtApiDevice *info );
+  bool probeDeviceOpen( int device, StreamMode mode, int channels, 
+                        int sampleRate, RtAudioFormat format,
+                        int *bufferSize, int numberOfBuffers );
 };
 
+#endif
+
 // Define the following flag to have extra information spewed to stderr.
 //#define __RTAUDIO_DEBUG__
 
diff --git a/RtError.h b/RtError.h
new file mode 100644 (file)
index 0000000..465cd75
--- /dev/null
+++ b/RtError.h
@@ -0,0 +1,60 @@
+/************************************************************************/
+/*! \class RtError
+    \brief Exception handling class for RtAudio & RtMidi.
+
+    The RtError class is quite simple but it does allow errors to be
+    "caught" by RtError::Type. See the RtAudio and RtMidi
+    documentation to know which methods can throw an RtError.
+
+*/
+/************************************************************************/
+
+#ifndef RTERROR_H
+#define RTERROR_H
+
+#include <iostream>
+#include <string>
+
+class RtError
+{
+public:
+  //! Defined RtError types.
+  enum Type {
+    WARNING,           /*!< A non-critical error. */
+    DEBUG_WARNING,     /*!< A non-critical error which might be useful for debugging. */
+    UNSPECIFIED,       /*!< The default, unspecified error type. */
+    NO_DEVICES_FOUND,  /*!< No devices found on system. */
+    INVALID_DEVICE,    /*!< An invalid device ID was specified. */
+    INVALID_STREAM,    /*!< An invalid stream ID was specified. */
+    MEMORY_ERROR,      /*!< An error occured during memory allocation. */
+    INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
+    DRIVER_ERROR,      /*!< A system driver error occured. */
+    SYSTEM_ERROR,      /*!< A system error occured. */
+    THREAD_ERROR       /*!< A thread error occured. */
+  };
+
+protected:
+  std::string message_;
+  Type type_;
+
+public:
+  //! The constructor.
+  RtError(const std::string& message, Type type = RtError::UNSPECIFIED) : message_(message), type_(type){}
+
+  //! The destructor.
+  virtual ~RtError(void) {};
+
+  //! Prints thrown error message to stderr.
+  virtual void printMessage(void) { std::cerr << '\n' << message_ << "\n\n"; }
+
+  //! Returns the thrown error message type.
+  virtual const Type& getType(void) { return type_; }
+
+  //! Returns the thrown error message string.
+  virtual const std::string& getMessage(void) { return message_; }
+
+  //! Returns the thrown error message as a C string.
+  virtual const char *getMessageString(void) { return message_.c_str(); }
+};
+
+#endif
diff --git a/asio/asio.h b/asio/asio.h
new file mode 100644 (file)
index 0000000..3003130
--- /dev/null
@@ -0,0 +1,955 @@
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+/*\r
+       Steinberg Audio Stream I/O API\r
+       (c) 1997 - 1999, Steinberg Soft- und Hardware GmbH\r
+\r
+       ASIO Interface Specification v 2.0\r
+\r
+       basic concept is an i/o synchronous double-buffer scheme:\r
+       \r
+       on bufferSwitch(index == 0), host will read/write:\r
+\r
+               after ASIOStart(), the\r
+  read  first input buffer A (index 0)\r
+       |   will be invalid (empty)\r
+       *   ------------------------\r
+       |------------------------|-----------------------|\r
+       |                        |                       |\r
+       |  Input Buffer A (0)    |   Input Buffer B (1)  |\r
+       |                        |                       |\r
+       |------------------------|-----------------------|\r
+       |                        |                       |\r
+       |  Output Buffer A (0)   |   Output Buffer B (1) |\r
+       |                        |                       |\r
+       |------------------------|-----------------------|\r
+       *                        -------------------------\r
+       |                        before calling ASIOStart(),\r
+  write                      host will have filled output\r
+                             buffer B (index 1) already\r
+\r
+  *please* take special care of proper statement of input\r
+  and output latencies (see ASIOGetLatencies()), these\r
+  control sequencer sync accuracy\r
+\r
+*/\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+/*\r
+\r
+prototypes summary:\r
+\r
+ASIOError ASIOInit(ASIODriverInfo *info);\r
+ASIOError ASIOExit(void);\r
+ASIOError ASIOStart(void);\r
+ASIOError ASIOStop(void);\r
+ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);\r
+ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);\r
+ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
+ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);\r
+ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);\r
+ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);\r
+ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);\r
+ASIOError ASIOSetClockSource(long reference);\r
+ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);\r
+ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+       long bufferSize, ASIOCallbacks *callbacks);\r
+ASIOError ASIODisposeBuffers(void);\r
+ASIOError ASIOControlPanel(void);\r
+void *ASIOFuture(long selector, void *params);\r
+ASIOError ASIOOutputReady(void);\r
+\r
+*/\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+#ifndef __ASIO_H\r
+#define __ASIO_H\r
+\r
+// force 4 byte alignment\r
+#if defined(_MSC_VER) && !defined(__MWERKS__) \r
+#pragma pack(push,4)\r
+#elif PRAGMA_ALIGN_SUPPORTED\r
+#pragma options align = native\r
+#endif\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Type definitions\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+// number of samples data type is 64 bit integer\r
+#if NATIVE_INT64\r
+       typedef long long int ASIOSamples;\r
+#else\r
+       typedef struct ASIOSamples {\r
+               unsigned long hi;\r
+               unsigned long lo;\r
+       } ASIOSamples;\r
+#endif\r
+\r
+// Timestamp data type is 64 bit integer,\r
+// Time format is Nanoseconds.\r
+#if NATIVE_INT64\r
+       typedef long long int ASIOTimeStamp ;\r
+#else\r
+       typedef struct ASIOTimeStamp {\r
+               unsigned long hi;\r
+               unsigned long lo;\r
+       } ASIOTimeStamp;\r
+#endif\r
+\r
+// Samplerates are expressed in IEEE 754 64 bit double float,\r
+// native format as host computer\r
+#if IEEE754_64FLOAT\r
+       typedef double ASIOSampleRate;\r
+#else\r
+       typedef struct ASIOSampleRate {\r
+               char ieee[8];\r
+       } ASIOSampleRate;\r
+#endif\r
+\r
+// Boolean values are expressed as long\r
+typedef long ASIOBool;\r
+enum {\r
+       ASIOFalse = 0,\r
+       ASIOTrue = 1\r
+};\r
+\r
+// Sample Types are expressed as long\r
+typedef long ASIOSampleType;\r
+enum {\r
+       ASIOSTInt16MSB   = 0,\r
+       ASIOSTInt24MSB   = 1,           // used for 20 bits as well\r
+       ASIOSTInt32MSB   = 2,\r
+       ASIOSTFloat32MSB = 3,           // IEEE 754 32 bit float\r
+       ASIOSTFloat64MSB = 4,           // IEEE 754 64 bit double float\r
+\r
+       // these are used for 32 bit data buffer, with different alignment of the data inside\r
+       // 32 bit PCI bus systems can be more easily used with these\r
+       ASIOSTInt32MSB16 = 8,           // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32MSB18 = 9,           // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32MSB20 = 10,          // 32 bit data with 20 bit alignment\r
+       ASIOSTInt32MSB24 = 11,          // 32 bit data with 24 bit alignment\r
+       \r
+       ASIOSTInt16LSB   = 16,\r
+       ASIOSTInt24LSB   = 17,          // used for 20 bits as well\r
+       ASIOSTInt32LSB   = 18,\r
+       ASIOSTFloat32LSB = 19,          // IEEE 754 32 bit float, as found on Intel x86 architecture\r
+       ASIOSTFloat64LSB = 20,          // IEEE 754 64 bit double float, as found on Intel x86 architecture\r
+\r
+       // these are used for 32 bit data buffer, with different alignment of the data inside\r
+       // 32 bit PCI bus systems can more easily used with these\r
+       ASIOSTInt32LSB16 = 24,          // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32LSB18 = 25,          // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32LSB20 = 26,          // 32 bit data with 20 bit alignment\r
+       ASIOSTInt32LSB24 = 27           // 32 bit data with 24 bit alignment\r
+};\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Error codes\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef long ASIOError;\r
+enum {\r
+       ASE_OK = 0,             // This value will be returned whenever the call succeeded\r
+       ASE_SUCCESS = 0x3f4847a0,       // unique success return value for ASIOFuture calls\r
+       ASE_NotPresent = -1000, // hardware input or output is not present or available\r
+       ASE_HWMalfunction,      // hardware is malfunctioning (can be returned by any ASIO function)\r
+       ASE_InvalidParameter,   // input parameter invalid\r
+       ASE_InvalidMode,        // hardware is in a bad mode or used in a bad mode\r
+       ASE_SPNotAdvancing,     // hardware is not running when sample position is inquired\r
+       ASE_NoClock,            // sample clock or rate cannot be determined or is not present\r
+       ASE_NoMemory            // not enough memory for completing the request\r
+};\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Time Info support\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOTimeCode\r
+{       \r
+       double          speed;                  // speed relation (fraction of nominal speed)\r
+                                               // optional; set to 0. or 1. if not supported\r
+       ASIOSamples     timeCodeSamples;        // time in samples\r
+       unsigned long   flags;                  // some information flags (see below)\r
+       char future[64];\r
+} ASIOTimeCode;\r
+\r
+typedef enum ASIOTimeCodeFlags\r
+{\r
+       kTcValid                = 1,\r
+       kTcRunning              = 1 << 1,\r
+       kTcReverse              = 1 << 2,\r
+       kTcOnspeed              = 1 << 3,\r
+       kTcStill                = 1 << 4,\r
+       \r
+       kTcSpeedValid           = 1 << 8\r
+}  ASIOTimeCodeFlags;\r
+\r
+typedef struct AsioTimeInfo\r
+{\r
+       double          speed;                  // absolute speed (1. = nominal)\r
+       ASIOTimeStamp   systemTime;             // system time related to samplePosition, in nanoseconds\r
+                                               // on mac, must be derived from Microseconds() (not UpTime()!)\r
+                                               // on windows, must be derived from timeGetTime()\r
+       ASIOSamples     samplePosition;\r
+       ASIOSampleRate  sampleRate;             // current rate\r
+       unsigned long flags;                    // (see below)\r
+       char reserved[12];\r
+} AsioTimeInfo;\r
+\r
+typedef enum AsioTimeInfoFlags\r
+{\r
+       kSystemTimeValid        = 1,            // must always be valid\r
+       kSamplePositionValid    = 1 << 1,       // must always be valid\r
+       kSampleRateValid        = 1 << 2,\r
+       kSpeedValid             = 1 << 3,\r
+       \r
+       kSampleRateChanged      = 1 << 4,\r
+       kClockSourceChanged     = 1 << 5\r
+} AsioTimeInfoFlags;\r
+\r
+typedef struct ASIOTime                          // both input/output\r
+{\r
+       long reserved[4];                       // must be 0\r
+       struct AsioTimeInfo     timeInfo;       // required\r
+       struct ASIOTimeCode     timeCode;       // optional, evaluated if (timeCode.flags & kTcValid)\r
+} ASIOTime;\r
+\r
+/*\r
+\r
+using time info:\r
+it is recommended to use the new method with time info even if the asio\r
+device does not support timecode; continuous calls to ASIOGetSamplePosition\r
+and ASIOGetSampleRate are avoided, and there is a more defined relationship\r
+between callback time and the time info.\r
+\r
+see the example below.\r
+to initiate time info mode, after you have received the callbacks pointer in\r
+ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo\r
+as the argument. if this returns 1, host has accepted time info mode.\r
+now host expects the new callback bufferSwitchTimeInfo to be used instead\r
+of the old bufferSwitch method. the ASIOTime structure is assumed to be valid\r
+and accessible until the callback returns.\r
+\r
+using time code:\r
+if the device supports reading time code, it will call host's asioMessage callback\r
+with kAsioSupportsTimeCode as the selector. it may then fill the according\r
+fields and set the kTcValid flag.\r
+host will call the future method with the kAsioEnableTimeCodeRead selector when\r
+it wants to enable or disable tc reading by the device. you should also support\r
+the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example).\r
+\r
+note:\r
+the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions.\r
+as a matter of convention, the relationship between the sample\r
+position counter and the time code at buffer switch time is\r
+(ignoring offset between tc and sample pos when tc is running):\r
+\r
+on input:      sample 0 -> input  buffer sample 0 -> time code 0\r
+on output:     sample 0 -> output buffer sample 0 -> time code 0\r
+\r
+this means that for 'real' calculations, one has to take into account\r
+the according latencies.\r
+\r
+example:\r
+\r
+ASIOTime asioTime;\r
+\r
+in createBuffers()\r
+{\r
+       memset(&asioTime, 0, sizeof(ASIOTime));\r
+       AsioTimeInfo* ti = &asioTime.timeInfo;\r
+       ti->sampleRate = theSampleRate;\r
+       ASIOTimeCode* tc = &asioTime.timeCode;\r
+       tc->speed = 1.;\r
+       timeInfoMode = false;\r
+       canTimeCode = false;\r
+       if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1)\r
+       {\r
+               timeInfoMode = true;\r
+#if kCanTimeCode\r
+               if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1)\r
+                       canTimeCode = true;\r
+#endif\r
+       }\r
+}\r
+\r
+void switchBuffers(long doubleBufferIndex, bool processNow)\r
+{\r
+       if(timeInfoMode)\r
+       {\r
+               AsioTimeInfo* ti = &asioTime.timeInfo;\r
+               ti->flags =     kSystemTimeValid | kSamplePositionValid | kSampleRateValid;\r
+               ti->systemTime = theNanoSeconds;\r
+               ti->samplePosition = theSamplePosition;\r
+               if(ti->sampleRate != theSampleRate)\r
+                       ti->flags |= kSampleRateChanged;\r
+               ti->sampleRate = theSampleRate;\r
+\r
+#if kCanTimeCode\r
+               if(canTimeCode && timeCodeEnabled)\r
+               {\r
+                       ASIOTimeCode* tc = &asioTime.timeCode;\r
+                       tc->timeCodeSamples = tcSamples;                                                // tc in samples\r
+                       tc->flags = kTcValid | kTcRunning | kTcOnspeed;                 // if so...\r
+               }\r
+               ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);\r
+#else\r
+               callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);\r
+#endif\r
+       }\r
+       else\r
+               callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse);\r
+}\r
+\r
+ASIOError ASIOFuture(long selector, void *params)\r
+{\r
+       switch(selector)\r
+       {\r
+               case kAsioEnableTimeCodeRead:\r
+                       timeCodeEnabled = true;\r
+                       return ASE_SUCCESS;\r
+               case kAsioDisableTimeCodeRead:\r
+                       timeCodeEnabled = false;\r
+                       return ASE_SUCCESS;\r
+               case kAsioCanTimeInfo:\r
+                       return ASE_SUCCESS;\r
+               #if kCanTimeCode\r
+               case kAsioCanTimeCode:\r
+                       return ASE_SUCCESS;\r
+               #endif\r
+       }\r
+       return ASE_NotPresent;\r
+};\r
+\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// application's audio stream handler callbacks\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOCallbacks\r
+{\r
+       void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess);\r
+               // bufferSwitch indicates that both input and output are to be processed.\r
+               // the current buffer half index (0 for A, 1 for B) determines\r
+               // - the output buffer that the host should start to fill. the other buffer\r
+               //   will be passed to output hardware regardless of whether it got filled\r
+               //   in time or not.\r
+               // - the input buffer that is now filled with incoming data. Note that\r
+               //   because of the synchronicity of i/o, the input always has at\r
+               //   least one buffer latency in relation to the output.\r
+               // directProcess suggests to the host whether it should immedeately\r
+               // start processing (directProcess == ASIOTrue), or whether its process\r
+               // should be deferred because the call comes from a very low level\r
+               // (for instance, a high level priority interrupt), and direct processing\r
+               // would cause timing instabilities for the rest of the system. If in doubt,\r
+               // directProcess should be set to ASIOFalse.\r
+               // Note: bufferSwitch may be called at interrupt time for highest efficiency.\r
+\r
+       void (*sampleRateDidChange) (ASIOSampleRate sRate);\r
+               // gets called when the AudioStreamIO detects a sample rate change\r
+               // If sample rate is unknown, 0 is passed (for instance, clock loss\r
+               // when externally synchronized).\r
+\r
+       long (*asioMessage) (long selector, long value, void* message, double* opt);\r
+               // generic callback for various purposes, see selectors below.\r
+               // note this is only present if the asio version is 2 or higher\r
+\r
+       ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess);\r
+               // new callback with time info. makes ASIOGetSamplePosition() and various\r
+               // calls to ASIOGetSampleRate obsolete,\r
+               // and allows for timecode sync etc. to be preferred; will be used if\r
+               // the driver calls asioMessage with selector kAsioSupportsTimeInfo.\r
+} ASIOCallbacks;\r
+\r
+// asioMessage selectors\r
+enum\r
+{\r
+       kAsioSelectorSupported = 1,     // selector in <value>, returns 1L if supported,\r
+                                                               // 0 otherwise\r
+    kAsioEngineVersion,                        // returns engine (host) asio implementation version,\r
+                                                               // 2 or higher\r
+       kAsioResetRequest,                      // request driver reset. if accepted, this\r
+                                                               // will close the driver (ASIO_Exit() ) and\r
+                                                               // re-open it again (ASIO_Init() etc). some\r
+                                                               // drivers need to reconfigure for instance\r
+                                                               // when the sample rate changes, or some basic\r
+                                                               // changes have been made in ASIO_ControlPanel().\r
+                                                               // returns 1L; note the request is merely passed\r
+                                                               // to the application, there is no way to determine\r
+                                                               // if it gets accepted at this time (but it usually\r
+                                                               // will be).\r
+       kAsioBufferSizeChange,          // not yet supported, will currently always return 0L.\r
+                                                               // for now, use kAsioResetRequest instead.\r
+                                                               // once implemented, the new buffer size is expected\r
+                                                               // in <value>, and on success returns 1L\r
+       kAsioResyncRequest,                     // the driver went out of sync, such that\r
+                                                               // the timestamp is no longer valid. this\r
+                                                               // is a request to re-start the engine and\r
+                                                               // slave devices (sequencer). returns 1 for ok,\r
+                                                               // 0 if not supported.\r
+       kAsioLatenciesChanged,          // the drivers latencies have changed. The engine\r
+                                                               // will refetch the latencies.\r
+       kAsioSupportsTimeInfo,          // if host returns true here, it will expect the\r
+                                                               // callback bufferSwitchTimeInfo to be called instead\r
+                                                               // of bufferSwitch\r
+       kAsioSupportsTimeCode,          // supports time code reading/writing\r
+\r
+       kAsioSupportsInputMonitor,      // supports input monitoring\r
+\r
+       kAsioNumMessageSelectors\r
+};\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// (De-)Construction\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIODriverInfo\r
+{\r
+       long asioVersion;               // currently, 2\r
+       long driverVersion;             // driver specific\r
+       char name[32];\r
+       char errorMessage[124];\r
+       void *sysRef;                   // on input: system reference\r
+                                                       // (Windows: application main window handle, Mac & SGI: 0)\r
+} ASIODriverInfo;\r
+\r
+ASIOError ASIOInit(ASIODriverInfo *info);\r
+/* Purpose:\r
+         Initialize the AudioStreamIO.\r
+       Parameter:\r
+         info: pointer to an ASIODriver structure:\r
+           - asioVersion:\r
+                       - on input, the host version. *** Note *** this is 0 for earlier asio\r
+                       implementations, and the asioMessage callback is implemeted\r
+                       only if asioVersion is 2 or greater. sorry but due to a design fault\r
+                       the driver doesn't have access to the host version in ASIOInit :-(\r
+                       added selector for host (engine) version in the asioMessage callback\r
+                       so we're ok from now on.\r
+                       - on return, asio implementation version.\r
+                         older versions are 1\r
+                         if you support this version (namely, ASIO_outputReady() )\r
+                         this should be 2 or higher. also see the note in\r
+                         ASIO_getTimeStamp() !\r
+           - version: on return, the driver version (format is driver specific)\r
+           - name: on return, a null-terminated string containing the driver's name\r
+               - error message: on return, should contain a user message describing\r
+                 the type of error that occured during ASIOInit(), if any.\r
+               - sysRef: platform specific\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+         ASE_NoMemory, ASE_HWMalfunction are other possible error conditions\r
+*/\r
+\r
+ASIOError ASIOExit(void);\r
+/* Purpose:\r
+         Terminates the AudioStreamIO.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+       Notes: this implies ASIOStop() and ASIODisposeBuffers(),\r
+         meaning that no host callbacks must be accessed after ASIOExit().\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Start/Stop\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+ASIOError ASIOStart(void);\r
+/* Purpose:\r
+         Start input and output processing synchronously.\r
+         This will\r
+         - reset the sample counter to zero\r
+         - start the hardware (both input and output)\r
+           The first call to the hosts' bufferSwitch(index == 0) then tells\r
+           the host to read from input buffer A (index 0), and start\r
+           processing to output buffer A while output buffer B (which\r
+           has been filled by the host prior to calling ASIOStart())\r
+           is possibly sounding (see also ASIOGetLatencies()) \r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present, ASE_NotPresent\r
+         will be returned.\r
+         If the hardware fails to start, ASE_HWMalfunction will be returned.\r
+       Notes:\r
+         There is no restriction on the time that ASIOStart() takes\r
+         to perform (that is, it is not considered a realtime trigger).\r
+*/\r
+\r
+ASIOError ASIOStop(void);\r
+/* Purpose:\r
+         Stops input and output processing altogether.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+       Notes:\r
+         On return from ASIOStop(), the driver must in no\r
+         case call the hosts' bufferSwitch() routine.\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Inquiry methods and sample rate\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);\r
+/* Purpose:\r
+         Returns number of individual input/output channels.\r
+       Parameter:\r
+         numInputChannels will hold the number of available input channels\r
+         numOutputChannels will hold the number of available output channels\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If only inputs, or only outputs are available, the according\r
+         other parameter will be zero, and ASE_OK is returned.\r
+*/\r
+\r
+ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);\r
+/* Purpose:\r
+         Returns the input and output latencies. This includes\r
+         device specific delays, like FIFOs etc.\r
+       Parameter:\r
+         inputLatency will hold the 'age' of the first sample frame\r
+         in the input buffer when the hosts reads it in bufferSwitch()\r
+         (this is theoretical, meaning it does not include the overhead\r
+         and delay between the actual physical switch, and the time\r
+         when bufferSitch() enters).\r
+         This will usually be the size of one block in sample frames, plus\r
+         device specific latencies.\r
+\r
+         outputLatency will specify the time between the buffer switch,\r
+         and the time when the next play buffer will start to sound.\r
+         The next play buffer is defined as the one the host starts\r
+         processing after (or at) bufferSwitch(), indicated by the\r
+         index parameter (0 for buffer A, 1 for buffer B).\r
+         It will usually be either one block, if the host writes directly\r
+         to a dma buffer, or two or more blocks if the buffer is 'latched' by\r
+         the driver. As an example, on ASIOStart(), the host will have filled\r
+         the play buffer at index 1 already; when it gets the callback (with\r
+         the parameter index == 0), this tells it to read from the input\r
+         buffer 0, and start to fill the play buffer 0 (assuming that now\r
+         play buffer 1 is already sounding). In this case, the output\r
+         latency is one block. If the driver decides to copy buffer 1\r
+         at that time, and pass it to the hardware at the next slot (which\r
+         is most commonly done, but should be avoided), the output latency\r
+         becomes two blocks instead, resulting in a total i/o latency of at least\r
+         3 blocks. As memory access is the main bottleneck in native dsp processing,\r
+         and to acheive less latency, it is highly recommended to try to avoid\r
+         copying (this is also why the driver is the owner of the buffers). To\r
+         summarize, the minimum i/o latency can be acheived if the input buffer\r
+         is processed by the host into the output buffer which will physically\r
+         start to sound on the next time slice. Also note that the host expects\r
+         the bufferSwitch() callback to be accessed for each time slice in order\r
+         to retain sync, possibly recursively; if it fails to process a block in\r
+         time, it will suspend its operation for some time in order to recover.\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+*/\r
+\r
+ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
+/* Purpose:\r
+         Returns min, max, and preferred buffer sizes for input/output\r
+       Parameter:\r
+         minSize will hold the minimum buffer size\r
+         maxSize will hold the maxium possible buffer size\r
+         preferredSize will hold the preferred buffer size (a size which\r
+         best fits performance and hardware requirements)\r
+         granularity will hold the granularity at which buffer sizes\r
+         may differ. Usually, the buffer size will be a power of 2;\r
+         in this case, granularity will hold -1 on return, signalling\r
+         possible buffer sizes starting from minSize, increased in\r
+         powers of 2 up to maxSize.\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         When minimum and maximum buffer size are equal,\r
+         the preferred buffer size has to be the same value as well; granularity\r
+         should be 0 in this case.\r
+*/\r
+\r
+ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);\r
+/* Purpose:\r
+         Inquires the hardware for the available sample rates.\r
+       Parameter:\r
+         sampleRate is the rate in question.\r
+       Returns:\r
+         If the inquired sample rate is not supported, ASE_NoClock will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+*/\r
+ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);\r
+/* Purpose:\r
+         Get the current sample Rate.\r
+       Parameter:\r
+         currentRate will hold the current sample rate on return.\r
+       Returns:\r
+         If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);\r
+/* Purpose:\r
+         Set the hardware to the requested sample Rate. If sampleRate == 0,\r
+         enable external sync.\r
+       Parameter:\r
+         sampleRate: on input, the requested rate\r
+       Returns:\r
+         If sampleRate is unknown ASE_NoClock will be returned.\r
+         If the current clock is external, and sampleRate is != 0,\r
+         ASE_InvalidMode will be returned\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+typedef struct ASIOClockSource\r
+{\r
+       long index;                                     // as used for ASIOSetClockSource()\r
+       long associatedChannel;         // for instance, S/PDIF or AES/EBU\r
+       long associatedGroup;           // see channel groups (ASIOGetChannelInfo())\r
+       ASIOBool isCurrentSource;       // ASIOTrue if this is the current clock source\r
+       char name[32];                          // for user selection\r
+} ASIOClockSource;\r
+\r
+ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);\r
+/* Purpose:\r
+         Get the available external audio clock sources\r
+       Parameter:\r
+         clocks points to an array of ASIOClockSource structures:\r
+               - index: this is used to identify the clock source\r
+                 when ASIOSetClockSource() is accessed, should be\r
+                 an index counting from zero\r
+               - associatedInputChannel: the first channel of an associated\r
+                 input group, if any.\r
+               - associatedGroup: the group index of that channel.\r
+                 groups of channels are defined to seperate for\r
+                 instance analog, S/PDIF, AES/EBU, ADAT connectors etc,\r
+                 when present simultaniously. Note that associated channel\r
+                 is enumerated according to numInputs/numOutputs, means it\r
+                 is independant from a group (see also ASIOGetChannelInfo())\r
+                 inputs are associated to a clock if the physical connection\r
+                 transfers both data and clock (like S/PDIF, AES/EBU, or\r
+                 ADAT inputs). if there is no input channel associated with\r
+                 the clock source (like Word Clock, or internal oscillator), both\r
+                 associatedChannel and associatedGroup should be set to -1.\r
+               - isCurrentSource: on exit, ASIOTrue if this is the current clock\r
+                 source, ASIOFalse else\r
+               - name: a null-terminated string for user selection of the available sources.\r
+         numSources:\r
+             on input: the number of allocated array members\r
+             on output: the number of available clock sources, at least\r
+             1 (internal clock generator).\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+ASIOError ASIOSetClockSource(long index);\r
+/* Purpose:\r
+         Set the audio clock source\r
+       Parameter:\r
+         index as obtained from an inquiry to ASIOGetClockSources()\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If the clock can not be selected because an input channel which\r
+         carries the current clock source is active, ASE_InvalidMode\r
+         *may* be returned (this depends on the properties of the driver\r
+         and/or hardware).\r
+       Notes:\r
+         Should *not* return ASE_NoClock if there is no clock signal present\r
+         at the selected source; this will be inquired via ASIOGetSampleRate().\r
+         It should call the host callback procedure sampleRateHasChanged(),\r
+         if the switch causes a sample rate change, or if no external clock\r
+         is present at the selected source.\r
+*/\r
+\r
+ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+/* Purpose:\r
+         Inquires the sample position/time stamp pair.\r
+       Parameter:\r
+         sPos will hold the sample position on return. The sample\r
+         position is reset to zero when ASIOStart() gets called.\r
+         tStamp will hold the system time when the sample position\r
+         was latched.\r
+       Returns:\r
+         If no input/output is present, ASE_NotPresent will be returned.\r
+         If there is no clock, ASE_SPNotAdvancing will be returned.\r
+       Notes:\r
+\r
+         in order to be able to synchronise properly,\r
+         the sample position / time stamp pair must refer to the current block,\r
+         that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch()\r
+         callback and expect the time for the current block. thus, when requested\r
+         in the very first bufferSwitch after ASIO_Start(), the sample position\r
+         should be zero, and the time stamp should refer to the very time where\r
+         the stream was started. it also means that the sample position must be\r
+         block aligned. the driver must ensure proper interpolation if the system\r
+         time can not be determined for the block position. the driver is responsible\r
+         for precise time stamps as it usually has most direct access to lower\r
+         level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies()\r
+         are essential for precise media synchronization!\r
+*/\r
+\r
+typedef struct ASIOChannelInfo\r
+{\r
+       long channel;                   // on input, channel index\r
+       ASIOBool isInput;               // on input\r
+       ASIOBool isActive;              // on exit\r
+       long channelGroup;              // dto\r
+       ASIOSampleType type;    // dto\r
+       char name[32];                  // dto\r
+} ASIOChannelInfo;\r
+\r
+ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);\r
+/* Purpose:\r
+         retreive information about the nature of a channel\r
+       Parameter:\r
+         info: pointer to a ASIOChannelInfo structure with\r
+               - channel: on input, the channel index of the channel in question.\r
+               - isInput: on input, ASIOTrue if info for an input channel is\r
+                 requested, else output\r
+               - channelGroup: on return, the channel group that the channel\r
+                 belongs to. For drivers which support different types of\r
+                 channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces,\r
+                 there should be a reasonable grouping of these types. Groups\r
+                 are always independant form a channel index, that is, a channel\r
+                 index always counts from 0 to numInputs/numOutputs regardless\r
+                 of the group it may belong to.\r
+                 There will always be at least one group (group 0). Please\r
+                 also note that by default, the host may decide to activate\r
+                 channels 0 and 1; thus, these should belong to the most\r
+                 useful type (analog i/o, if present).\r
+               - type: on return, contains the sample type of the channel\r
+               - isActive: on return, ASIOTrue if channel is active as it was\r
+                 installed by ASIOCreateBuffers(), ASIOFalse else\r
+               - name:  describing the type of channel in question. Used to allow\r
+                 for user selection, and enabling of specific channels. examples:\r
+             "Analog In", "SPDIF Out" etc\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         If possible, the string should be organised such that the first\r
+         characters are most significantly describing the nature of the\r
+         port, to allow for identification even if the view showing the\r
+         port name is too small to display more than 8 characters, for\r
+         instance.\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Buffer preparation\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOBufferInfo\r
+{\r
+       ASIOBool isInput;                       // on input:  ASIOTrue: input, else output\r
+       long channelNum;                        // on input:  channel index\r
+       void *buffers[2];                       // on output: double buffer addresses\r
+} ASIOBufferInfo;\r
+\r
+ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+       long bufferSize, ASIOCallbacks *callbacks);\r
+\r
+/* Purpose:\r
+         Allocates input/output buffers for all input and output channels to be activated.\r
+       Parameter:\r
+         bufferInfos is a pointer to an array of ASIOBufferInfo structures:\r
+           - isInput: on input, ASIOTrue if the buffer is to be allocated\r
+             for an input, output buffer else\r
+           - channelNum: on input, the index of the channel in question\r
+             (counting from 0)\r
+           - buffers: on exit, 2 pointers to the halves of the channels' double-buffer.\r
+             the size of the buffer(s) of course depend on both the ASIOSampleType\r
+             as obtained from ASIOGetChannelInfo(), and bufferSize\r
+         numChannels is the sum of all input and output channels to be created;\r
+         thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo\r
+         structures.\r
+         bufferSize selects one of the possible buffer sizes as obtained from\r
+         ASIOGetBufferSizes().\r
+         callbacks is a pointer to an ASIOCallbacks structure.\r
+       Returns:\r
+         If not enough memory is available ASE_NoMemory will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If bufferSize is not supported, or one or more of the bufferInfos elements\r
+         contain invalid settings, ASE_InvalidMode will be returned.\r
+       Notes:\r
+         If individual channel selection is not possible but requested,\r
+         the driver has to handle this. namely, bufferSwitch() will only\r
+         have filled buffers of enabled outputs. If possible, processing\r
+         and buss activities overhead should be avoided for channels which\r
+         were not enabled here.\r
+*/\r
+\r
+ASIOError ASIODisposeBuffers(void);\r
+/* Purpose:\r
+         Releases all buffers for the device.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If no buffer were ever prepared, ASE_InvalidMode will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         This implies ASIOStop().\r
+*/\r
+\r
+ASIOError ASIOControlPanel(void);\r
+/* Purpose:\r
+         request the driver to start a control panel component\r
+         for device specific user settings. This will not be\r
+         accessed on some platforms (where the component is accessed\r
+         instead).\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If no panel is available ASE_NotPresent will be returned.\r
+         Actually, the return code is ignored.\r
+       Notes:\r
+         if the user applied settings which require a re-configuration\r
+         of parts or all of the enigine and/or driver (such as a change of\r
+         the block size), the asioMessage callback can be used (see\r
+         ASIO_Callbacks).\r
+*/\r
+\r
+ASIOError ASIOFuture(long selector, void *params);\r
+/* Purpose:\r
+         various\r
+       Parameter:\r
+         selector: operation Code as to be defined. zero is reserved for\r
+         testing purposes.\r
+         params: depends on the selector; usually pointer to a structure\r
+         for passing and retreiving any type and amount of parameters.\r
+       Returns:\r
+         the return value is also selector dependant. if the selector\r
+         is unknown, ASE_InvalidParameter should be returned to prevent\r
+         further calls with this selector. on success, ASE_SUCCESS\r
+         must be returned (note: ASE_OK is *not* sufficient!)\r
+       Notes:\r
+         see selectors defined below.    \r
+*/\r
+\r
+enum\r
+{\r
+       kAsioEnableTimeCodeRead = 1,    // no arguments\r
+       kAsioDisableTimeCodeRead,               // no arguments\r
+       kAsioSetInputMonitor,                   // ASIOInputMonitor* in params\r
+       kAsioTransport,                                 // ASIOTransportParameters* in params\r
+       kAsioSetInputGain,                              // ASIOChannelControls* in params, apply gain\r
+       kAsioGetInputMeter,                             // ASIOChannelControls* in params, fill meter\r
+       kAsioSetOutputGain,                             // ASIOChannelControls* in params, apply gain\r
+       kAsioGetOutputMeter,                    // ASIOChannelControls* in params, fill meter\r
+       kAsioCanInputMonitor,                   // no arguments for kAsioCanXXX selectors\r
+       kAsioCanTimeInfo,\r
+       kAsioCanTimeCode,\r
+       kAsioCanTransport,\r
+       kAsioCanInputGain,\r
+       kAsioCanInputMeter,\r
+       kAsioCanOutputGain,\r
+       kAsioCanOutputMeter\r
+};\r
+\r
+typedef struct ASIOInputMonitor\r
+{\r
+       long input;             // this input was set to monitor (or off), -1: all\r
+       long output;    // suggested output for monitoring the input (if so)\r
+       long gain;              // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB)\r
+       ASIOBool state; // ASIOTrue => on, ASIOFalse => off\r
+       long pan;               // suggested pan, 0 => all left, 0x7fffffff => right\r
+} ASIOInputMonitor;\r
+\r
+typedef struct ASIOChannelControls\r
+{\r
+       long channel;                   // on input, channel index\r
+       ASIOBool isInput;               // on input\r
+       long gain;                              // on input,  ranges 0 thru 0x7fffffff\r
+       long meter;                             // on return, ranges 0 thru 0x7fffffff\r
+       char future[32];\r
+} ASIOChannelControls;\r
+\r
+typedef struct ASIOTransportParameters\r
+{\r
+       long command;           // see enum below\r
+       ASIOSamples samplePosition;\r
+       long track;\r
+       long trackSwitches[16];         // 512 tracks on/off\r
+       char future[64];\r
+} ASIOTransportParameters;\r
+\r
+enum\r
+{\r
+       kTransStart = 1,\r
+       kTransStop,\r
+       kTransLocate,           // to samplePosition\r
+       kTransPunchIn,\r
+       kTransPunchOut,\r
+       kTransArmOn,            // track\r
+       kTransArmOff,           // track\r
+       kTransMonitorOn,        // track\r
+       kTransMonitorOff,       // track\r
+       kTransArm,                      // trackSwitches\r
+       kTransMonitor           // trackSwitches\r
+};\r
+\r
+ASIOError ASIOOutputReady(void);\r
+/* Purpose:\r
+         this tells the driver that the host has completed processing\r
+         the output buffers. if the data format required by the hardware\r
+         differs from the supported asio formats, but the hardware\r
+         buffers are DMA buffers, the driver will have to convert\r
+         the audio stream data; as the bufferSwitch callback is\r
+         usually issued at dma block switch time, the driver will\r
+         have to convert the *previous* host buffer, which increases\r
+         the output latency by one block.\r
+         when the host finds out that ASIOOutputReady() returns\r
+         true, it will issue this call whenever it completed\r
+         output processing. then the driver can convert the\r
+         host data directly to the dma buffer to be played next,\r
+         reducing output latency by one block.\r
+         another way to look at it is, that the buffer switch is called\r
+         in order to pass the *input* stream to the host, so that it can\r
+         process the input into the output, and the output stream is passed\r
+         to the driver when the host has completed its process.\r
+       Parameter:\r
+               None\r
+       Returns:\r
+         only if the above mentioned scenario is given, and a reduction\r
+         of output latency can be acheived by this mechanism, should\r
+         ASE_OK be returned. otherwise (and usually), ASE_NotPresent\r
+         should be returned in order to prevent further calls to this\r
+         function. note that the host may want to determine if it is\r
+         to use this when the system is not yet fully initialized, so\r
+         ASE_OK should always be returned if the mechanism makes sense.          \r
+       Notes:\r
+         please remeber to adjust ASIOGetLatencies() according to\r
+         whether ASIOOutputReady() was ever called or not, if your\r
+         driver supports this scenario.\r
+         also note that the engine may fail to call ASIO_OutputReady()\r
+         in time in overload cases. as already mentioned, bufferSwitch\r
+      should be called for every block regardless of whether a block\r
+      could be processed in time.\r
+*/\r
+\r
+// restore old alignment\r
+#if defined(_MSC_VER) && !defined(__MWERKS__) \r
+#pragma pack(pop)\r
+#elif PRAGMA_ALIGN_SUPPORTED\r
+#pragma options align = reset\r
+#endif\r
+\r
+#endif\r
+\r
diff --git a/asio/asiodrivers.h b/asio/asiodrivers.h
new file mode 100644 (file)
index 0000000..2ddf7ad
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __AsioDrivers__\r
+#define __AsioDrivers__\r
+\r
+#include "ginclude.h"\r
+\r
+#if MAC\r
+#include "CodeFragments.hpp"\r
+\r
+class AsioDrivers : public CodeFragments\r
+\r
+#elif WINDOWS\r
+#include <windows.h>\r
+#include "asiolist.h"\r
+\r
+class AsioDrivers : public AsioDriverList\r
+\r
+#elif SGI || BEOS\r
+#include "asiolist.h"\r
+\r
+class AsioDrivers : public AsioDriverList\r
+\r
+#else\r
+#error implement me\r
+#endif\r
+\r
+{\r
+public:\r
+       AsioDrivers();\r
+       ~AsioDrivers();\r
+       \r
+       bool getCurrentDriverName(char *name);\r
+       long getDriverNames(char **names, long maxDrivers);\r
+       bool loadDriver(char *name);\r
+       void removeCurrentDriver();\r
+       long getCurrentDriverIndex() {return curIndex;}\r
+protected:\r
+       unsigned long connID;\r
+       long curIndex;\r
+};\r
+\r
+#endif\r
diff --git a/asio/asiolist.h b/asio/asiolist.h
new file mode 100644 (file)
index 0000000..01c64f0
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __asiolist__\r
+#define __asiolist__\r
+\r
+#define DRVERR                 -5000\r
+#define DRVERR_INVALID_PARAM           DRVERR-1\r
+#define DRVERR_DEVICE_ALREADY_OPEN     DRVERR-2\r
+#define DRVERR_DEVICE_NOT_FOUND                DRVERR-3\r
+\r
+#define MAXPATHLEN                     512\r
+#define MAXDRVNAMELEN          128\r
+\r
+struct asiodrvstruct\r
+{\r
+       int                                             drvID;\r
+       CLSID                                   clsid;\r
+       char                                    dllpath[MAXPATHLEN];\r
+       char                                    drvname[MAXDRVNAMELEN];\r
+       LPVOID                                  asiodrv;\r
+       struct asiodrvstruct    *next;\r
+};\r
+\r
+typedef struct asiodrvstruct ASIODRVSTRUCT;\r
+typedef ASIODRVSTRUCT  *LPASIODRVSTRUCT;\r
+\r
+class AsioDriverList {\r
+public:\r
+       AsioDriverList();\r
+       ~AsioDriverList();\r
+       \r
+       LONG asioOpenDriver (int,VOID **);\r
+       LONG asioCloseDriver (int);\r
+\r
+       // nice to have\r
+       LONG asioGetNumDev (VOID);\r
+       LONG asioGetDriverName (int,char *,int);                \r
+       LONG asioGetDriverPath (int,char *,int);\r
+       LONG asioGetDriverCLSID (int,CLSID *);\r
+\r
+       // or use directly access\r
+       LPASIODRVSTRUCT lpdrvlist;\r
+       int                             numdrv;\r
+};\r
+\r
+typedef class AsioDriverList *LPASIODRIVERLIST;\r
+\r
+#endif\r
diff --git a/asio/asiosys.h b/asio/asiosys.h
new file mode 100644 (file)
index 0000000..37f7a48
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __asiosys__\r
+       #define __asiosys__\r
+\r
+       #ifdef WIN32\r
+               #undef MAC \r
+               #define PPC 0\r
+               #define WINDOWS 1\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+\r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+       \r
+       #elif BEOS\r
+               #define MAC 0\r
+               #define PPC 0\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               \r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+               \r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+\r
+       #elif SGI\r
+               #define MAC 0\r
+               #define PPC 0\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+               \r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+               \r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+\r
+       #else   // MAC\r
+\r
+               #define MAC 1\r
+               #define PPC 1\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+\r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+\r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+       #endif\r
+\r
+#endif\r
diff --git a/asio/ginclude.h b/asio/ginclude.h
new file mode 100644 (file)
index 0000000..b627dc2
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __gInclude__\r
+#define __gInclude__\r
+\r
+#if SGI \r
+       #undef BEOS \r
+       #undef MAC \r
+       #undef WINDOWS\r
+       //\r
+       #define ASIO_BIG_ENDIAN 1\r
+       #define ASIO_CPU_MIPS 1\r
+#elif defined WIN32\r
+       #undef BEOS \r
+       #undef MAC \r
+       #undef SGI\r
+       #define WINDOWS 1\r
+       #define ASIO_LITTLE_ENDIAN 1\r
+       #define ASIO_CPU_X86 1\r
+#elif BEOS\r
+       #undef MAC \r
+       #undef SGI\r
+       #undef WINDOWS\r
+       #define ASIO_LITTLE_ENDIAN 1\r
+       #define ASIO_CPU_X86 1\r
+       //\r
+#else\r
+       #define MAC 1\r
+       #undef BEOS \r
+       #undef WINDOWS\r
+       #undef SGI\r
+       #define ASIO_BIG_ENDIAN 1\r
+       #define ASIO_CPU_PPC 1\r
+#endif\r
+\r
+// always\r
+#define NATIVE_INT64 0\r
+#define IEEE754_64FLOAT 1\r
+\r
+#endif // __gInclude__\r
old mode 100755 (executable)
new mode 100644 (file)
index ba66165..313be34
@@ -3,7 +3,7 @@
 #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
 #   Free Software Foundation, Inc.
 
-timestamp='2001-04-20'
+timestamp='2004-02-26'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
old mode 100644 (file)
new mode 100755 (executable)
index a06a480..7d3f49f
@@ -3,7 +3,7 @@
 #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
 #   Free Software Foundation, Inc.
 
-timestamp='2001-04-20'
+timestamp='2004-02-26'
 
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
index 909cf958c645b58908cbf6246e6883321a45ba6a..0ad7b372c02e4fb43184aca187d2122eea35c056 100644 (file)
@@ -1,11 +1,14 @@
 # Process this file with autoconf to produce a configure script.
-AC_INIT(RtAudio, 2.1, gary@ccrma.stanford.edu, rtaudio)
+AC_INIT(RtAudio, 3.0, gary@ccrma.stanford.edu, rtaudio)
 AC_CONFIG_SRCDIR(RtAudio.cpp)
 AC_CONFIG_FILES(tests/Makefile)
 
+# Fill GXX with something before test.
+AC_SUBST( GXX, ["no"] )
+
 # Checks for programs.
 AC_PROG_CC
-AC_PROG_CXX(CC g++ c++ cxx)
+AC_PROG_CXX(g++ CC c++ cxx)
 
 # Checks for libraries.
 AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
@@ -25,7 +28,7 @@ AC_ARG_ENABLE(debug,
   [AC_SUBST( debug, [] ) AC_SUBST( cflags, [-O2] ) AC_SUBST( object_path, [Release] ) AC_MSG_RESULT(no)])
 
 # Check compiler and use -Wall if gnu.
-if test $GXX = "yes" ; then
+if [test $GXX = "yes" ;] then
   AC_SUBST( warn, [-Wall] )
 fi
 
@@ -34,15 +37,39 @@ AC_CANONICAL_HOST
 AC_MSG_CHECKING(for audio API)
 case $host in
   *-*-linux*)
-  AC_ARG_WITH(alsa, [  --with-alsa = choose native ALSA API support (linux only)], [AC_SUBST( sound_api, [-D__LINUX_ALSA__] ) AC_MSG_RESULT(using ALSA) ], [AC_SUBST( sound_api, [-D__LINUX_OSS__] ) AC_MSG_RESULT(using OSS)])
+  AC_SUBST( sound_api, [_NO_API_] )
+  AC_ARG_WITH(jack, [  --with-jack = choose JACK server support (linux only)], [AC_SUBST( sound_api, [-D__LINUX_JACK__] ) AC_MSG_RESULT(using JACK)], )
+  if [test $sound_api = -D__LINUX_JACK__;] then
+    TEMP_LIBS=$LIBS
+    AC_CHECK_LIB(jack, jack_client_new, , AC_MSG_ERROR(JACK support requires the jack library!))
+    AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(Jack support also requires the asound library!))
+    LIBS="`pkg-config --cflags --libs jack` $TEMP_LIBS -lasound"
+    audio_apis="-D__LINUX_JACK__"
+  fi
 
-  if test $sound_api = -D__LINUX_ALSA__; then
+  # Look for Alsa flag
+  AC_ARG_WITH(alsa, [  --with-alsa = choose native ALSA API support (linux only)], [AC_SUBST( sound_api, [-D__LINUX_ALSA__] ) AC_MSG_RESULT(using ALSA)], )
+  if [test $sound_api = -D__LINUX_ALSA__;] then
     AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))
+    audio_apis="-D__LINUX_ALSA__ $audio_apis"
+  fi
+
+  # Look for OSS flag
+  AC_ARG_WITH(oss, [  --with-oss = choose OSS API support (linux only)], [AC_SUBST( sound_api, [-D__LINUX_OSS__] ) AC_MSG_RESULT(using OSS)], )
+  if test $sound_api = -D__LINUX_OSS__; then
+    audio_apis="-D__LINUX_OSS__ $audio_apis"
+  fi
+
+  # If no audio api flags specified, use OSS
+  if [test $sound_api = _NO_API_;] then
+    AC_SUBST( sound_api, [-D__LINUX_OSS__] )
+    AC_MSG_RESULT(using OSS)
+    AC_SUBST( audio_apis, [-D__LINUX_OSS__] )
   fi
   ;;
 
   *-sgi*)
-  AC_SUBST( sound_api, [-D__IRIX_AL__] )
+  AC_SUBST( audio_apis, ["-D__IRIX_AL__ -LANG:std -w"] )
   AC_MSG_RESULT(using IRIX AL)
   AC_CHECK_LIB(audio, alOpenPort, , AC_MSG_ERROR(IRIX audio support requires the audio library!) )
   ;;
@@ -50,7 +77,7 @@ case $host in
   *-apple*)
   # Check for CoreAudio framework
   AC_CHECK_HEADER(CoreAudio/CoreAudio.h,
-    [AC_SUBST( sound_api, [-D__MACOSX_CORE__] )],
+    [AC_SUBST( audio_apis, [-D__MACOSX_CORE__] )],
     [AC_MSG_ERROR(CoreAudio header files not found!)] )
   AC_SUBST( frameworks, ["-framework CoreAudio"] )
   AC_CHECK_LIB(stdc++, printf, , AC_MSG_ERROR(RtAudio requires the C++ library!) )
index c65a58cff411cace677c5a9edd7d3157628975b7..a104bd48b4e05c1a257bd0be8d4155238573f38f 100644 (file)
@@ -51,7 +51,7 @@ WARN_LOGFILE           =
 #---------------------------------------------------------------------------
 # configuration options related to the input files
 #---------------------------------------------------------------------------
-INPUT                  = tutorial.txt ../../RtAudio.h
+INPUT                  = tutorial.txt ../../RtAudio.h ../../RtError.h
 FILE_PATTERNS          = 
 RECURSIVE              = NO
 EXCLUDE                = 
index b34356f58f9cb438b92f9e98fb54036b87d454a3..888ebe6421630a3cdb19e19744e94c4793697d27 100644 (file)
@@ -1,9 +1,9 @@
 <HR>
 
-<table><tr><td><img src="../images/ccrma.gif">
-  <td>&copy;2001-2002 Gary P. Scavone, CCRMA, Stanford University. All Rights Reserved.<br>
-  Maintained by Gary P. Scavone, <a href="mailto:gary@ccrma.stanford.edu">gary@ccrma.stanford.edu</a><P>
+<table><tr><td><img src="../images/mcgill.gif" width=165></td>
+  <td>&copy;2001-2004 Gary P. Scavone, McGill University. All Rights Reserved.<br>
+  Maintained by Gary P. Scavone, <a href="mailto:gary@music.mcgill.ca">gary@music.mcgill.ca</a></td></tr>
 </table>
 
 </BODY>
-</HTML>
\ No newline at end of file
+</HTML>
index 8458ac9717ab1df5aa2cbabda023cdfa3cdd0f75..a368db28f3429ef756be2a4a68414058a52bc737 100644 (file)
@@ -6,4 +6,4 @@
 <BODY BGCOLOR="#FFFFFF">
 <CENTER>
 <a class="qindex" href="index.html">Tutorial</a> &nbsp; <a class="qindex" href="annotated.html">Class/Enum List</a> &nbsp; <a class="qindex" href="files.html">File List</a> &nbsp; <a class="qindex" href="functions.html">Compound Members</a> &nbsp; </CENTER>
-<HR>
\ No newline at end of file
+<HR>
index 49bd4adc265f9c5a2c40486bf0313af95b570cd7..6623c0e5f2ee8dedc022ab0dbea5b506343df602 100644 (file)
@@ -2,51 +2,49 @@
 
 <BODY BGCOLOR="white">
 
-- \ref intro
-- \ref download
-- \ref start
-- \ref error
-- \ref probing
-- \ref settings
-- \ref playbackb
-- \ref playbackc
-- \ref recording
-- \ref duplex
-- \ref methods
-- \ref compiling
-- \ref debug
-- \ref osnotes
-- \ref acknowledge
-- \ref license
+<CENTER>\ref intro &nbsp;&nbsp; \ref changes &nbsp;&nbsp;\ref download &nbsp;&nbsp; \ref start &nbsp;&nbsp; \ref error &nbsp;&nbsp; \ref probing &nbsp;&nbsp; \ref settings &nbsp;&nbsp; \ref playbackb &nbsp;&nbsp; \ref playbackc &nbsp;&nbsp; \ref recording &nbsp;&nbsp; \ref duplex &nbsp;&nbsp; \ref multi &nbsp;&nbsp; \ref methods &nbsp;&nbsp; \ref compiling &nbsp;&nbsp; \ref debug &nbsp;&nbsp; \ref apinotes &nbsp;&nbsp; \ref acknowledge &nbsp;&nbsp; \ref license</CENTER>
 
 \section intro Introduction
 
-RtAudio is a C++ class which provides a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA and OSS), Macintosh OS X, SGI, and Windows (DirectSound and ASIO) operating systems.  RtAudio significantly simplifies the process of interacting with computer audio hardware.  It was designed with the following goals:
+RtAudio is a set of C++ classes which provide a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, JACK, and OSS), Macintosh OS X, SGI, and Windows (DirectSound and ASIO) operating systems.  RtAudio significantly simplifies the process of interacting with computer audio hardware.  It was designed with the following goals:
 
 <UL>
   <LI>object oriented C++ design</LI>
   <LI>simple, common API across all supported platforms</LI>
-  <LI>single independent header and source file for easy inclusion in programming projects</LI>
+  <LI>only two header files and one source file for easy inclusion in programming projects</LI>
+  <LI>allow simultaneous multi-api support</LI>
   <LI>blocking functionality</LI>
   <LI>callback functionality</LI>
   <LI>extensive audio device parameter control</LI>
   <LI>audio device capability probing</LI>
   <LI>automatic internal conversion for data format, channel number compensation, de-interleaving, and byte-swapping</LI>
-  <LI>control over multiple audio streams and devices with a single instance</LI>
 </UL>
 
-RtAudio incorporates the concept of audio streams, which represent audio output (playback) and/or input (recording).  Available audio devices and their capabilities can be enumerated and then specified when opening a stream.  When allowed by the underlying audio API, multiple streams can run at the same time and a single device can serve multiple streams.  See the \ref osnotes section for information specific to each of the supported audio APIs.
+RtAudio incorporates the concept of audio streams, which represent audio output (playback) and/or input (recording).  Available audio devices and their capabilities can be enumerated and then specified when opening a stream.  Where applicable, multiple API support can be compiled and a particular API specified when creating an RtAudio instance.  See the \ref apinotes section for information specific to each of the supported audio APIs.
 
-The RtAudio API provides both blocking (synchronous) and callback (asyncronous) functionality.  Callbacks are typically used in conjunction with graphical user interfaces (GUI).  Blocking functionality is often necessary for explicit control of multiple input/output stream synchronization or when audio must be synchronized with other system events.
+The RtAudio API provides both blocking (synchronous) and callback (asynchronous) functionality.  Callbacks are typically used in conjunction with graphical user interfaces (GUI).  Blocking functionality is often necessary for explicit control of multiple input/output stream synchronization or when audio must be synchronized with other system events.
 
-\section download Download
+\section changes What's New (Version 3.0)
+
+RtAudio now allows simultaneous multi-api support.  For example, you can compile RtAudio to provide both DirectSound and ASIO support on Windows platforms or ALSA, JACK, and OSS support on Linux platforms.  This was accomplished by creating an abstract base class, RtApi, with subclasses for each supported API (RtApiAlsa, RtApiJack, RtApiOss, RtApiDs, RtApiAsio, RtApiCore, and RtApiAl).  The class RtAudio is now a "controller" which creates an instance of an RtApi subclass based on the user's API choice via an optional RtAudio::RtAudioApi instantiation argument.  If no API is specified, RtAudio attempts to make a "logical" API selection.
+
+Support for the JACK low-latency audio server has been added with this version of RtAudio.  It is necessary to have the JACK server running before creating an instance of RtAudio.
+
+Several API changes have been made in version 3.0 of RtAudio in an effort to provide more consistent behavior across all supported audio APIs.  The most significant of these changes is that multiple stream support from a single RtAudio instance has been discontinued.  As a result, stream identifier input arguments are no longer required.  Also, the RtAudio::streamWillBlock() function was poorly supported by most APIs and has been deprecated (though the function still exists in those subclasses of RtApi that do allow it to be implemented).
+
+The RtAudio::getDeviceInfo() function was modified to return a globally defined RtAudioDeviceInfo structure.  This structure is a simplified version of the previous RTAUDIO_DEVICE structure.  In addition, the RTAUDIO_FORMAT structure was renamed RtAudioFormat and defined globally within RtAudio.h.  These changes were made for clarity and to better conform with standard C++ programming practices.
+
+The RtError class declaration and definition have been extracted to a separate file (RtError.h).  This was done in preparation for a new release of the RtMidi class (planned for Summer 2004).
 
-Latest Release (24 October 2002): <A href="http://www-ccrma.stanford.edu/~gary/rtaudio/release/rtaudio-2.1.1.tar.gz">Version 2.1.1 (165 kB tar/gzipped)</A>
+\section download Download
 
+Latest Release (11 March 2004): <A href="http://music.mcgill.ca/~gary/rtaudio/release/rtaudio-3.0.tar.gz">Version 3.0 (200 kB tar/gzipped)</A>
 
 \section start Getting Started
 
-The first thing that must be done when using RtAudio is to create an instance of the class.  The default constructor RtAudio::RtAudio() scans the underlying audio system to verify that at least one device is available.  RtAudio often uses C++ exceptions to report errors, necessitating try/catch blocks around most member functions.  The following code example demonstrates default object construction and destruction:
+With version 3.0, it is now possible to compile multiple API support on a given platform and to specify an API choice during class instantiation.  In the examples that follow, no API will be specified (in which case, RtAudio attempts to select the most "logical" available API).
+
+The first thing that must be done when using RtAudio is to create an instance of the class.  The default constructor scans the underlying audio system to verify that at least one device is available.  RtAudio often uses C++ exceptions to report errors, necessitating try/catch blocks around most member functions.  The following code example demonstrates default object construction and destruction:
 
 \code
 
@@ -62,6 +60,7 @@ int main()
   }
   catch (RtError &error) {
     // Handle the exception here
+    error.printMessage();
   }
 
   // Clean up
@@ -74,7 +73,7 @@ Obviously, this example doesn't demonstrate any of the real functionality of RtA
 
 \section error Error Handling
 
-RtAudio uses a C++ exception handler called RtError, which is declared and defined within the RtAudio class files.  The RtError class is quite simple but it does allow errors to be "caught" by RtError::TYPE.  Almost all RtAudio methods can "throw" an RtError, most typically if an invalid stream identifier is supplied to a method or a driver error occurs.  There are a number of cases within RtAudio where warning messages may be displayed but an exception is not thrown.  There is a private RtAudio method, error(), which can be modified to globally control how these messages are handled and reported.
+RtAudio uses a C++ exception handler called RtError, which is declared and defined in RtError.h.  The RtError class is quite simple but it does allow errors to be "caught" by RtError::Type.  Almost all RtAudio methods can "throw" an RtError, most typically if a driver error occurs or a stream function is called when no stream is open.  There are a number of cases within RtAudio where warning messages may be displayed but an exception is not thrown.  There is a protected RtAudio method, error(), which can be modified to globally control how these messages are handled and reported.  By default, error messages are not automatically displayed in RtAudio unless the preprocessor definition __RTAUDIO_DEBUG__ is defined.  Messages associated with caught exceptions can be displayed with, for example, the RtError::printMessage() function.
 
 
 \section probing Probing Device Capabilities
@@ -105,11 +104,11 @@ int main()
   int devices = audio->getDeviceCount();
 
   // Scan through devices for various capabilities
-  RtAudio::RTAUDIO_DEVICE info;
+  RtAudioDeviceInfo info;
   for (int i=1; i<=devices; i++) {
 
     try {
-      audio->getDeviceInfo(i, &info);
+      info = audio->getDeviceInfo(i);
     }
     catch (RtError &error) {
       error.printMessage();
@@ -117,8 +116,8 @@ int main()
     }
 
     // Print, for example, the maximum number of output channels for each device
-    cout << "device = " << i;
-    cout << ": maximum output channels = " << info.maxOutputChannels << "\n";
+    std::cout << "device = " << i;
+    std::cout << ": maximum output channels = " << info.outputChannels << "\n";
   }
 
   // Clean up
@@ -128,43 +127,38 @@ int main()
 }
 \endcode
 
-The RTAUDIO_DEVICE structure is defined in RtAudio.h and provides a variety of information useful in assessing the capabilities of a device:
+The RtAudioDeviceInfo structure is defined in RtAudio.h and provides a variety of information useful in assessing the capabilities of a device:
 
 \code
-  typedef struct {
-    char name[128];
-    bool probed;                          // true if the device probe was successful.
-    int maxOutputChannels;
-    int maxInputChannels;
-    int maxDuplexChannels;
-    int minOutputChannels;
-    int minInputChannels;
-    int minDuplexChannels;
-    bool hasDuplexSupport;                // true if duplex mode is supported.
-    bool isDefault;                       // true if this is the default output or input device.
-    int nSampleRates;                     // Number of discrete rates, or -1 if range supported.
-    double sampleRates[MAX_SAMPLE_RATES]; // Supported sample rates, or {min, max} if range.
-    RTAUDIO_FORMAT nativeFormats;
-  } RTAUDIO_DEVICE;
+  typedef struct RtAudioDeviceInfo{
+    std::string name;             // Character string device identifier.
+    bool probed;                  // true if the device capabilities were successfully probed.
+    int outputChannels;           // Maximum output channels supported by device.
+    int inputChannels;            // Maximum input channels supported by device.
+    int duplexChannels;           // Maximum simultaneous input/output channels supported by device.
+    bool isDefault;               // true if this is the default output or input device.
+    std::vector<int> sampleRates; // Supported sample rates.
+    RtAudioFormat nativeFormats;  // Bit mask of supported data formats.
+  };
 \endcode
 
 The following data formats are defined and fully supported by RtAudio:
 
 \code
-  typedef unsigned long RTAUDIO_FORMAT;
-  static const RTAUDIO_FORMAT  RTAUDIO_SINT8;   // Signed 8-bit integer
-  static const RTAUDIO_FORMAT  RTAUDIO_SINT16;  // Signed 16-bit integer
-  static const RTAUDIO_FORMAT  RTAUDIO_SINT24;  // Signed 24-bit integer (upper 3 bytes of 32-bit signed integer.)
-  static const RTAUDIO_FORMAT  RTAUDIO_SINT32;  // Signed 32-bit integer
-  static const RTAUDIO_FORMAT  RTAUDIO_FLOAT32; // 32-bit float normalized between +/- 1.0
-  static const RTAUDIO_FORMAT  RTAUDIO_FLOAT64; // 64-bit double normalized between +/- 1.0
+  typedef unsigned long RtAudioFormat;
+  static const RtAudioFormat  RTAUDIO_SINT8;   // Signed 8-bit integer
+  static const RtAudioFormat  RTAUDIO_SINT16;  // Signed 16-bit integer
+  static const RtAudioFormat  RTAUDIO_SINT24;  // Signed 24-bit integer (upper 3 bytes of 32-bit signed integer.)
+  static const RtAudioFormat  RTAUDIO_SINT32;  // Signed 32-bit integer
+  static const RtAudioFormat  RTAUDIO_FLOAT32; // 32-bit float normalized between +/- 1.0
+  static const RtAudioFormat  RTAUDIO_FLOAT64; // 64-bit double normalized between +/- 1.0
 \endcode
 
-The <I>nativeFormats</I> member of the RtAudio::RTAUDIO_DEVICE structure is a bit mask of the above formats which are natively supported by the device.  However, RtAudio will automatically provide format conversion if a particular format is not natively supported.  When the <I>probed</I> member of the RTAUDIO_DEVICE structure is false, the remaining structure members are undefined and the device is probably unuseable.
+The <I>nativeFormats</I> member of the RtAudioDeviceInfo structure is a bit mask of the above formats which are natively supported by the device.  However, RtAudio will automatically provide format conversion if a particular format is not natively supported.  When the <I>probed</I> member of the RtAudioDeviceInfo structure is false, the remaining structure members are undefined and the device is probably unuseable.
 
-In general, the user need not be concerned with the minimum channel values reported in the RTAUDIO_DEVICE structure.  While some audio devices may require a minimum channel value > 1, RtAudio will provide automatic channel number compensation when the number of channels set by the user is less than that required by the device.  Channel compensation is <I>NOT</I> possible when the number of channels set by the user is greater than that supported by the device.
+While some audio devices may require a minimum channel value greater than one, RtAudio will provide automatic channel number compensation when the number of channels set by the user is less than that required by the device.  Channel compensation is <I>NOT</I> possible when the number of channels set by the user is greater than that supported by the device.
 
-It should be noted that the capabilities reported by a device driver or underlying audio API are not always accurate and/or may be dependent on a combination of device settings.  For this reason, RtAudio does not rely on the reported values when attempting to open a stream.
+It should be noted that the capabilities reported by a device driver or underlying audio API are not always accurate and/or may be dependent on a combination of device settings.  For this reason, RtAudio does not typically rely on the queried values when attempting to open a stream.
 
 
 \section settings Device Settings
@@ -178,24 +172,30 @@ The next step in using RtAudio is to open a stream with particular device and pa
 int main()
 {
   int channels = 2;
-  int sample_rate = 44100;
-  int buffer_size = 256;  // 256 sample frames
-  int n_buffers = 4;      // number of internal buffers used by device
-  int device = 0;         // 0 indicates the default or first available device
-  int stream;             // our stream identifier
+  int sampleRate = 44100;
+  int bufferSize = 256;  // 256 sample frames
+  int nBuffers = 4;      // number of internal buffers used by device
+  int device = 0;        // 0 indicates the default or first available device
   RtAudio *audio;
 
   // Instantiate RtAudio and open a stream within a try/catch block
   try {
     audio = new RtAudio();
-    stream = audio->openStream(device, channels, 0, 0, RtAudio::RTAUDIO_FLOAT32,
-                               sample_rate, &buffer_size, n_buffers);
   }
   catch (RtError &error) {
     error.printMessage();
     exit(EXIT_FAILURE);
   }
 
+  try {
+    audio->openStream(device, channels, 0, 0, RTAUDIO_FLOAT32,
+                      sampleRate, &bufferSize, nBuffers);
+  }
+  catch (RtError &error) {
+    error.printMessage();
+    // Perhaps try other parameters?
+  }
+
   // Clean up
   delete audio;
 
@@ -203,11 +203,11 @@ int main()
 }
 \endcode
 
-The RtAudio::openStream() method attempts to open a stream with a specified set of parameter values.  When successful, a stream identifier is returned.  In this case, we attempt to open a two channel playback stream with the default output device, 32-bit floating point data, a sample rate of 44100 Hz, a frame rate of 256 sample frames per read/write, and 4 internal device buffers.  When device = 0, RtAudio first attempts to open the default audio device with the given parameters.  If that attempt fails, RtAudio searches through the remaining available devices in an effort to find a device which will meet the given parameters.  If all attempts are unsuccessful, an RtError is thrown.  When a non-zero device value is specified, an attempt is made to open that device only (device = 1 specifies the first identified device, as reported by RtAudio::getDeviceInfo()).
+The RtAudio::openStream() method attempts to open a stream with a specified set of parameter values.  In this case, we attempt to open a two channel playback stream with the default output device, 32-bit floating point data, a sample rate of 44100 Hz, a frame rate of 256 sample frames per read/write, and 4 internal device buffers.  When device = 0, RtAudio first attempts to open the default audio device with the given parameters.  If that attempt fails, RtAudio searches through the remaining available devices in an effort to find a device which will meet the given parameters.  If all attempts are unsuccessful, an RtError is thrown.  When a non-zero device value is specified, an attempt is made to open that device \e ONLY (device = 1 specifies the first identified device, as reported by RtAudio::getDeviceInfo()).
 
-RtAudio provides four signed integer and two floating point data formats which can be specified using the RtAudio::RTAUDIO_FORMAT parameter values mentioned earlier.  If the opened device does not natively support the given format, RtAudio will automatically perform the necessary data format conversion.
+RtAudio provides four signed integer and two floating point data formats which can be specified using the RtAudioFormat parameter values mentioned earlier.  If the opened device does not natively support the given format, RtAudio will automatically perform the necessary data format conversion.
 
-The <I>bufferSize</I> parameter specifies the desired number of sample frames which will be written to and/or read from a device per write/read operation.  The <I>nBuffers</I> parameter is used in setting the underlying device buffer parameters.  Both the <I>bufferSize</I> and <I>nBuffers</I> parameters can be used to control stream latency though there is no guarantee that the passed values will be those used by a device (the <I>nBuffers</I> parameter is ignored when using the OS X CoreAudio and the Windows ASIO APIs).  In general, lower values for both parameters will produce less latency but perhaps less robust performance.  Both parameters can be specified with values of zero, in which case the smallest allowable values will be used.  The <I>bufferSize</I> parameter is passed as a pointer and the actual value used by the stream is set during the device setup procedure.  <I>bufferSize</I> values should be a power of two.  Optimal and allowable buffer values tend to vary between systems and devices.  Check the \ref osnotes section for general guidelines.
+The <I>bufferSize</I> parameter specifies the desired number of sample frames which will be written to and/or read from a device per write/read operation.  The <I>nBuffers</I> parameter is used in setting the underlying device buffer parameters.  Both the <I>bufferSize</I> and <I>nBuffers</I> parameters can be used to control stream latency though there is no guarantee that the passed values will be those used by a device (the <I>nBuffers</I> parameter is ignored when using the OS X CoreAudio, Linux Jack, and the Windows ASIO APIs).  In general, lower values for both parameters will produce less latency but perhaps less robust performance.  Both parameters can be specified with values of zero, in which case the smallest allowable values will be used.  The <I>bufferSize</I> parameter is passed as a pointer and the actual value used by the stream is set during the device setup procedure.  <I>bufferSize</I> values should be a power of two.  Optimal and allowable buffer values tend to vary between systems and devices.  Check the \ref apinotes section for general guidelines.
 
 As noted earlier, the device capabilities reported by a driver or underlying audio API are not always accurate and/or may be dependent on a combination of device settings.  Because of this, RtAudio does not attempt to query a device's capabilities or use previously reported values when opening a device.  Instead, RtAudio simply attempts to set the given parameters on a specified device and then checks whether the setup is successful or not.
 
@@ -225,18 +225,17 @@ int main()
 {
   int count;
   int channels = 2;
-  int sample_rate = 44100;
-  int buffer_size = 256;  // 256 sample frames
-  int n_buffers = 4;      // number of internal buffers used by device
+  int sampleRate = 44100;
+  int bufferSize = 256;  // 256 sample frames
+  int nBuffers = 4;      // number of internal buffers used by device
   float *buffer;
-  int device = 0;         // 0 indicates the default or first available device
-  int stream;             // our stream identifier
+  int device = 0;        // 0 indicates the default or first available device
   RtAudio *audio;
 
   // Open a stream during RtAudio instantiation
   try {
-    audio = new RtAudio(&stream, device, channels, 0, 0, RtAudio::RTAUDIO_FLOAT32,
-                        sample_rate, &buffer_size, n_buffers);
+    audio = new RtAudio(device, channels, 0, 0, RTAUDIO_FLOAT32,
+                        sampleRate, &bufferSize, nBuffers);
   }
   catch (RtError &error) {
     error.printMessage();
@@ -245,38 +244,38 @@ int main()
 
   try {
     // Get a pointer to the stream buffer
-    buffer = (float *) audio->getStreamBuffer(stream);
+    buffer = (float *) audio->getStreamBuffer();
 
     // Start the stream
-    audio->startStream(stream);
+    audio->startStream();
   }
   catch (RtError &error) {
     error.printMessage();
     goto cleanup;
   }
 
-  // An example loop which runs for about 40000 sample frames
+  // An example loop which runs for 40000 sample frames
   count = 0;
   while (count < 40000) {
-    // Generate your samples and fill the buffer with buffer_size sample frames of data
+    // Generate your samples and fill the buffer with bufferSize sample frames of data
     ...
 
     // Trigger the output of the data buffer
     try {
-      audio->tickStream(stream);
+      audio->tickStream();
     }
     catch (RtError &error) {
       error.printMessage();
       goto cleanup;
     }
 
-    count += buffer_size;
+    count += bufferSize;
   }
 
   try {
     // Stop and close the stream
-    audio->stopStream(stream);
-    audio->closeStream(stream);
+    audio->stopStream();
+    audio->closeStream();
   }
   catch (RtError &error) {
     error.printMessage();
@@ -289,9 +288,9 @@ int main()
 }
 \endcode
 
-The first thing to notice in this example is that we attempt to open a stream during class instantiation with an overloaded constructor.  This constructor simply combines the functionality of the default constructor, used earlier, and the RtAudio::openStream() method.  Again, we have specified a device value of 0, indicating that the default or first available device meeting the given parameters should be used.  The integer identifier of the opened stream is returned via the <I>stream</I> pointer value.  An attempt is made to open the stream with the specified <I>bufferSize</I> value.  However, it is possible that the device will not accept this value, in which case the closest allowable size is used and returned via the pointer value.   The constructor can fail if no available devices are found, or a memory allocation or device driver error occurs.  Note that you should not call the RtAudio destructor if an exception is thrown during instantiation.
+The first thing to notice in this example is that we attempt to open a stream during class instantiation with an overloaded constructor.  This constructor simply combines the functionality of the default constructor, used earlier, and the RtAudio::openStream() method.  Again, we have specified a device value of 0, indicating that the default or first available device meeting the given parameters should be used.  An attempt is made to open the stream with the specified <I>bufferSize</I> value.  However, it is possible that the device will not accept this value, in which case the closest allowable size is used and returned via the pointer value.   The constructor can fail if no available devices are found, or a memory allocation or device driver error occurs.  Note that you should not call the RtAudio destructor if an exception is thrown during instantiation.
 
-Because RtAudio can typically be used to simultaneously control more than a single stream, it is necessary that the stream identifier be provided to nearly all public methods.  Assuming the constructor is successful, it is necessary to get a pointer to the buffer, provided by RtAudio, for use in feeding data to/from the opened stream.  Note that the user should <I>NOT</I> attempt to deallocate the stream buffer memory ... memory management for the stream buffer will be automatically controlled by RtAudio.  After starting the stream with RtAudio::startStream(), one simply fills that buffer, which is of length equal to the returned <I>bufferSize</I> value, with interleaved audio data (in the specified format) for playback.  Finally, a call to the RtAudio::tickStream() routine triggers a blocking write call for the stream.
+Assuming the constructor is successful, it is necessary to get a pointer to the buffer, provided by RtAudio, for use in feeding data to/from the opened stream.  Note that the user should <I>NOT</I> attempt to deallocate the stream buffer memory ... memory management for the stream buffer will be automatically controlled by RtAudio.  After starting the stream with RtAudio::startStream(), one simply fills that buffer, which is of length equal to the returned <I>bufferSize</I> value, with interleaved audio data (in the specified format) for playback.  Finally, a call to the RtAudio::tickStream() routine triggers a blocking write call for the stream.
 
 In general, one should call the RtAudio::stopStream() and RtAudio::closeStream() methods after finishing with a stream.  However, both methods will implicitly be called during object destruction if necessary.
 
@@ -306,14 +305,14 @@ The primary difference in using RtAudio with callback functionality involves the
 #include "RtAudio.h"
 
 // Two-channel sawtooth wave generator.
-int sawtooth(char *buffer, int buffer_size, void *data)
+int sawtooth(char *buffer, int bufferSize, void *data)
 {
   int i, j;
   double *my_buffer = (double *) buffer;
   double *my_data = (double *) data;
 
   // Write interleaved audio data.
-  for (i=0; i<buffer_size; i++) {
+  for (i=0; i<bufferSize; i++) {
     for (j=0; j<2; j++) {
       *my_buffer++ = my_data[j];
 
@@ -328,19 +327,18 @@ int sawtooth(char *buffer, int buffer_size, void *data)
 int main()
 {
   int channels = 2;
-  int sample_rate = 44100;
-  int buffer_size = 256;  // 256 sample frames
-  int n_buffers = 4;      // number of internal buffers used by device
-  int device = 0;         // 0 indicates the default or first available device
-  int stream;             // our stream identifier
+  int sampleRate = 44100;
+  int bufferSize = 256;  // 256 sample frames
+  int nBuffers = 4;      // number of internal buffers used by device
+  int device = 0;        // 0 indicates the default or first available device
   double data[2];
   char input;
   RtAudio *audio;
 
   // Open a stream during RtAudio instantiation
   try {
-    audio = new RtAudio(&stream, device, channels, 0, 0, RtAudio::RTAUDIO_FLOAT64,
-                        sample_rate, &buffer_size, n_buffers);
+    audio = new RtAudio(device, channels, 0, 0, RTAUDIO_FLOAT64,
+                        sampleRate, &bufferSize, nBuffers);
   }
   catch (RtError &error) {
     error.printMessage();
@@ -349,23 +347,23 @@ int main()
 
   try {
     // Set the stream callback function
-    audio->setStreamCallback(stream, &sawtooth, (void *)data);
+    audio->setStreamCallback(&sawtooth, (void *)data);
 
     // Start the stream
-    audio->startStream(stream);
+    audio->startStream();
   }
   catch (RtError &error) {
     error.printMessage();
     goto cleanup;
   }
 
-  cout << "\nPlaying ... press <enter> to quit.\n";
-  cin.get(input);
+  std::cout << "\nPlaying ... press <enter> to quit.\n";
+  std::cin.get(input);
 
   try {
     // Stop and close the stream
-    audio->stopStream(stream);
-    audio->closeStream(stream);
+    audio->stopStream();
+    audio->closeStream();
   }
   catch (RtError &error) {
     error.printMessage();
@@ -378,7 +376,7 @@ int main()
 }
 \endcode
 
-After opening the device in exactly the same way as the previous example (except with a data format change), we must set our callback function for the stream using RtAudio::setStreamCallback().  When the underlying audio API uses blocking calls (OSS, ALSA, SGI, and Windows DirectSound), this method will spawn a new process (or thread) which automatically calls the callback function when more data is needed.  Callback-based audio APIs (OS X CoreAudio and ASIO) implement their own event notification schemes.  Note that the callback function is called only when the stream is "running" (between calls to the RtAudio::startStream() and RtAudio::stopStream() methods).  The last argument to RtAudio::setStreamCallback() is a pointer to arbitrary data that you wish to access from within your callback function.
+After opening the device in exactly the same way as the previous example (except with a data format change), we must set our callback function for the stream using RtAudio::setStreamCallback().  When the underlying audio API uses blocking calls (OSS, ALSA, SGI, and Windows DirectSound), this method will spawn a new process (or thread) which automatically calls the callback function when more data is needed.  Callback-based audio APIs (OS X CoreAudio Linux Jack, and ASIO) implement their own event notification schemes.  Note that the callback function is called only when the stream is "running" (between calls to the RtAudio::startStream() and RtAudio::stopStream() methods).  The last argument to RtAudio::setStreamCallback() is a pointer to arbitrary data that you wish to access from within your callback function.
 
 In this example, we stop the stream with an explicit call to RtAudio::stopStream().  When using callback functionality, it is also possible to stop a stream by returning a non-zero value from the callback function.
 
@@ -398,18 +396,17 @@ int main()
 {
   int count;
   int channels = 2;
-  int sample_rate = 44100;
-  int buffer_size = 256;  // 256 sample frames
-  int n_buffers = 4;      // number of internal buffers used by device
+  int sampleRate = 44100;
+  int bufferSize = 256;  // 256 sample frames
+  int nBuffers = 4;      // number of internal buffers used by device
   float *buffer;
-  int device = 0;         // 0 indicates the default or first available device
-  int stream;             // our stream identifier
+  int device = 0;        // 0 indicates the default or first available device
   RtAudio *audio;
 
   // Instantiate RtAudio and open a stream.
   try {
     audio = new RtAudio(&stream, 0, 0, device, channels,
-                        RtAudio::RTAUDIO_FLOAT32, sample_rate, &buffer_size, n_buffers);
+                        RTAUDIO_FLOAT32, sampleRate, &bufferSize, nBuffers);
   }
   catch (RtError &error) {
     error.printMessage();
@@ -418,10 +415,10 @@ int main()
 
   try {
     // Get a pointer to the stream buffer
-    buffer = (float *) audio->getStreamBuffer(stream);
+    buffer = (float *) audio->getStreamBuffer();
 
     // Start the stream
-    audio->startStream(stream);
+    audio->startStream();
   }
   catch (RtError &error) {
     error.printMessage();
@@ -434,22 +431,22 @@ int main()
 
     // Read a buffer of data
     try {
-      audio->tickStream(stream);
+      audio->tickStream();
     }
     catch (RtError &error) {
       error.printMessage();
       goto cleanup;
     }
 
-    // Process the input samples (buffer_size sample frames) that were read
+    // Process the input samples (bufferSize sample frames) that were read
     ...
 
-    count += buffer_size;
+    count += bufferSize;
   }
 
   try {
     // Stop the stream
-    audio->stopStream(stream);
+    audio->stopStream();
   }
   catch (RtError &error) {
     error.printMessage();
@@ -476,13 +473,13 @@ Finally, it is easy to use RtAudio for simultaneous audio input/output, or duple
 #include "RtAudio.h"
 
 // Pass-through function.
-int scale(char *buffer, int buffer_size, void *)
+int scale(char *buffer, int bufferSize, void *)
 {
   // Note: do nothing here for pass through.
   double *my_buffer = (double *) buffer;
 
   // Scale input data for output.
-  for (int i=0; i<buffer_size; i++) {
+  for (int i=0; i<bufferSize; i++) {
     // Do for two channels.
     *my_buffer++ *= 0.5;
     *my_buffer++ *= 0.5;
@@ -494,18 +491,17 @@ int scale(char *buffer, int buffer_size, void *)
 int main()
 {
   int channels = 2;
-  int sample_rate = 44100;
-  int buffer_size = 256;  // 256 sample frames
-  int n_buffers = 4;      // number of internal buffers used by device
-  int device = 0;         // 0 indicates the default or first available device
-  int stream;             // our stream identifier
+  int sampleRate = 44100;
+  int bufferSize = 256;  // 256 sample frames
+  int nBuffers = 4;      // number of internal buffers used by device
+  int device = 0;        // 0 indicates the default or first available device
   char input;
   RtAudio *audio;
 
   // Open a stream during RtAudio instantiation
   try {
-    audio = new RtAudio(&stream, device, channels, device, channels, RtAudio::RTAUDIO_FLOAT64,
-                        sample_rate, &buffer_size, n_buffers);
+    audio = new RtAudio(device, channels, device, channels, RTAUDIO_FLOAT64,
+                        sampleRate, &bufferSize, nBuffers);
   }
   catch (RtError &error) {
     error.printMessage();
@@ -514,23 +510,23 @@ int main()
 
   try {
     // Set the stream callback function
-    audio->setStreamCallback(stream, &scale, NULL);
+    audio->setStreamCallback(&scale, NULL);
 
     // Start the stream
-    audio->startStream(stream);
+    audio->startStream();
   }
   catch (RtError &error) {
     error.printMessage();
     goto cleanup;
   }
 
-  cout << "\nRunning duplex ... press <enter> to quit.\n";
-  cin.get(input);
+  std::cout << "\nRunning duplex ... press <enter> to quit.\n";
+  std::cin.get(input);
 
   try {
     // Stop and close the stream
-    audio->stopStream(stream);
-    audio->closeStream(stream);
+    audio->stopStream();
+    audio->closeStream();
   }
   catch (RtError &error) {
     error.printMessage();
@@ -547,26 +543,30 @@ When an RtAudio stream is running in duplex mode (nonzero input <I>AND</I> outpu
 
 As we see with this example, the write-read sequence of operations does not preclude the use of RtAudio in situations where input data is first processed and then output through a duplex stream.  When the stream buffer is first allocated, it is initialized with zeros, which produces no audible result when output to the device.  In this example, anything recorded by the audio stream input will be scaled and played out during the next round of audio processing.
 
-Note that duplex operation can also be achieved by opening one output stream and one input stream using the same or different devices.  However, there may be timing problems when attempting to use two different devices, due to possible device clock variations, unless a common external "sync" is provided.  This becomes even more difficult to achieve using two separate callback streams because it is not possible to <I>explicitly</I> control the calling order of the callback functions.
+Note that duplex operation can also be achieved by opening one output stream instance and one input stream instance using the same or different devices.  However, there may be timing problems when attempting to use two different devices, due to possible device clock variations, unless a common external "sync" is provided.  This becomes even more difficult to achieve using two separate callback streams because it is not possible to <I>explicitly</I> control the calling order of the callback functions.
+
+
+\section multi Using Simultaneous Multiple APIs
+
+Because support for each audio API is encapsulated in a specific RtApi subclass, it is possible to compile and instantiate multiple API-specific subclasses on a given operating system.  For example, one can compile both the RtApiDs and RtApiAsio classes on Windows operating systems by providing the appropriate preprocessor definitions, include files, and libraries for each.  In a run-time situation, one might first attempt to determine whether any ASIO device drivers exist.  This can be done by specifying the api argument RtAudio::WINDOWS_ASIO when attempting to create an instance of RtAudio.  If an RtError is thrown (indicating no available drivers), then an instance of RtAudio with the api argument RtAudio::WINDOWS_DS can be created.  Alternately, if no api argument is specified, RtAudio will first look for ASIO drivers and then DirectSound drivers (on Linux systems, the default API search order is Jack, Alsa, and finally OSS).  In theory, it should also be possible to have separate instances of RtAudio open at the same time with different underlying audio API support, though this has not been tested.  It is difficult to know how well different audio APIs can simultaneously coexist on a given operating system.  In particular, it is most unlikely that the same device could be simultaneously controlled with two different audio APIs.
 
 
 \section methods Summary of Methods
 
-The following is short summary of public methods (not including constructors and the destructor) provided by RtAudio:
+The following is short summary of public methods (not including constructors and the destructor) provided by RtAudio:
 
 <UL>
 <LI>RtAudio::openStream(): opens a stream with the specified parameters.</LI>
-<LI>RtAudio::setStreamCallback(): sets a user-defined callback function for a given stream.</LI>
-<LI>RtAudio::cancelStreamCallback(): cancels a callback process and function for a given stream.</LI>
+<LI>RtAudio::setStreamCallback(): sets a user-defined callback function for the stream.</LI>
+<LI>RtAudio::cancelStreamCallback(): cancels a callback process and function for the stream.</LI>
 <LI>RtAudio::getDeviceCount(): returns the number of audio devices available.</LI>
-<LI>RtAudio::getDeviceInfo(): fills a user-supplied RTAUDIO_DEVICE structure for a specified device.</LI>
+<LI>RtAudio::getDeviceInfo(): returns an RtAudioDeviceInfo structure for a specified device.</LI>
 <LI>RtAudio::getStreamBuffer(): returns a pointer to the stream buffer.</LI>
-<LI>RtAudio::tickStream(): triggers processing of input/output data for a stream (blocking).</LI>
-<LI>RtAudio::closeStream(): closes the specified stream (implicitly called during object destruction).  Once a stream is closed, the stream identifier is invalid and should not be used in calling any other RtAudio methods.</LI>
-<LI>RtAudio::startStream(): (re)starts the specified stream, typically after it has been stopped with either stopStream() or abortStream() or after first opening the stream.</LI>
-<LI>RtAudio::stopStream(): stops the specified stream, allowing any remaining samples in the queue to be played out and/or read in.  This does not implicitly call RtAudio::closeStream().</LI>
-<LI>RtAudio::abortStream(): stops the specified stream, discarding any remaining samples in the queue.  This does not implicitly call closeStream().</LI>
-<LI>RtAudio::streamWillBlock(): queries a stream to determine whether a call to the <I>tickStream()</I> method will block.  A return value of 0 indicates that the stream will NOT block.  A positive return value indicates the  number of sample frames that cannot yet be processed without blocking.</LI>
+<LI>RtAudio::tickStream(): triggers processing of input/output data for the stream (blocking).</LI>
+<LI>RtAudio::closeStream(): closes the stream (implicitly called during object destruction).</LI>
+<LI>RtAudio::startStream(): (re)starts the stream, typically after it has been stopped with either stopStream() or abortStream() or after first opening the stream.</LI>
+<LI>RtAudio::stopStream(): stops the stream, allowing any remaining samples in the queue to be played out and/or read in.  This does not implicitly call RtAudio::closeStream().</LI>
+<LI>RtAudio::abortStream(): stops the stream, discarding any remaining samples in the queue.  This does not implicitly call closeStream().</LI>
 </UL>
 
 
@@ -579,6 +579,7 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
 <TR BGCOLOR="beige">
   <TD WIDTH="5%"><B>OS:</B></TD>
   <TD WIDTH="5%"><B>Audio API:</B></TD>
+  <TD WIDTH="5%"><B>C++ Class:</B></TD>
   <TD WIDTH="5%"><B>Preprocessor Definition:</B></TD>
   <TD WIDTH="5%"><B>Library or Framework:</B></TD>
   <TD><B>Example Compiler Statement:</B></TD>
@@ -586,13 +587,23 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
 <TR>
   <TD>Linux</TD>
   <TD>ALSA</TD>
+  <TD>RtApiAlsa</TD>
   <TD>__LINUX_ALSA__</TD>
   <TD><TT>asound, pthread</TT></TD>
   <TD><TT>g++ -Wall -D__LINUX_ALSA__ -o probe probe.cpp RtAudio.cpp -lasound -lpthread</TT></TD>
 </TR>
+<TR>
+  <TD>Linux</TD>
+  <TD>Jack Audio Server</TD>
+  <TD>RtApiJack</TD>
+  <TD>__LINUX_JACK__</TD>
+  <TD><TT>jack, pthread</TT></TD>
+  <TD><TT>g++ -Wall -D__LINUX_JACK__ -o probe probe.cpp RtAudio.cpp `pkg-config --cflags --libs jack` -lpthread</TT></TD>
+</TR>
 <TR>
   <TD>Linux</TD>
   <TD>OSS</TD>
+  <TD>RtApiOss</TD>
   <TD>__LINUX_OSS__</TD>
   <TD><TT>pthread</TT></TD>
   <TD><TT>g++ -Wall -D__LINUX_OSS__ -o probe probe.cpp RtAudio.cpp -lpthread</TT></TD>
@@ -600,13 +611,15 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
 <TR>
   <TD>Macintosh OS X</TD>
   <TD>CoreAudio</TD>
+  <TD>RtApiCore</TD>
   <TD>__MACOSX_CORE__</TD>
   <TD><TT>pthread, stdc++, CoreAudio</TT></TD>
-  <TD><TT>CC -Wall -D__MACOSX_CORE__ -o probe probe.cpp RtAudio.cpp -framework CoreAudio -lstdc++ -lpthread</TT></TD>
+  <TD><TT>g++ -Wall -D__MACOSX_CORE__ -o probe probe.cpp RtAudio.cpp -framework CoreAudio -lpthread</TT></TD>
 </TR>
 <TR>
   <TD>Irix</TD>
   <TD>AL</TD>
+  <TD>RtApiAl</TD>
   <TD>__IRIX_AL__</TD>
   <TD><TT>audio, pthread</TT></TD>
   <TD><TT>CC -Wall -D__IRIX_AL__ -o probe probe.cpp RtAudio.cpp -laudio -lpthread</TT></TD>
@@ -614,6 +627,7 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
 <TR>
   <TD>Windows</TD>
   <TD>Direct Sound</TD>
+  <TD>RtApiDs</TD>
   <TD>__WINDOWS_DS__</TD>
   <TD><TT>dsound.lib (ver. 5.0 or higher), multithreaded</TT></TD>
   <TD><I>compiler specific</I></TD>
@@ -621,6 +635,7 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
 <TR>
   <TD>Windows</TD>
   <TD>ASIO</TD>
+  <TD>RtApiAsio</TD>
   <TD>__WINDOWS_ASIO__</TD>
   <TD><I>various ASIO header and source files</I></TD>
   <TD><I>compiler specific</I></TD>
@@ -628,27 +643,31 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
 </TABLE>
 <P>
 
-The example compiler statements above could be used to compile the <TT>probe.cpp</TT> example file, assuming that <TT>probe.cpp</TT>, <TT>RtAudio.h</TT>, and <TT>RtAudio.cpp</TT> all exist in the same directory.
+The example compiler statements above could be used to compile the <TT>probe.cpp</TT> example file, assuming that <TT>probe.cpp</TT>, <TT>RtAudio.h</TT>, <tt>RtError.h</tt>, and <TT>RtAudio.cpp</TT> all exist in the same directory.
 
 \section debug Debugging
 
-If you are having problems getting RtAudio to run on your system, try passing the preprocessor definition <TT>__RTAUDIO_DEBUG__</TT> to the compiler (or uncomment the definition at the bottom of RtAudio.h).  A variety of warning messages will be displayed which may help in determining the problem.
+If you are having problems getting RtAudio to run on your system, try passing the preprocessor definition <TT>__RTAUDIO_DEBUG__</TT> to the compiler (or uncomment the definition at the bottom of RtAudio.h).  A variety of warning messages will be displayed which may help in determining the problem.  Also try using the programs included in the <tt>test</tt> directory.  The program <tt>info</tt> displays the queried capabilities of all hardware devices found.
 
-\section osnotes OS Notes
+\section apinotes API Notes
 
-RtAudio is designed to provide a common API across the various supported operating systems and audio libraries.  Despite that, some issues need to be mentioned with regard to each.
+RtAudio is designed to provide a common API across the various supported operating systems and audio libraries.  Despite that, some issues should be mentioned with regard to each.
 
 \subsection linux Linux:
 
-RtAudio for Linux was developed under Redhat distributions 7.0 - 7.2.  Two different audio APIs are supported on Linux platforms: OSS and <A href="http://www.alsa-project.org/">ALSA</A>.  The OSS API has existed for at least 6 years and the Linux kernel is distributed with free versions of OSS audio drivers.  Therefore, a generic Linux system is most likely to have OSS support.  The ALSA API, although relatively new, is now part of the Linux development kernel and offers significantly better functionality than the OSS API.  RtAudio provides support for the 0.9 and higher versions of ALSA.  Input/output latency on the order of 15 milliseconds can typically be achieved under both OSS or ALSA by fine-tuning the RtAudio buffer parameters (without kernel modifications).  Latencies on the order of 5 milliseconds or less can be achieved using a low-latency kernel patch and increasing FIFO scheduling priority.  The pthread library, which is used for callback functionality, is a standard component of all Linux distributions.
+RtAudio for Linux was developed under Redhat distributions 7.0 - Fedora.  Three different audio APIs are supported on Linux platforms: OSS, <A href="http://www.alsa-project.org/">ALSA</A>, and <A href="http://jackit.sourceforge.net/">Jack</A>.  The OSS API has existed for at least 6 years and the Linux kernel is distributed with free versions of OSS audio drivers.  Therefore, a generic Linux system is most likely to have OSS support (though the availability and quality of OSS drivers for new hardware is decreasing).  The ALSA API, although relatively new, is now part of the Linux development kernel and offers significantly better functionality than the OSS API.  RtAudio provides support for the 1.0 and higher versions of ALSA.  Jack, which is still in development, is a low-latency audio server, written primarily for the GNU/Linux operating system. It can connect a number of different applications to an audio device, as well as allow them to share audio between themselves.  Input/output latency on the order of 15 milliseconds can typically be achieved using any of the Linux APIs by fine-tuning the RtAudio buffer parameters (without kernel modifications).  Latencies on the order of 5 milliseconds or less can be achieved using a low-latency kernel patch and increasing FIFO scheduling priority.  The pthread library, which is used for callback functionality, is a standard component of all Linux distributions.
 
 The ALSA library includes OSS emulation support.  That means that you can run programs compiled for the OSS API even when using the ALSA drivers and library.  It should be noted however that OSS emulation under ALSA is not perfect.  Specifically, channel number queries seem to consistently produce invalid results.  While OSS emulation is successful for the majority of RtAudio tests, it is recommended that the native ALSA implementation of RtAudio be used on systems which have ALSA drivers installed.
 
 The ALSA implementation of RtAudio makes no use of the ALSA "plug" interface.  All necessary data format conversions, channel compensation, de-interleaving, and byte-swapping is handled by internal RtAudio routines.
 
+The Jack API is based on a callback scheme.  RtAudio provides blocking functionality, in addition to callback functionality, within the context of that behavior.  It should be noted, however, that the best performance is achieved when using RtAudio's callback functionality with the Jack API.  At the moment, only one RtAudio instance can be connected to the Jack server.  Because RtAudio does not provide a mechanism for allowing the user to specify particular channels (or ports) of a device, it simply opens the first <I>N</I> enumerated Jack ports for input/output.
+
 \subsection macosx Macintosh OS X (CoreAudio):
 
-The Apple CoreAudio API is based on a callback scheme.  RtAudio provides blocking functionality, in addition to callback functionality, within the context of that behavior.  CoreAudio is designed to use a separate callback procedure for each of its audio devices.  A single RtAudio duplex stream using two different devices is supported, though it cannot be guaranteed to always behave correctly because we cannot synchronize these two callbacks.  This same functionality can be achieved with better synchrony by opening two separate streams for the devices and using RtAudio blocking calls (i.e. RtAudio::tickStream()).  The <I>numberOfBuffers</I> parameter to the RtAudio::openStream() function has no affect in this implementation.  It is not currently possible to have multiple simultaneous RtAudio streams accessing the same device.
+The Apple CoreAudio API is based on a callback scheme.  RtAudio provides blocking functionality, in addition to callback functionality, within the context of that behavior.  CoreAudio is designed to use a separate callback procedure for each of its audio devices.  A single RtAudio duplex stream using two different devices is supported, though it cannot be guaranteed to always behave correctly because we cannot synchronize these two callbacks.  This same functionality might be achieved with better synchrony by creating separate instances of RtAudio for each device and making use of RtAudio blocking calls (i.e. RtAudio::tickStream()).  The <I>numberOfBuffers</I> parameter to the RtAudio::openStream() function has no affect in this implementation.
+
+It is not possible to have multiple instances of RtAudio accessing the same CoreAudio device.
 
 \subsection irix Irix (SGI):
 
@@ -656,25 +675,25 @@ The Irix version of RtAudio was written and tested on an SGI Indy running Irix v
 
 \subsection windowsds Windows (DirectSound):
 
-In order to compile RtAudio under Windows for the DirectSound API, you must have the header and source files for DirectSound version 5.0 or higher.  As far as I know, there is no DirectSoundCapture support for Windows NT.  Audio output latency with DirectSound can be reasonably good (on the order of 20 milliseconds).  On the other hand, input audio latency tends to be terrible (100 milliseconds or more).  Further, DirectSound drivers tend to crash easily when experimenting with buffer parameters.  On my system, I found it necessary to use values around nBuffers = 8 and bufferSize = 512 to avoid crashes.  RtAudio was developed with Visual C++ version 6.0.  I was forced in several instances to modify code in order to get it to compile under the non-standard version of C++ that Microsoft so unprofessionally implemented.  Unfortunately, it appears they are continuing to undermine the C++ standard with more recent compiler releases.
+In order to compile RtAudio under Windows for the DirectSound API, you must have the header and source files for DirectSound version 5.0 or higher.  As far as I know, there is no DirectSoundCapture support for Windows NT.  Audio output latency with DirectSound can be reasonably good (on the order of 20 milliseconds).  On the other hand, input audio latency tends to be terrible (100 milliseconds or more).  Further, DirectSound drivers tend to crash easily when experimenting with buffer parameters.  On my system, I found it necessary to use values around nBuffers = 8 and bufferSize = 512 to avoid crashes.  RtAudio was originally developed with Visual C++ version 6.0.
 
 \subsection windowsasio Windows (ASIO):
 
-The Steinberg ASIO audio API is based on a callback scheme.  In addition, the API allows only a single device driver to be loaded and accessed at a time.  Therefore, it is not possible to have multiple simultaneous RtAudio streams running concurrently with this API.  ASIO device drivers must be supplied by audio hardware manufacturers, though ASIO emulation is possible on top of systems with DirectSound drivers.  The <I>numberOfBuffers</I> parameter to the RtAudio::openStream() function has no affect in this implementation.
+The Steinberg ASIO audio API is based on a callback scheme.  In addition, the API allows only a single device driver to be loaded and accessed at a time.  ASIO device drivers must be supplied by audio hardware manufacturers, though ASIO emulation is possible on top of systems with DirectSound drivers.  The <I>numberOfBuffers</I> parameter to the RtAudio::openStream() function has no affect in this implementation.
 
-A number of ASIO source and header files are required for use with RtAudio.  Specifically, an RtAudio project must include the following files: <TT>asio.h,cpp; asiodrivers.h,cpp; asiolist.h,cpp; asiodrvr.h; asiosys.h; ginclude.h; iasiodrv.h</TT>.  See the <TT>/tests/asio/</TT> directory for example Visual C++ 6.0 projects.
+A number of ASIO source and header files are required for use with RtAudio.  Specifically, an RtAudio project must include the following files: <TT>asio.h,cpp; asiodrivers.h,cpp; asiolist.h,cpp; asiodrvr.h; asiosys.h; ginclude.h; iasiodrv.h</TT>.  The Visual C++ projects found in <TT>/tests/Windows/</TT> compile both ASIO and DirectSound support.
 
 
 \section acknowledge Acknowledgements
 
 The RtAudio API incorporates many of the concepts developed in the <A href="http://www.portaudio.com/">PortAudio</A> project by Phil Burk and Ross Bencina.  Early development also incorporated ideas from Bill Schottstaedt's <A href="http://www-ccrma.stanford.edu/software/snd/sndlib/">sndlib</A>.  The CCRMA <A href="http://www-ccrma.stanford.edu/groups/soundwire/">SoundWire group</A> provided valuable feedback during the API proposal stages.
 
-RtAudio, version 2.0, was slowly developed over the course of many months while in residence at the <A href="http://www.iua.upf.es/">Institut Universitari de L'Audiovisual (IUA)</A> in Barcelona, Spain, the <A href="http://www.acoustics.hut.fi/">Laboratory of Acoustics and Audio Signal Processing</A> at the Helsinki University of Technology, Finland, and the <A href="http://www-ccrma.stanford.edu/">Center for Computer Research in Music and Acoustics (CCRMA)</A> at <A href="http://www.stanford.edu/">Stanford University</A>.  This work was supported in part by the United States Air Force Office of Scientific Research (grant \#F49620-99-1-0293).
+The early 2.0 version of RtAudio was slowly developed over the course of many months while in residence at the <A href="http://www.iua.upf.es/">Institut Universitari de L'Audiovisual (IUA)</A> in Barcelona, Spain and the <A href="http://www.acoustics.hut.fi/">Laboratory of Acoustics and Audio Signal Processing</A> at the Helsinki University of Technology, Finland.  Much subsequent development happened while working at the <A href="http://www-ccrma.stanford.edu/">Center for Computer Research in Music and Acoustics (CCRMA)</A> at <A href="http://www.stanford.edu/">Stanford University</A>.  The most recent version of RtAudio was finished while working as an assistant professor of <a href="http://www.music.mcgill.ca/musictech/">Music Technology</a> at <a href="http://www.mcgill.ca/">McGill University</a>.  This work was supported in part by the United States Air Force Office of Scientific Research (grant \#F49620-99-1-0293).
 
 \section license License
 
-    RtAudio: a realtime audio i/o C++ class<BR>
-    Copyright (c) 2001-2002 Gary P. Scavone
+    RtAudio: a realtime audio i/o C++ classes<BR>
+    Copyright (c) 2001-2004 Gary P. Scavone
 
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation files
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/doc/images/mcgill.gif b/doc/images/mcgill.gif
new file mode 100644 (file)
index 0000000..c571e37
Binary files /dev/null and b/doc/images/mcgill.gif differ
index bcd38671967e7ac097141f58c50511dcba5d4f07..b1719161577c6085d3cbc34960efce73fc2bf2d2 100644 (file)
@@ -1,6 +1,14 @@
-RtAudio - a C++ class which provides a common API for realtime audio input/output across Linux (native ALSA and OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound and ASIO) operating systems.
+RtAudio - a set of C++ classes which provide a common API for realtime audio input/output across Linux (native ALSA, JACK, and OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound and ASIO) operating systems.
 
-By Gary P. Scavone, 2002.
+By Gary P. Scavone, 2001-2004.
+
+v3.0: (11 March 2004)
+- added Linux Jack audio server support
+- new multi-api support by subclassing all apis and making rtaudio a controller class
+- added over/underload check to Mac OS X support
+- new scheme for blocking functionality in callback-based apis (CoreAudio, ASIO, and JACK)
+- removed multiple stream support (all stream indentifier arguments removed)
+- various style and name changes to conform with standard C++ practice
 
 v2.1.1: (24 October 2002)
 - bug fix in duplex for Mac OS X and Windows ASIO code
diff --git a/install b/install
new file mode 100644 (file)
index 0000000..7aab632
--- /dev/null
+++ b/install
@@ -0,0 +1,30 @@
+RtAudio - a set of C++ classes which provide a common API for realtime audio input/output across Linux (native ALSA, JACK, and OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound and ASIO) operating systems.
+
+By Gary P. Scavone, 2001-2004.
+
+To configure and compile (on Unix systems):
+
+1. Unpack the RtAudio distribution (tar -xzf rtaudio-x.x.tar.gz).
+2. From within the directory containing this file, run configure:
+
+   ./configure
+
+3. From within the "tests" directory, type "make".
+
+A few options can be passed to configure, including:
+
+  --enable-debug = enable various debug output
+  --with-alsa = choose native ALSA API support (linux only)
+  --with-jack = choose JACK server support (linux only)
+  --with-oss = choose OSS API support (linux only)
+
+Typing "./configure --help" will display all the available options.
+
+If you wish to use a different compiler than that selected by configure, specify that compiler in the command line (ex. to use CC):
+
+  ./configure CXX=CC
+
+
+For Windows Users:
+
+Visual C++ 6.0 project files are included for the test programs in the /tests/Windows/ directory.  These projects compile API support for both ASIO and DirectSound.
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/readme b/readme
new file mode 100644 (file)
index 0000000..ae40510
--- /dev/null
+++ b/readme
@@ -0,0 +1,64 @@
+RtAudio - a set of C++ classes which provide a common API for realtime audio input/output across Linux (native ALSA, JACK, and OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound and ASIO) operating systems.
+
+By Gary P. Scavone, 2001-2004.
+
+This distribution of RtAudio contains the following:
+
+doc:      RtAudio documentation (see doc/html/index.html)
+tests:    example RtAudio programs
+asio:     header files necessary for ASIO compilation
+tests/Windows: Visual C++ 6.0 test program workspace and projects
+
+OVERVIEW:
+
+RtAudio is a set of C++ classes which provide a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, JACK, and OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound and ASIO) operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following goals:
+
+  - object oriented C++ design
+  - simple, common API across all supported platforms
+  - only two header files and one source file for easy inclusion in programming projects
+  - allow simultaneous multi-api support
+  - blocking functionality
+  - callback functionality
+  - extensive audio device parameter control
+  - audio device capability probing
+  - automatic internal conversion for data format, channel number compensation, de-interleaving, and byte-swapping
+
+RtAudio incorporates the concept of audio streams, which represent audio output (playback) and/or input (recording). Available audio devices and their capabilities can be enumerated and then specified when opening a stream.  Where applicable, multiple API support can be compiled and a particular API specified when creating an RtAudio instance.
+
+The RtAudio API provides both blocking (synchronous) and callback (asyncronous) functionality. Callbacks are typically used in conjunction with graphical user interfaces (GUI). Blocking functionality is often necessary for explicit control of multiple input/output stream synchronization or when audio must be synchronized with other system events. 
+
+
+FURTHER READING:
+
+For complete documentation on RtAudio, see the doc directory of the distribution or surf to http://music.mcgill.ca/~gary/rtaudio/.
+
+
+LEGAL AND ETHICAL:
+
+The RtAudio license is similar to the the MIT License, with the added "feature" that modifications be sent to the developer.
+
+    RtAudio: a set of realtime audio i/o C++ classes
+    Copyright (c) 2001-2004 Gary P. Scavone
+
+    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/tests/DirectSound/Debug/.placeholder b/tests/DirectSound/Debug/.placeholder
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tests/DirectSound/Release/.placeholder b/tests/DirectSound/Release/.placeholder
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tests/DirectSound/call_inout.dsp b/tests/DirectSound/call_inout.dsp
deleted file mode 100755 (executable)
index fdebf94..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="call_inout" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=call_inout - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_inout.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_inout.mak" CFG="call_inout - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "call_inout - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "call_inout - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "call_inout - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "call_inout - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "call_inout - Win32 Release"\r
-# Name "call_inout - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\call_inout.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/call_playtwo.dsp b/tests/DirectSound/call_playtwo.dsp
deleted file mode 100755 (executable)
index 1c9966b..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="call_playtwo" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=call_playtwo - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_playtwo.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_playtwo.mak" CFG="call_playtwo - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "call_playtwo - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "call_playtwo - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "call_playtwo - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "call_playtwo - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "call_playtwo - Win32 Release"\r
-# Name "call_playtwo - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\call_playtwo.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/call_saw.dsp b/tests/DirectSound/call_saw.dsp
deleted file mode 100755 (executable)
index 1e3b866..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="call_saw" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=call_saw - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_saw.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_saw.mak" CFG="call_saw - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "call_saw - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "call_saw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "call_saw - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "call_saw - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "call_saw - Win32 Release"\r
-# Name "call_saw - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\call_saw.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/call_twostreams.dsp b/tests/DirectSound/call_twostreams.dsp
deleted file mode 100755 (executable)
index 16da2e5..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="call_twostreams" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=call_twostreams - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_twostreams.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_twostreams.mak" CFG="call_twostreams - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "call_twostreams - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "call_twostreams - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "call_twostreams - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "call_twostreams - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "call_twostreams - Win32 Release"\r
-# Name "call_twostreams - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\call_twostreams.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/in_out.dsp b/tests/DirectSound/in_out.dsp
deleted file mode 100755 (executable)
index f8585e6..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="in_out" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=in_out - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "in_out.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "in_out.mak" CFG="in_out - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "in_out - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "in_out - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "in_out - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "in_out - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "in_out - Win32 Release"\r
-# Name "in_out - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\in_out.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/info.dsp b/tests/DirectSound/info.dsp
deleted file mode 100755 (executable)
index 3bf97c6..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="info" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=info - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "info.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "info.mak" CFG="info - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "info - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "info - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "info - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "info - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "info - Win32 Release"\r
-# Name "info - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\info.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/play_raw.dsp b/tests/DirectSound/play_raw.dsp
deleted file mode 100755 (executable)
index 7915897..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="play_raw" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=play_raw - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "play_raw.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "play_raw.mak" CFG="play_raw - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "play_raw - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "play_raw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "play_raw - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "play_raw - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "play_raw - Win32 Release"\r
-# Name "play_raw - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\play_raw.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/play_saw.dsp b/tests/DirectSound/play_saw.dsp
deleted file mode 100755 (executable)
index bbe59b4..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="play_saw" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=play_saw - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "play_saw.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "play_saw.mak" CFG="play_saw - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "play_saw - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "play_saw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "play_saw - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "play_saw - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "play_saw - Win32 Release"\r
-# Name "play_saw - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\play_saw.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/record_raw.dsp b/tests/DirectSound/record_raw.dsp
deleted file mode 100755 (executable)
index 18e66bc..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="record_raw" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=record_raw - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "record_raw.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "record_raw.mak" CFG="record_raw - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "record_raw - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "record_raw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "record_raw - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "record_raw - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "record_raw - Win32 Release"\r
-# Name "record_raw - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\record_raw.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/DirectSound/rtaudio.dsw b/tests/DirectSound/rtaudio.dsw
deleted file mode 100755 (executable)
index f276a43..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00\r
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
-\r
-###############################################################################\r
-\r
-Project: "call_inout"=.\call_inout.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "call_playtwo"=.\call_playtwo.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "call_saw"=.\call_saw.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "call_twostreams"=.\call_twostreams.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "in_out"=.\in_out.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "info"=.\info.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "play_raw"=.\play_raw.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "play_saw"=.\play_saw.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "record_raw"=.\record_raw.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "twostreams"=.\twostreams.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Global:\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<3>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
diff --git a/tests/DirectSound/twostreams.dsp b/tests/DirectSound/twostreams.dsp
deleted file mode 100755 (executable)
index 54c9bc6..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# Microsoft Developer Studio Project File - Name="twostreams" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=twostreams - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "twostreams.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "twostreams.mak" CFG="twostreams - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "twostreams - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "twostreams - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "twostreams - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "twostreams - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Ignore_Export_Lib 0\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "twostreams - Win32 Release"\r
-# Name "twostreams - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=..\twostreams.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
index 3bacb8c837c8a0495beb9d83e02c24410a696d1c..54f4d4a0304b87754beab5b4d59264cc918fc33c 100644 (file)
@@ -1,6 +1,6 @@
 ### RtAudio tests Makefile - for various flavors of unix
 
-PROGRAMS = info play_saw record_raw in_out play_raw twostreams call_saw call_inout call_twostreams call_playtwo
+PROGRAMS = info play_saw record_raw in_out play_raw twostreams call_saw call_inout
 RM = /bin/rm
 SRC_PATH = ../
 INCLUDE = ../
@@ -11,7 +11,7 @@ OBJECTS       =       RtAudio.o
 
 CC       = @CXX@
 DEFS     = @debug@
-DEFS    += @sound_api@
+DEFS    += @audio_apis@
 CFLAGS   = @cflags@
 CFLAGS  += @warn@ -I$(INCLUDE)
 LIBRARY  = @LIBS@
@@ -46,12 +46,6 @@ call_saw : call_saw.cpp $(OBJECTS)
 call_inout : call_inout.cpp $(OBJECTS)
        $(CC) $(CFLAGS) $(DEFS) -o call_inout call_inout.cpp $(OBJECT_PATH)/RtAudio.o $(LIBRARY)
 
-call_twostreams : call_twostreams.cpp $(OBJECTS)
-       $(CC) $(CFLAGS) $(DEFS) -o call_twostreams call_twostreams.cpp $(OBJECT_PATH)/RtAudio.o $(LIBRARY)
-
-call_playtwo : call_playtwo.cpp $(OBJECTS)
-       $(CC) $(CFLAGS) $(DEFS) -o call_playtwo call_playtwo.cpp $(OBJECT_PATH)/RtAudio.o $(LIBRARY)
-
 clean : 
        -rm $(OBJECT_PATH)/*.o
        -rm $(PROGRAMS)
diff --git a/tests/Windows/Debug/.placeholder b/tests/Windows/Debug/.placeholder
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/Windows/Release/.placeholder b/tests/Windows/Release/.placeholder
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/Windows/asio.cpp b/tests/Windows/asio.cpp
new file mode 100644 (file)
index 0000000..b241663
--- /dev/null
@@ -0,0 +1,257 @@
+/*\r
+       Steinberg Audio Stream I/O API\r
+       (c) 1996, Steinberg Soft- und Hardware GmbH\r
+\r
+       asio.cpp\r
+       \r
+       asio functions entries which translate the\r
+       asio interface to the asiodrvr class methods\r
+*/ \r
+       \r
+#include <string.h>\r
+#include "asiosys.h"           // platform definition\r
+#include "asio.h"\r
+\r
+#if MAC\r
+#include "asiodrvr.h"\r
+\r
+#pragma export on\r
+\r
+AsioDriver *theAsioDriver = 0;\r
+\r
+extern "C"\r
+{\r
+\r
+long main()\r
+{\r
+       return 'ASIO';\r
+}\r
+\r
+#elif WINDOWS\r
+\r
+#include "windows.h"\r
+#include "iasiodrv.h"\r
+#include "asiodrivers.h"\r
+\r
+IASIO *theAsioDriver = 0;\r
+extern AsioDrivers *asioDrivers;\r
+\r
+#elif SGI || SUN || BEOS || LINUX\r
+#include "asiodrvr.h"\r
+static AsioDriver *theAsioDriver = 0;\r
+#endif\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+ASIOError ASIOInit(ASIODriverInfo *info)\r
+{\r
+#if MAC || SGI || SUN || BEOS || LINUX\r
+       if(theAsioDriver)\r
+       {\r
+               delete theAsioDriver;\r
+               theAsioDriver = 0;\r
+       }               \r
+       info->driverVersion = 0;\r
+       strcpy(info->name, "No ASIO Driver");\r
+       theAsioDriver = getDriver();\r
+       if(!theAsioDriver)\r
+       {\r
+               strcpy(info->errorMessage, "Not enough memory for the ASIO driver!"); \r
+               return ASE_NotPresent;\r
+       }\r
+       if(!theAsioDriver->init(info->sysRef))\r
+       {\r
+               theAsioDriver->getErrorMessage(info->errorMessage);\r
+               delete theAsioDriver;\r
+               theAsioDriver = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       strcpy(info->errorMessage, "No ASIO Driver Error");\r
+       theAsioDriver->getDriverName(info->name);\r
+       info->driverVersion = theAsioDriver->getDriverVersion();\r
+       return ASE_OK;\r
+\r
+#else\r
+\r
+       info->driverVersion = 0;\r
+       strcpy(info->name, "No ASIO Driver");\r
+       if(theAsioDriver)       // must be loaded!\r
+       {\r
+               if(!theAsioDriver->init(info->sysRef))\r
+               {\r
+                       theAsioDriver->getErrorMessage(info->errorMessage);\r
+                       theAsioDriver = 0;\r
+                       return ASE_NotPresent;\r
+               }               \r
+\r
+               strcpy(info->errorMessage, "No ASIO Driver Error");\r
+               theAsioDriver->getDriverName(info->name);\r
+               info->driverVersion = theAsioDriver->getDriverVersion();\r
+               return ASE_OK;\r
+       }\r
+       return ASE_NotPresent;\r
+\r
+#endif // !MAC\r
+}\r
+\r
+ASIOError ASIOExit(void)\r
+{\r
+       if(theAsioDriver)\r
+       {\r
+#if WINDOWS\r
+               asioDrivers->removeCurrentDriver();\r
+#else\r
+               delete theAsioDriver;\r
+#endif\r
+       }               \r
+       theAsioDriver = 0;\r
+       return ASE_OK;\r
+}\r
+\r
+ASIOError ASIOStart(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->start();\r
+}\r
+\r
+ASIOError ASIOStop(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->stop();\r
+}\r
+\r
+ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               *numInputChannels = *numOutputChannels = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getChannels(numInputChannels, numOutputChannels);\r
+}\r
+\r
+ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               *inputLatency = *outputLatency = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getLatencies(inputLatency, outputLatency);\r
+}\r
+\r
+ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               *minSize = *maxSize = *preferredSize = *granularity = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity);\r
+}\r
+\r
+ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->canSampleRate(sampleRate);\r
+}\r
+\r
+ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->getSampleRate(currentRate);\r
+}\r
+\r
+ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->setSampleRate(sampleRate);\r
+}\r
+\r
+ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               *numSources = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getClockSources(clocks, numSources);\r
+}\r
+\r
+ASIOError ASIOSetClockSource(long reference)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->setClockSource(reference);\r
+}\r
+\r
+ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->getSamplePosition(sPos, tStamp);\r
+}\r
+\r
+ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               info->channelGroup = -1;\r
+               info->type = ASIOSTInt16MSB;\r
+               strcpy(info->name, "None");\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->getChannelInfo(info);\r
+}\r
+\r
+ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+       long bufferSize, ASIOCallbacks *callbacks)\r
+{\r
+       if(!theAsioDriver)\r
+       {\r
+               ASIOBufferInfo *info = bufferInfos;\r
+               for(long i = 0; i < numChannels; i++, info++)\r
+                       info->buffers[0] = info->buffers[1] = 0;\r
+               return ASE_NotPresent;\r
+       }\r
+       return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks);\r
+}\r
+\r
+ASIOError ASIODisposeBuffers(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->disposeBuffers();\r
+}\r
+\r
+ASIOError ASIOControlPanel(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->controlPanel();\r
+}\r
+\r
+ASIOError ASIOFuture(long selector, void *opt)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->future(selector, opt);\r
+}\r
+\r
+ASIOError ASIOOutputReady(void)\r
+{\r
+       if(!theAsioDriver)\r
+               return ASE_NotPresent;\r
+       return theAsioDriver->outputReady();\r
+}\r
+\r
+#if MAC\r
+}      // extern "C"\r
+#pragma export off\r
+#endif\r
+\r
+\r
diff --git a/tests/Windows/asio.h b/tests/Windows/asio.h
new file mode 100644 (file)
index 0000000..3003130
--- /dev/null
@@ -0,0 +1,955 @@
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+/*\r
+       Steinberg Audio Stream I/O API\r
+       (c) 1997 - 1999, Steinberg Soft- und Hardware GmbH\r
+\r
+       ASIO Interface Specification v 2.0\r
+\r
+       basic concept is an i/o synchronous double-buffer scheme:\r
+       \r
+       on bufferSwitch(index == 0), host will read/write:\r
+\r
+               after ASIOStart(), the\r
+  read  first input buffer A (index 0)\r
+       |   will be invalid (empty)\r
+       *   ------------------------\r
+       |------------------------|-----------------------|\r
+       |                        |                       |\r
+       |  Input Buffer A (0)    |   Input Buffer B (1)  |\r
+       |                        |                       |\r
+       |------------------------|-----------------------|\r
+       |                        |                       |\r
+       |  Output Buffer A (0)   |   Output Buffer B (1) |\r
+       |                        |                       |\r
+       |------------------------|-----------------------|\r
+       *                        -------------------------\r
+       |                        before calling ASIOStart(),\r
+  write                      host will have filled output\r
+                             buffer B (index 1) already\r
+\r
+  *please* take special care of proper statement of input\r
+  and output latencies (see ASIOGetLatencies()), these\r
+  control sequencer sync accuracy\r
+\r
+*/\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+/*\r
+\r
+prototypes summary:\r
+\r
+ASIOError ASIOInit(ASIODriverInfo *info);\r
+ASIOError ASIOExit(void);\r
+ASIOError ASIOStart(void);\r
+ASIOError ASIOStop(void);\r
+ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);\r
+ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);\r
+ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
+ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);\r
+ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);\r
+ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);\r
+ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);\r
+ASIOError ASIOSetClockSource(long reference);\r
+ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);\r
+ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+       long bufferSize, ASIOCallbacks *callbacks);\r
+ASIOError ASIODisposeBuffers(void);\r
+ASIOError ASIOControlPanel(void);\r
+void *ASIOFuture(long selector, void *params);\r
+ASIOError ASIOOutputReady(void);\r
+\r
+*/\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+#ifndef __ASIO_H\r
+#define __ASIO_H\r
+\r
+// force 4 byte alignment\r
+#if defined(_MSC_VER) && !defined(__MWERKS__) \r
+#pragma pack(push,4)\r
+#elif PRAGMA_ALIGN_SUPPORTED\r
+#pragma options align = native\r
+#endif\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Type definitions\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+// number of samples data type is 64 bit integer\r
+#if NATIVE_INT64\r
+       typedef long long int ASIOSamples;\r
+#else\r
+       typedef struct ASIOSamples {\r
+               unsigned long hi;\r
+               unsigned long lo;\r
+       } ASIOSamples;\r
+#endif\r
+\r
+// Timestamp data type is 64 bit integer,\r
+// Time format is Nanoseconds.\r
+#if NATIVE_INT64\r
+       typedef long long int ASIOTimeStamp ;\r
+#else\r
+       typedef struct ASIOTimeStamp {\r
+               unsigned long hi;\r
+               unsigned long lo;\r
+       } ASIOTimeStamp;\r
+#endif\r
+\r
+// Samplerates are expressed in IEEE 754 64 bit double float,\r
+// native format as host computer\r
+#if IEEE754_64FLOAT\r
+       typedef double ASIOSampleRate;\r
+#else\r
+       typedef struct ASIOSampleRate {\r
+               char ieee[8];\r
+       } ASIOSampleRate;\r
+#endif\r
+\r
+// Boolean values are expressed as long\r
+typedef long ASIOBool;\r
+enum {\r
+       ASIOFalse = 0,\r
+       ASIOTrue = 1\r
+};\r
+\r
+// Sample Types are expressed as long\r
+typedef long ASIOSampleType;\r
+enum {\r
+       ASIOSTInt16MSB   = 0,\r
+       ASIOSTInt24MSB   = 1,           // used for 20 bits as well\r
+       ASIOSTInt32MSB   = 2,\r
+       ASIOSTFloat32MSB = 3,           // IEEE 754 32 bit float\r
+       ASIOSTFloat64MSB = 4,           // IEEE 754 64 bit double float\r
+\r
+       // these are used for 32 bit data buffer, with different alignment of the data inside\r
+       // 32 bit PCI bus systems can be more easily used with these\r
+       ASIOSTInt32MSB16 = 8,           // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32MSB18 = 9,           // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32MSB20 = 10,          // 32 bit data with 20 bit alignment\r
+       ASIOSTInt32MSB24 = 11,          // 32 bit data with 24 bit alignment\r
+       \r
+       ASIOSTInt16LSB   = 16,\r
+       ASIOSTInt24LSB   = 17,          // used for 20 bits as well\r
+       ASIOSTInt32LSB   = 18,\r
+       ASIOSTFloat32LSB = 19,          // IEEE 754 32 bit float, as found on Intel x86 architecture\r
+       ASIOSTFloat64LSB = 20,          // IEEE 754 64 bit double float, as found on Intel x86 architecture\r
+\r
+       // these are used for 32 bit data buffer, with different alignment of the data inside\r
+       // 32 bit PCI bus systems can more easily used with these\r
+       ASIOSTInt32LSB16 = 24,          // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32LSB18 = 25,          // 32 bit data with 18 bit alignment\r
+       ASIOSTInt32LSB20 = 26,          // 32 bit data with 20 bit alignment\r
+       ASIOSTInt32LSB24 = 27           // 32 bit data with 24 bit alignment\r
+};\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Error codes\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef long ASIOError;\r
+enum {\r
+       ASE_OK = 0,             // This value will be returned whenever the call succeeded\r
+       ASE_SUCCESS = 0x3f4847a0,       // unique success return value for ASIOFuture calls\r
+       ASE_NotPresent = -1000, // hardware input or output is not present or available\r
+       ASE_HWMalfunction,      // hardware is malfunctioning (can be returned by any ASIO function)\r
+       ASE_InvalidParameter,   // input parameter invalid\r
+       ASE_InvalidMode,        // hardware is in a bad mode or used in a bad mode\r
+       ASE_SPNotAdvancing,     // hardware is not running when sample position is inquired\r
+       ASE_NoClock,            // sample clock or rate cannot be determined or is not present\r
+       ASE_NoMemory            // not enough memory for completing the request\r
+};\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Time Info support\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOTimeCode\r
+{       \r
+       double          speed;                  // speed relation (fraction of nominal speed)\r
+                                               // optional; set to 0. or 1. if not supported\r
+       ASIOSamples     timeCodeSamples;        // time in samples\r
+       unsigned long   flags;                  // some information flags (see below)\r
+       char future[64];\r
+} ASIOTimeCode;\r
+\r
+typedef enum ASIOTimeCodeFlags\r
+{\r
+       kTcValid                = 1,\r
+       kTcRunning              = 1 << 1,\r
+       kTcReverse              = 1 << 2,\r
+       kTcOnspeed              = 1 << 3,\r
+       kTcStill                = 1 << 4,\r
+       \r
+       kTcSpeedValid           = 1 << 8\r
+}  ASIOTimeCodeFlags;\r
+\r
+typedef struct AsioTimeInfo\r
+{\r
+       double          speed;                  // absolute speed (1. = nominal)\r
+       ASIOTimeStamp   systemTime;             // system time related to samplePosition, in nanoseconds\r
+                                               // on mac, must be derived from Microseconds() (not UpTime()!)\r
+                                               // on windows, must be derived from timeGetTime()\r
+       ASIOSamples     samplePosition;\r
+       ASIOSampleRate  sampleRate;             // current rate\r
+       unsigned long flags;                    // (see below)\r
+       char reserved[12];\r
+} AsioTimeInfo;\r
+\r
+typedef enum AsioTimeInfoFlags\r
+{\r
+       kSystemTimeValid        = 1,            // must always be valid\r
+       kSamplePositionValid    = 1 << 1,       // must always be valid\r
+       kSampleRateValid        = 1 << 2,\r
+       kSpeedValid             = 1 << 3,\r
+       \r
+       kSampleRateChanged      = 1 << 4,\r
+       kClockSourceChanged     = 1 << 5\r
+} AsioTimeInfoFlags;\r
+\r
+typedef struct ASIOTime                          // both input/output\r
+{\r
+       long reserved[4];                       // must be 0\r
+       struct AsioTimeInfo     timeInfo;       // required\r
+       struct ASIOTimeCode     timeCode;       // optional, evaluated if (timeCode.flags & kTcValid)\r
+} ASIOTime;\r
+\r
+/*\r
+\r
+using time info:\r
+it is recommended to use the new method with time info even if the asio\r
+device does not support timecode; continuous calls to ASIOGetSamplePosition\r
+and ASIOGetSampleRate are avoided, and there is a more defined relationship\r
+between callback time and the time info.\r
+\r
+see the example below.\r
+to initiate time info mode, after you have received the callbacks pointer in\r
+ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo\r
+as the argument. if this returns 1, host has accepted time info mode.\r
+now host expects the new callback bufferSwitchTimeInfo to be used instead\r
+of the old bufferSwitch method. the ASIOTime structure is assumed to be valid\r
+and accessible until the callback returns.\r
+\r
+using time code:\r
+if the device supports reading time code, it will call host's asioMessage callback\r
+with kAsioSupportsTimeCode as the selector. it may then fill the according\r
+fields and set the kTcValid flag.\r
+host will call the future method with the kAsioEnableTimeCodeRead selector when\r
+it wants to enable or disable tc reading by the device. you should also support\r
+the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example).\r
+\r
+note:\r
+the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions.\r
+as a matter of convention, the relationship between the sample\r
+position counter and the time code at buffer switch time is\r
+(ignoring offset between tc and sample pos when tc is running):\r
+\r
+on input:      sample 0 -> input  buffer sample 0 -> time code 0\r
+on output:     sample 0 -> output buffer sample 0 -> time code 0\r
+\r
+this means that for 'real' calculations, one has to take into account\r
+the according latencies.\r
+\r
+example:\r
+\r
+ASIOTime asioTime;\r
+\r
+in createBuffers()\r
+{\r
+       memset(&asioTime, 0, sizeof(ASIOTime));\r
+       AsioTimeInfo* ti = &asioTime.timeInfo;\r
+       ti->sampleRate = theSampleRate;\r
+       ASIOTimeCode* tc = &asioTime.timeCode;\r
+       tc->speed = 1.;\r
+       timeInfoMode = false;\r
+       canTimeCode = false;\r
+       if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1)\r
+       {\r
+               timeInfoMode = true;\r
+#if kCanTimeCode\r
+               if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1)\r
+                       canTimeCode = true;\r
+#endif\r
+       }\r
+}\r
+\r
+void switchBuffers(long doubleBufferIndex, bool processNow)\r
+{\r
+       if(timeInfoMode)\r
+       {\r
+               AsioTimeInfo* ti = &asioTime.timeInfo;\r
+               ti->flags =     kSystemTimeValid | kSamplePositionValid | kSampleRateValid;\r
+               ti->systemTime = theNanoSeconds;\r
+               ti->samplePosition = theSamplePosition;\r
+               if(ti->sampleRate != theSampleRate)\r
+                       ti->flags |= kSampleRateChanged;\r
+               ti->sampleRate = theSampleRate;\r
+\r
+#if kCanTimeCode\r
+               if(canTimeCode && timeCodeEnabled)\r
+               {\r
+                       ASIOTimeCode* tc = &asioTime.timeCode;\r
+                       tc->timeCodeSamples = tcSamples;                                                // tc in samples\r
+                       tc->flags = kTcValid | kTcRunning | kTcOnspeed;                 // if so...\r
+               }\r
+               ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);\r
+#else\r
+               callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);\r
+#endif\r
+       }\r
+       else\r
+               callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse);\r
+}\r
+\r
+ASIOError ASIOFuture(long selector, void *params)\r
+{\r
+       switch(selector)\r
+       {\r
+               case kAsioEnableTimeCodeRead:\r
+                       timeCodeEnabled = true;\r
+                       return ASE_SUCCESS;\r
+               case kAsioDisableTimeCodeRead:\r
+                       timeCodeEnabled = false;\r
+                       return ASE_SUCCESS;\r
+               case kAsioCanTimeInfo:\r
+                       return ASE_SUCCESS;\r
+               #if kCanTimeCode\r
+               case kAsioCanTimeCode:\r
+                       return ASE_SUCCESS;\r
+               #endif\r
+       }\r
+       return ASE_NotPresent;\r
+};\r
+\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// application's audio stream handler callbacks\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOCallbacks\r
+{\r
+       void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess);\r
+               // bufferSwitch indicates that both input and output are to be processed.\r
+               // the current buffer half index (0 for A, 1 for B) determines\r
+               // - the output buffer that the host should start to fill. the other buffer\r
+               //   will be passed to output hardware regardless of whether it got filled\r
+               //   in time or not.\r
+               // - the input buffer that is now filled with incoming data. Note that\r
+               //   because of the synchronicity of i/o, the input always has at\r
+               //   least one buffer latency in relation to the output.\r
+               // directProcess suggests to the host whether it should immedeately\r
+               // start processing (directProcess == ASIOTrue), or whether its process\r
+               // should be deferred because the call comes from a very low level\r
+               // (for instance, a high level priority interrupt), and direct processing\r
+               // would cause timing instabilities for the rest of the system. If in doubt,\r
+               // directProcess should be set to ASIOFalse.\r
+               // Note: bufferSwitch may be called at interrupt time for highest efficiency.\r
+\r
+       void (*sampleRateDidChange) (ASIOSampleRate sRate);\r
+               // gets called when the AudioStreamIO detects a sample rate change\r
+               // If sample rate is unknown, 0 is passed (for instance, clock loss\r
+               // when externally synchronized).\r
+\r
+       long (*asioMessage) (long selector, long value, void* message, double* opt);\r
+               // generic callback for various purposes, see selectors below.\r
+               // note this is only present if the asio version is 2 or higher\r
+\r
+       ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess);\r
+               // new callback with time info. makes ASIOGetSamplePosition() and various\r
+               // calls to ASIOGetSampleRate obsolete,\r
+               // and allows for timecode sync etc. to be preferred; will be used if\r
+               // the driver calls asioMessage with selector kAsioSupportsTimeInfo.\r
+} ASIOCallbacks;\r
+\r
+// asioMessage selectors\r
+enum\r
+{\r
+       kAsioSelectorSupported = 1,     // selector in <value>, returns 1L if supported,\r
+                                                               // 0 otherwise\r
+    kAsioEngineVersion,                        // returns engine (host) asio implementation version,\r
+                                                               // 2 or higher\r
+       kAsioResetRequest,                      // request driver reset. if accepted, this\r
+                                                               // will close the driver (ASIO_Exit() ) and\r
+                                                               // re-open it again (ASIO_Init() etc). some\r
+                                                               // drivers need to reconfigure for instance\r
+                                                               // when the sample rate changes, or some basic\r
+                                                               // changes have been made in ASIO_ControlPanel().\r
+                                                               // returns 1L; note the request is merely passed\r
+                                                               // to the application, there is no way to determine\r
+                                                               // if it gets accepted at this time (but it usually\r
+                                                               // will be).\r
+       kAsioBufferSizeChange,          // not yet supported, will currently always return 0L.\r
+                                                               // for now, use kAsioResetRequest instead.\r
+                                                               // once implemented, the new buffer size is expected\r
+                                                               // in <value>, and on success returns 1L\r
+       kAsioResyncRequest,                     // the driver went out of sync, such that\r
+                                                               // the timestamp is no longer valid. this\r
+                                                               // is a request to re-start the engine and\r
+                                                               // slave devices (sequencer). returns 1 for ok,\r
+                                                               // 0 if not supported.\r
+       kAsioLatenciesChanged,          // the drivers latencies have changed. The engine\r
+                                                               // will refetch the latencies.\r
+       kAsioSupportsTimeInfo,          // if host returns true here, it will expect the\r
+                                                               // callback bufferSwitchTimeInfo to be called instead\r
+                                                               // of bufferSwitch\r
+       kAsioSupportsTimeCode,          // supports time code reading/writing\r
+\r
+       kAsioSupportsInputMonitor,      // supports input monitoring\r
+\r
+       kAsioNumMessageSelectors\r
+};\r
+\r
+//---------------------------------------------------------------------------------------------------\r
+//---------------------------------------------------------------------------------------------------\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// (De-)Construction\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIODriverInfo\r
+{\r
+       long asioVersion;               // currently, 2\r
+       long driverVersion;             // driver specific\r
+       char name[32];\r
+       char errorMessage[124];\r
+       void *sysRef;                   // on input: system reference\r
+                                                       // (Windows: application main window handle, Mac & SGI: 0)\r
+} ASIODriverInfo;\r
+\r
+ASIOError ASIOInit(ASIODriverInfo *info);\r
+/* Purpose:\r
+         Initialize the AudioStreamIO.\r
+       Parameter:\r
+         info: pointer to an ASIODriver structure:\r
+           - asioVersion:\r
+                       - on input, the host version. *** Note *** this is 0 for earlier asio\r
+                       implementations, and the asioMessage callback is implemeted\r
+                       only if asioVersion is 2 or greater. sorry but due to a design fault\r
+                       the driver doesn't have access to the host version in ASIOInit :-(\r
+                       added selector for host (engine) version in the asioMessage callback\r
+                       so we're ok from now on.\r
+                       - on return, asio implementation version.\r
+                         older versions are 1\r
+                         if you support this version (namely, ASIO_outputReady() )\r
+                         this should be 2 or higher. also see the note in\r
+                         ASIO_getTimeStamp() !\r
+           - version: on return, the driver version (format is driver specific)\r
+           - name: on return, a null-terminated string containing the driver's name\r
+               - error message: on return, should contain a user message describing\r
+                 the type of error that occured during ASIOInit(), if any.\r
+               - sysRef: platform specific\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+         ASE_NoMemory, ASE_HWMalfunction are other possible error conditions\r
+*/\r
+\r
+ASIOError ASIOExit(void);\r
+/* Purpose:\r
+         Terminates the AudioStreamIO.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+       Notes: this implies ASIOStop() and ASIODisposeBuffers(),\r
+         meaning that no host callbacks must be accessed after ASIOExit().\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Start/Stop\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+ASIOError ASIOStart(void);\r
+/* Purpose:\r
+         Start input and output processing synchronously.\r
+         This will\r
+         - reset the sample counter to zero\r
+         - start the hardware (both input and output)\r
+           The first call to the hosts' bufferSwitch(index == 0) then tells\r
+           the host to read from input buffer A (index 0), and start\r
+           processing to output buffer A while output buffer B (which\r
+           has been filled by the host prior to calling ASIOStart())\r
+           is possibly sounding (see also ASIOGetLatencies()) \r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present, ASE_NotPresent\r
+         will be returned.\r
+         If the hardware fails to start, ASE_HWMalfunction will be returned.\r
+       Notes:\r
+         There is no restriction on the time that ASIOStart() takes\r
+         to perform (that is, it is not considered a realtime trigger).\r
+*/\r
+\r
+ASIOError ASIOStop(void);\r
+/* Purpose:\r
+         Stops input and output processing altogether.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If neither input nor output is present ASE_NotPresent\r
+         will be returned.\r
+       Notes:\r
+         On return from ASIOStop(), the driver must in no\r
+         case call the hosts' bufferSwitch() routine.\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Inquiry methods and sample rate\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);\r
+/* Purpose:\r
+         Returns number of individual input/output channels.\r
+       Parameter:\r
+         numInputChannels will hold the number of available input channels\r
+         numOutputChannels will hold the number of available output channels\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If only inputs, or only outputs are available, the according\r
+         other parameter will be zero, and ASE_OK is returned.\r
+*/\r
+\r
+ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);\r
+/* Purpose:\r
+         Returns the input and output latencies. This includes\r
+         device specific delays, like FIFOs etc.\r
+       Parameter:\r
+         inputLatency will hold the 'age' of the first sample frame\r
+         in the input buffer when the hosts reads it in bufferSwitch()\r
+         (this is theoretical, meaning it does not include the overhead\r
+         and delay between the actual physical switch, and the time\r
+         when bufferSitch() enters).\r
+         This will usually be the size of one block in sample frames, plus\r
+         device specific latencies.\r
+\r
+         outputLatency will specify the time between the buffer switch,\r
+         and the time when the next play buffer will start to sound.\r
+         The next play buffer is defined as the one the host starts\r
+         processing after (or at) bufferSwitch(), indicated by the\r
+         index parameter (0 for buffer A, 1 for buffer B).\r
+         It will usually be either one block, if the host writes directly\r
+         to a dma buffer, or two or more blocks if the buffer is 'latched' by\r
+         the driver. As an example, on ASIOStart(), the host will have filled\r
+         the play buffer at index 1 already; when it gets the callback (with\r
+         the parameter index == 0), this tells it to read from the input\r
+         buffer 0, and start to fill the play buffer 0 (assuming that now\r
+         play buffer 1 is already sounding). In this case, the output\r
+         latency is one block. If the driver decides to copy buffer 1\r
+         at that time, and pass it to the hardware at the next slot (which\r
+         is most commonly done, but should be avoided), the output latency\r
+         becomes two blocks instead, resulting in a total i/o latency of at least\r
+         3 blocks. As memory access is the main bottleneck in native dsp processing,\r
+         and to acheive less latency, it is highly recommended to try to avoid\r
+         copying (this is also why the driver is the owner of the buffers). To\r
+         summarize, the minimum i/o latency can be acheived if the input buffer\r
+         is processed by the host into the output buffer which will physically\r
+         start to sound on the next time slice. Also note that the host expects\r
+         the bufferSwitch() callback to be accessed for each time slice in order\r
+         to retain sync, possibly recursively; if it fails to process a block in\r
+         time, it will suspend its operation for some time in order to recover.\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+*/\r
+\r
+ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
+/* Purpose:\r
+         Returns min, max, and preferred buffer sizes for input/output\r
+       Parameter:\r
+         minSize will hold the minimum buffer size\r
+         maxSize will hold the maxium possible buffer size\r
+         preferredSize will hold the preferred buffer size (a size which\r
+         best fits performance and hardware requirements)\r
+         granularity will hold the granularity at which buffer sizes\r
+         may differ. Usually, the buffer size will be a power of 2;\r
+         in this case, granularity will hold -1 on return, signalling\r
+         possible buffer sizes starting from minSize, increased in\r
+         powers of 2 up to maxSize.\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         When minimum and maximum buffer size are equal,\r
+         the preferred buffer size has to be the same value as well; granularity\r
+         should be 0 in this case.\r
+*/\r
+\r
+ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);\r
+/* Purpose:\r
+         Inquires the hardware for the available sample rates.\r
+       Parameter:\r
+         sampleRate is the rate in question.\r
+       Returns:\r
+         If the inquired sample rate is not supported, ASE_NoClock will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+*/\r
+ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);\r
+/* Purpose:\r
+         Get the current sample Rate.\r
+       Parameter:\r
+         currentRate will hold the current sample rate on return.\r
+       Returns:\r
+         If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);\r
+/* Purpose:\r
+         Set the hardware to the requested sample Rate. If sampleRate == 0,\r
+         enable external sync.\r
+       Parameter:\r
+         sampleRate: on input, the requested rate\r
+       Returns:\r
+         If sampleRate is unknown ASE_NoClock will be returned.\r
+         If the current clock is external, and sampleRate is != 0,\r
+         ASE_InvalidMode will be returned\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+typedef struct ASIOClockSource\r
+{\r
+       long index;                                     // as used for ASIOSetClockSource()\r
+       long associatedChannel;         // for instance, S/PDIF or AES/EBU\r
+       long associatedGroup;           // see channel groups (ASIOGetChannelInfo())\r
+       ASIOBool isCurrentSource;       // ASIOTrue if this is the current clock source\r
+       char name[32];                          // for user selection\r
+} ASIOClockSource;\r
+\r
+ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);\r
+/* Purpose:\r
+         Get the available external audio clock sources\r
+       Parameter:\r
+         clocks points to an array of ASIOClockSource structures:\r
+               - index: this is used to identify the clock source\r
+                 when ASIOSetClockSource() is accessed, should be\r
+                 an index counting from zero\r
+               - associatedInputChannel: the first channel of an associated\r
+                 input group, if any.\r
+               - associatedGroup: the group index of that channel.\r
+                 groups of channels are defined to seperate for\r
+                 instance analog, S/PDIF, AES/EBU, ADAT connectors etc,\r
+                 when present simultaniously. Note that associated channel\r
+                 is enumerated according to numInputs/numOutputs, means it\r
+                 is independant from a group (see also ASIOGetChannelInfo())\r
+                 inputs are associated to a clock if the physical connection\r
+                 transfers both data and clock (like S/PDIF, AES/EBU, or\r
+                 ADAT inputs). if there is no input channel associated with\r
+                 the clock source (like Word Clock, or internal oscillator), both\r
+                 associatedChannel and associatedGroup should be set to -1.\r
+               - isCurrentSource: on exit, ASIOTrue if this is the current clock\r
+                 source, ASIOFalse else\r
+               - name: a null-terminated string for user selection of the available sources.\r
+         numSources:\r
+             on input: the number of allocated array members\r
+             on output: the number of available clock sources, at least\r
+             1 (internal clock generator).\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+*/\r
+\r
+ASIOError ASIOSetClockSource(long index);\r
+/* Purpose:\r
+         Set the audio clock source\r
+       Parameter:\r
+         index as obtained from an inquiry to ASIOGetClockSources()\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If the clock can not be selected because an input channel which\r
+         carries the current clock source is active, ASE_InvalidMode\r
+         *may* be returned (this depends on the properties of the driver\r
+         and/or hardware).\r
+       Notes:\r
+         Should *not* return ASE_NoClock if there is no clock signal present\r
+         at the selected source; this will be inquired via ASIOGetSampleRate().\r
+         It should call the host callback procedure sampleRateHasChanged(),\r
+         if the switch causes a sample rate change, or if no external clock\r
+         is present at the selected source.\r
+*/\r
+\r
+ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+/* Purpose:\r
+         Inquires the sample position/time stamp pair.\r
+       Parameter:\r
+         sPos will hold the sample position on return. The sample\r
+         position is reset to zero when ASIOStart() gets called.\r
+         tStamp will hold the system time when the sample position\r
+         was latched.\r
+       Returns:\r
+         If no input/output is present, ASE_NotPresent will be returned.\r
+         If there is no clock, ASE_SPNotAdvancing will be returned.\r
+       Notes:\r
+\r
+         in order to be able to synchronise properly,\r
+         the sample position / time stamp pair must refer to the current block,\r
+         that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch()\r
+         callback and expect the time for the current block. thus, when requested\r
+         in the very first bufferSwitch after ASIO_Start(), the sample position\r
+         should be zero, and the time stamp should refer to the very time where\r
+         the stream was started. it also means that the sample position must be\r
+         block aligned. the driver must ensure proper interpolation if the system\r
+         time can not be determined for the block position. the driver is responsible\r
+         for precise time stamps as it usually has most direct access to lower\r
+         level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies()\r
+         are essential for precise media synchronization!\r
+*/\r
+\r
+typedef struct ASIOChannelInfo\r
+{\r
+       long channel;                   // on input, channel index\r
+       ASIOBool isInput;               // on input\r
+       ASIOBool isActive;              // on exit\r
+       long channelGroup;              // dto\r
+       ASIOSampleType type;    // dto\r
+       char name[32];                  // dto\r
+} ASIOChannelInfo;\r
+\r
+ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);\r
+/* Purpose:\r
+         retreive information about the nature of a channel\r
+       Parameter:\r
+         info: pointer to a ASIOChannelInfo structure with\r
+               - channel: on input, the channel index of the channel in question.\r
+               - isInput: on input, ASIOTrue if info for an input channel is\r
+                 requested, else output\r
+               - channelGroup: on return, the channel group that the channel\r
+                 belongs to. For drivers which support different types of\r
+                 channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces,\r
+                 there should be a reasonable grouping of these types. Groups\r
+                 are always independant form a channel index, that is, a channel\r
+                 index always counts from 0 to numInputs/numOutputs regardless\r
+                 of the group it may belong to.\r
+                 There will always be at least one group (group 0). Please\r
+                 also note that by default, the host may decide to activate\r
+                 channels 0 and 1; thus, these should belong to the most\r
+                 useful type (analog i/o, if present).\r
+               - type: on return, contains the sample type of the channel\r
+               - isActive: on return, ASIOTrue if channel is active as it was\r
+                 installed by ASIOCreateBuffers(), ASIOFalse else\r
+               - name:  describing the type of channel in question. Used to allow\r
+                 for user selection, and enabling of specific channels. examples:\r
+             "Analog In", "SPDIF Out" etc\r
+       Returns:\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         If possible, the string should be organised such that the first\r
+         characters are most significantly describing the nature of the\r
+         port, to allow for identification even if the view showing the\r
+         port name is too small to display more than 8 characters, for\r
+         instance.\r
+*/\r
+\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+// Buffer preparation\r
+//- - - - - - - - - - - - - - - - - - - - - - - - -\r
+\r
+typedef struct ASIOBufferInfo\r
+{\r
+       ASIOBool isInput;                       // on input:  ASIOTrue: input, else output\r
+       long channelNum;                        // on input:  channel index\r
+       void *buffers[2];                       // on output: double buffer addresses\r
+} ASIOBufferInfo;\r
+\r
+ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+       long bufferSize, ASIOCallbacks *callbacks);\r
+\r
+/* Purpose:\r
+         Allocates input/output buffers for all input and output channels to be activated.\r
+       Parameter:\r
+         bufferInfos is a pointer to an array of ASIOBufferInfo structures:\r
+           - isInput: on input, ASIOTrue if the buffer is to be allocated\r
+             for an input, output buffer else\r
+           - channelNum: on input, the index of the channel in question\r
+             (counting from 0)\r
+           - buffers: on exit, 2 pointers to the halves of the channels' double-buffer.\r
+             the size of the buffer(s) of course depend on both the ASIOSampleType\r
+             as obtained from ASIOGetChannelInfo(), and bufferSize\r
+         numChannels is the sum of all input and output channels to be created;\r
+         thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo\r
+         structures.\r
+         bufferSize selects one of the possible buffer sizes as obtained from\r
+         ASIOGetBufferSizes().\r
+         callbacks is a pointer to an ASIOCallbacks structure.\r
+       Returns:\r
+         If not enough memory is available ASE_NoMemory will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+         If bufferSize is not supported, or one or more of the bufferInfos elements\r
+         contain invalid settings, ASE_InvalidMode will be returned.\r
+       Notes:\r
+         If individual channel selection is not possible but requested,\r
+         the driver has to handle this. namely, bufferSwitch() will only\r
+         have filled buffers of enabled outputs. If possible, processing\r
+         and buss activities overhead should be avoided for channels which\r
+         were not enabled here.\r
+*/\r
+\r
+ASIOError ASIODisposeBuffers(void);\r
+/* Purpose:\r
+         Releases all buffers for the device.\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If no buffer were ever prepared, ASE_InvalidMode will be returned.\r
+         If no input/output is present ASE_NotPresent will be returned.\r
+       Notes:\r
+         This implies ASIOStop().\r
+*/\r
+\r
+ASIOError ASIOControlPanel(void);\r
+/* Purpose:\r
+         request the driver to start a control panel component\r
+         for device specific user settings. This will not be\r
+         accessed on some platforms (where the component is accessed\r
+         instead).\r
+       Parameter:\r
+         None.\r
+       Returns:\r
+         If no panel is available ASE_NotPresent will be returned.\r
+         Actually, the return code is ignored.\r
+       Notes:\r
+         if the user applied settings which require a re-configuration\r
+         of parts or all of the enigine and/or driver (such as a change of\r
+         the block size), the asioMessage callback can be used (see\r
+         ASIO_Callbacks).\r
+*/\r
+\r
+ASIOError ASIOFuture(long selector, void *params);\r
+/* Purpose:\r
+         various\r
+       Parameter:\r
+         selector: operation Code as to be defined. zero is reserved for\r
+         testing purposes.\r
+         params: depends on the selector; usually pointer to a structure\r
+         for passing and retreiving any type and amount of parameters.\r
+       Returns:\r
+         the return value is also selector dependant. if the selector\r
+         is unknown, ASE_InvalidParameter should be returned to prevent\r
+         further calls with this selector. on success, ASE_SUCCESS\r
+         must be returned (note: ASE_OK is *not* sufficient!)\r
+       Notes:\r
+         see selectors defined below.    \r
+*/\r
+\r
+enum\r
+{\r
+       kAsioEnableTimeCodeRead = 1,    // no arguments\r
+       kAsioDisableTimeCodeRead,               // no arguments\r
+       kAsioSetInputMonitor,                   // ASIOInputMonitor* in params\r
+       kAsioTransport,                                 // ASIOTransportParameters* in params\r
+       kAsioSetInputGain,                              // ASIOChannelControls* in params, apply gain\r
+       kAsioGetInputMeter,                             // ASIOChannelControls* in params, fill meter\r
+       kAsioSetOutputGain,                             // ASIOChannelControls* in params, apply gain\r
+       kAsioGetOutputMeter,                    // ASIOChannelControls* in params, fill meter\r
+       kAsioCanInputMonitor,                   // no arguments for kAsioCanXXX selectors\r
+       kAsioCanTimeInfo,\r
+       kAsioCanTimeCode,\r
+       kAsioCanTransport,\r
+       kAsioCanInputGain,\r
+       kAsioCanInputMeter,\r
+       kAsioCanOutputGain,\r
+       kAsioCanOutputMeter\r
+};\r
+\r
+typedef struct ASIOInputMonitor\r
+{\r
+       long input;             // this input was set to monitor (or off), -1: all\r
+       long output;    // suggested output for monitoring the input (if so)\r
+       long gain;              // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB)\r
+       ASIOBool state; // ASIOTrue => on, ASIOFalse => off\r
+       long pan;               // suggested pan, 0 => all left, 0x7fffffff => right\r
+} ASIOInputMonitor;\r
+\r
+typedef struct ASIOChannelControls\r
+{\r
+       long channel;                   // on input, channel index\r
+       ASIOBool isInput;               // on input\r
+       long gain;                              // on input,  ranges 0 thru 0x7fffffff\r
+       long meter;                             // on return, ranges 0 thru 0x7fffffff\r
+       char future[32];\r
+} ASIOChannelControls;\r
+\r
+typedef struct ASIOTransportParameters\r
+{\r
+       long command;           // see enum below\r
+       ASIOSamples samplePosition;\r
+       long track;\r
+       long trackSwitches[16];         // 512 tracks on/off\r
+       char future[64];\r
+} ASIOTransportParameters;\r
+\r
+enum\r
+{\r
+       kTransStart = 1,\r
+       kTransStop,\r
+       kTransLocate,           // to samplePosition\r
+       kTransPunchIn,\r
+       kTransPunchOut,\r
+       kTransArmOn,            // track\r
+       kTransArmOff,           // track\r
+       kTransMonitorOn,        // track\r
+       kTransMonitorOff,       // track\r
+       kTransArm,                      // trackSwitches\r
+       kTransMonitor           // trackSwitches\r
+};\r
+\r
+ASIOError ASIOOutputReady(void);\r
+/* Purpose:\r
+         this tells the driver that the host has completed processing\r
+         the output buffers. if the data format required by the hardware\r
+         differs from the supported asio formats, but the hardware\r
+         buffers are DMA buffers, the driver will have to convert\r
+         the audio stream data; as the bufferSwitch callback is\r
+         usually issued at dma block switch time, the driver will\r
+         have to convert the *previous* host buffer, which increases\r
+         the output latency by one block.\r
+         when the host finds out that ASIOOutputReady() returns\r
+         true, it will issue this call whenever it completed\r
+         output processing. then the driver can convert the\r
+         host data directly to the dma buffer to be played next,\r
+         reducing output latency by one block.\r
+         another way to look at it is, that the buffer switch is called\r
+         in order to pass the *input* stream to the host, so that it can\r
+         process the input into the output, and the output stream is passed\r
+         to the driver when the host has completed its process.\r
+       Parameter:\r
+               None\r
+       Returns:\r
+         only if the above mentioned scenario is given, and a reduction\r
+         of output latency can be acheived by this mechanism, should\r
+         ASE_OK be returned. otherwise (and usually), ASE_NotPresent\r
+         should be returned in order to prevent further calls to this\r
+         function. note that the host may want to determine if it is\r
+         to use this when the system is not yet fully initialized, so\r
+         ASE_OK should always be returned if the mechanism makes sense.          \r
+       Notes:\r
+         please remeber to adjust ASIOGetLatencies() according to\r
+         whether ASIOOutputReady() was ever called or not, if your\r
+         driver supports this scenario.\r
+         also note that the engine may fail to call ASIO_OutputReady()\r
+         in time in overload cases. as already mentioned, bufferSwitch\r
+      should be called for every block regardless of whether a block\r
+      could be processed in time.\r
+*/\r
+\r
+// restore old alignment\r
+#if defined(_MSC_VER) && !defined(__MWERKS__) \r
+#pragma pack(pop)\r
+#elif PRAGMA_ALIGN_SUPPORTED\r
+#pragma options align = reset\r
+#endif\r
+\r
+#endif\r
+\r
diff --git a/tests/Windows/asiodrivers.cpp b/tests/Windows/asiodrivers.cpp
new file mode 100644 (file)
index 0000000..5f56454
--- /dev/null
@@ -0,0 +1,186 @@
+#include <string.h>\r
+#include "asiodrivers.h"\r
+\r
+AsioDrivers* asioDrivers = 0;\r
+\r
+bool loadAsioDriver(char *name);\r
+\r
+bool loadAsioDriver(char *name)\r
+{\r
+       if(!asioDrivers)\r
+               asioDrivers = new AsioDrivers();\r
+       if(asioDrivers)\r
+               return asioDrivers->loadDriver(name);\r
+       return false;\r
+}\r
+\r
+//------------------------------------------------------------------------------------\r
+\r
+#if MAC\r
+\r
+bool resolveASIO(unsigned long aconnID);\r
+\r
+AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio')\r
+{\r
+       connID = -1;\r
+       curIndex = -1;\r
+}\r
+\r
+AsioDrivers::~AsioDrivers()\r
+{\r
+       removeCurrentDriver();\r
+}\r
+\r
+bool AsioDrivers::getCurrentDriverName(char *name)\r
+{\r
+       if(curIndex >= 0)\r
+               return getName(curIndex, name);\r
+       return false;\r
+}\r
+\r
+long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
+{\r
+       for(long i = 0; i < getNumFragments() && i < maxDrivers; i++)\r
+               getName(i, names[i]);\r
+       return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers;\r
+}\r
+\r
+bool AsioDrivers::loadDriver(char *name)\r
+{\r
+       char dname[64];\r
+       unsigned long newID;\r
+\r
+       for(long i = 0; i < getNumFragments(); i++)\r
+       {\r
+               if(getName(i, dname) && !strcmp(name, dname))\r
+               {\r
+                       if(newInstance(i, &newID))\r
+                       {\r
+                               if(resolveASIO(newID))\r
+                               {\r
+                                       if(connID != -1)\r
+                                               removeInstance(curIndex, connID);\r
+                                       curIndex = i;\r
+                                       connID = newID;\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+       }\r
+       return false;\r
+}\r
+\r
+void AsioDrivers::removeCurrentDriver()\r
+{\r
+       if(connID != -1)\r
+               removeInstance(curIndex, connID);\r
+       connID = -1;\r
+       curIndex = -1;\r
+}\r
+\r
+//------------------------------------------------------------------------------------\r
+\r
+#elif WINDOWS\r
+\r
+#include "iasiodrv.h"\r
+\r
+extern IASIO* theAsioDriver;\r
+\r
+AsioDrivers::AsioDrivers() : AsioDriverList()\r
+{\r
+       curIndex = -1;\r
+}\r
+\r
+AsioDrivers::~AsioDrivers()\r
+{\r
+}\r
+\r
+bool AsioDrivers::getCurrentDriverName(char *name)\r
+{\r
+       if(curIndex >= 0)\r
+               return asioGetDriverName(curIndex, name, 32) == 0 ? true : false;\r
+       name[0] = 0;\r
+       return false;\r
+}\r
+\r
+long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
+{\r
+       for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++)\r
+               asioGetDriverName(i, names[i], 32);\r
+       return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers;\r
+}\r
+\r
+bool AsioDrivers::loadDriver(char *name)\r
+{\r
+       char dname[64];\r
+       char curName[64];\r
+\r
+       for(long i = 0; i < asioGetNumDev(); i++)\r
+       {\r
+               if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname))\r
+               {\r
+                       curName[0] = 0;\r
+                       getCurrentDriverName(curName);  // in case we fail...\r
+                       removeCurrentDriver();\r
+\r
+                       if(!asioOpenDriver(i, (void **)&theAsioDriver))\r
+                       {\r
+                               curIndex = i;\r
+                               return true;\r
+                       }\r
+                       else\r
+                       {\r
+                               theAsioDriver = 0;\r
+                               if(curName[0] && strcmp(dname, curName))\r
+                                       loadDriver(curName);    // try restore\r
+                       }\r
+                       break;\r
+               }\r
+       }\r
+       return false;\r
+}\r
+\r
+void AsioDrivers::removeCurrentDriver()\r
+{\r
+       if(curIndex != -1)\r
+               asioCloseDriver(curIndex);\r
+       curIndex = -1;\r
+}\r
+\r
+#elif SGI || BEOS\r
+\r
+#include "asiolist.h"\r
+\r
+AsioDrivers::AsioDrivers() \r
+       : AsioDriverList()\r
+{\r
+       curIndex = -1;\r
+}\r
+\r
+AsioDrivers::~AsioDrivers()\r
+{\r
+}\r
+\r
+bool AsioDrivers::getCurrentDriverName(char *name)\r
+{\r
+       return false;\r
+}\r
+\r
+long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
+{\r
+       return 0;\r
+}\r
+\r
+bool AsioDrivers::loadDriver(char *name)\r
+{\r
+       return false;\r
+}\r
+\r
+void AsioDrivers::removeCurrentDriver()\r
+{\r
+}\r
+\r
+#else\r
+#error implement me\r
+#endif\r
diff --git a/tests/Windows/asiodrivers.h b/tests/Windows/asiodrivers.h
new file mode 100644 (file)
index 0000000..2ddf7ad
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __AsioDrivers__\r
+#define __AsioDrivers__\r
+\r
+#include "ginclude.h"\r
+\r
+#if MAC\r
+#include "CodeFragments.hpp"\r
+\r
+class AsioDrivers : public CodeFragments\r
+\r
+#elif WINDOWS\r
+#include <windows.h>\r
+#include "asiolist.h"\r
+\r
+class AsioDrivers : public AsioDriverList\r
+\r
+#elif SGI || BEOS\r
+#include "asiolist.h"\r
+\r
+class AsioDrivers : public AsioDriverList\r
+\r
+#else\r
+#error implement me\r
+#endif\r
+\r
+{\r
+public:\r
+       AsioDrivers();\r
+       ~AsioDrivers();\r
+       \r
+       bool getCurrentDriverName(char *name);\r
+       long getDriverNames(char **names, long maxDrivers);\r
+       bool loadDriver(char *name);\r
+       void removeCurrentDriver();\r
+       long getCurrentDriverIndex() {return curIndex;}\r
+protected:\r
+       unsigned long connID;\r
+       long curIndex;\r
+};\r
+\r
+#endif\r
diff --git a/tests/Windows/asiodrvr.h b/tests/Windows/asiodrvr.h
new file mode 100644 (file)
index 0000000..663f75a
--- /dev/null
@@ -0,0 +1,76 @@
+/*\r
+       Steinberg Audio Stream I/O API\r
+       (c) 1996, Steinberg Soft- und Hardware GmbH\r
+       charlie (May 1996)\r
+\r
+       asiodrvr.h\r
+       c++ superclass to implement asio functionality. from this,\r
+       you can derive whatever required\r
+*/\r
+\r
+#ifndef _asiodrvr_\r
+#define _asiodrvr_\r
+\r
+// cpu and os system we are running on\r
+#include "asiosys.h"\r
+// basic "C" interface\r
+#include "asio.h"\r
+\r
+class AsioDriver;\r
+extern AsioDriver *getDriver();                // for generic constructor \r
+\r
+#if WINDOWS\r
+#include <windows.h>\r
+#include "combase.h"\r
+#include "iasiodrv.h"\r
+class AsioDriver : public IASIO ,public CUnknown\r
+{\r
+public:\r
+       AsioDriver(LPUNKNOWN pUnk, HRESULT *phr);\r
+\r
+       DECLARE_IUNKNOWN\r
+       // Factory method\r
+       static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);\r
+       // IUnknown\r
+       virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject);\r
+\r
+#else\r
+\r
+class AsioDriver\r
+{\r
+public:\r
+       AsioDriver();\r
+#endif\r
+       virtual ~AsioDriver();\r
+\r
+       virtual ASIOBool init(void* sysRef);\r
+       virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero\r
+       virtual long getDriverVersion();\r
+       virtual void getErrorMessage(char *string);     // max 124 bytes incl.\r
+\r
+       virtual ASIOError start();\r
+       virtual ASIOError stop();\r
+\r
+       virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);\r
+       virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);\r
+       virtual ASIOError getBufferSize(long *minSize, long *maxSize,\r
+               long *preferredSize, long *granularity);\r
+\r
+       virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);\r
+       virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);\r
+       virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);\r
+       virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);\r
+       virtual ASIOError setClockSource(long reference);\r
+\r
+       virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
+       virtual ASIOError getChannelInfo(ASIOChannelInfo *info);\r
+\r
+       virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+               long bufferSize, ASIOCallbacks *callbacks);\r
+       virtual ASIOError disposeBuffers();\r
+\r
+       virtual ASIOError controlPanel();\r
+       virtual ASIOError future(long selector, void *opt);\r
+       virtual ASIOError outputReady();\r
+};\r
+#endif\r
diff --git a/tests/Windows/asiolist.cpp b/tests/Windows/asiolist.cpp
new file mode 100644 (file)
index 0000000..5a62f5b
--- /dev/null
@@ -0,0 +1,268 @@
+#include <windows.h>\r
+#include "iasiodrv.h"\r
+#include "asiolist.h"\r
+\r
+#define ASIODRV_DESC           "description"\r
+#define INPROC_SERVER          "InprocServer32"\r
+#define ASIO_PATH                      "software\\asio"\r
+#define COM_CLSID                      "clsid"\r
+\r
+// ******************************************************************\r
+// Local Functions \r
+// ******************************************************************\r
+static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)\r
+{\r
+       HKEY                    hkEnum,hksub,hkpath;\r
+       char                    databuf[512];\r
+       LONG                    cr,rc = -1;\r
+       DWORD                   datatype,datasize;\r
+       DWORD                   index;\r
+       OFSTRUCT                ofs;\r
+       HFILE                   hfile;\r
+       BOOL                    found = FALSE;\r
+\r
+       CharLowerBuff(clsidstr,strlen(clsidstr));\r
+       if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {\r
+\r
+               index = 0;\r
+               while (cr == ERROR_SUCCESS && !found) {\r
+                       cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512);\r
+                       if (cr == ERROR_SUCCESS) {\r
+                               CharLowerBuff(databuf,strlen(databuf));\r
+                               if (!(strcmp(databuf,clsidstr))) {\r
+                                       if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {\r
+                                               if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {\r
+                                                       datatype = REG_SZ; datasize = (DWORD)dllpathsize;\r
+                                                       cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);\r
+                                                       if (cr == ERROR_SUCCESS) {\r
+                                                               memset(&ofs,0,sizeof(OFSTRUCT));\r
+                                                               ofs.cBytes = sizeof(OFSTRUCT); \r
+                                                               hfile = OpenFile(dllpath,&ofs,OF_EXIST);\r
+                                                               if (hfile) rc = 0; \r
+                                                       }\r
+                                                       RegCloseKey(hkpath);\r
+                                               }\r
+                                               RegCloseKey(hksub);\r
+                                       }\r
+                                       found = TRUE;   // break out \r
+                               }\r
+                       }\r
+               }                               \r
+               RegCloseKey(hkEnum);\r
+       }\r
+       return rc;\r
+}\r
+\r
+\r
+static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)\r
+{\r
+       HKEY    hksub;\r
+       char    databuf[256];\r
+       char    dllpath[MAXPATHLEN];\r
+       WORD    wData[100];\r
+       CLSID   clsid;\r
+       DWORD   datatype,datasize;\r
+       LONG    cr,rc;\r
+\r
+       if (!lpdrv) {\r
+               if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {\r
+\r
+                       datatype = REG_SZ; datasize = 256;\r
+                       cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);\r
+                       if (cr == ERROR_SUCCESS) {\r
+                               rc = findDrvPath (databuf,dllpath,MAXPATHLEN);\r
+                               if (rc == 0) {\r
+                                       lpdrv = new ASIODRVSTRUCT[1];\r
+                                       if (lpdrv) {\r
+                                               memset(lpdrv,0,sizeof(ASIODRVSTRUCT));\r
+                                               lpdrv->drvID = drvID;\r
+                                               MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);\r
+                                               if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {\r
+                                                       memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));\r
+                                               }\r
+\r
+                                               datatype = REG_SZ; datasize = 256;\r
+                                               cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);\r
+                                               if (cr == ERROR_SUCCESS) {\r
+                                                       strcpy(lpdrv->drvname,databuf);\r
+                                               }\r
+                                               else strcpy(lpdrv->drvname,keyname);\r
+                                       }\r
+                               }\r
+                       }\r
+                       RegCloseKey(hksub);\r
+               }\r
+       }       \r
+       else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);\r
+\r
+       return lpdrv;\r
+}\r
+\r
+static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv)\r
+{\r
+       IASIO   *iasio;\r
+\r
+       if (lpdrv != 0) {\r
+               deleteDrvStruct(lpdrv->next);\r
+               if (lpdrv->asiodrv) {\r
+                       iasio = (IASIO *)lpdrv->asiodrv;\r
+                       iasio->Release();\r
+               }\r
+               delete lpdrv;\r
+       }\r
+}\r
+\r
+\r
+static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv)\r
+{\r
+       while (lpdrv) {\r
+               if (lpdrv->drvID == drvID) return lpdrv;\r
+               lpdrv = lpdrv->next;\r
+       }\r
+       return 0;\r
+}\r
+// ******************************************************************\r
+\r
+\r
+// ******************************************************************\r
+//     AsioDriverList\r
+// ******************************************************************\r
+AsioDriverList::AsioDriverList ()\r
+{\r
+       HKEY                    hkEnum = 0;\r
+       char                    keyname[MAXDRVNAMELEN];\r
+       LPASIODRVSTRUCT pdl;\r
+       LONG                    cr;\r
+       DWORD                   index = 0;\r
+       BOOL                    fin = FALSE;\r
+\r
+       numdrv          = 0;\r
+       lpdrvlist       = 0;\r
+\r
+       cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);\r
+       while (cr == ERROR_SUCCESS) {\r
+               if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {\r
+                       lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);\r
+               }\r
+               else fin = TRUE;\r
+       }\r
+       if (hkEnum) RegCloseKey(hkEnum);\r
+\r
+       pdl = lpdrvlist;\r
+       while (pdl) {\r
+               numdrv++;\r
+               pdl = pdl->next;\r
+       }\r
+\r
+       if (numdrv) CoInitialize(0);    // initialize COM\r
+}\r
+\r
+AsioDriverList::~AsioDriverList ()\r
+{\r
+       if (numdrv) {\r
+               deleteDrvStruct(lpdrvlist);\r
+               CoUninitialize();\r
+       }\r
+}\r
+\r
+\r
+LONG AsioDriverList::asioGetNumDev (VOID)\r
+{\r
+       return (LONG)numdrv;\r
+}\r
+\r
+\r
+LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv)\r
+{\r
+       LPASIODRVSTRUCT lpdrv = 0;\r
+       long                    rc;\r
+\r
+       if (!asiodrv) return DRVERR_INVALID_PARAM;\r
+\r
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
+               if (!lpdrv->asiodrv) {\r
+                       rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv);\r
+                       if (rc == S_OK) {\r
+                               lpdrv->asiodrv = *asiodrv;\r
+                               return 0;\r
+                       }\r
+                       // else if (rc == REGDB_E_CLASSNOTREG)\r
+                       //      strcpy (info->messageText, "Driver not registered in the Registration Database!");\r
+               }\r
+               else rc = DRVERR_DEVICE_ALREADY_OPEN;\r
+       }\r
+       else rc = DRVERR_DEVICE_NOT_FOUND;\r
+       \r
+       return rc;\r
+}\r
+\r
+\r
+LONG AsioDriverList::asioCloseDriver (int drvID)\r
+{\r
+       LPASIODRVSTRUCT lpdrv = 0;\r
+       IASIO                   *iasio;\r
+\r
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
+               if (lpdrv->asiodrv) {\r
+                       iasio = (IASIO *)lpdrv->asiodrv;\r
+                       iasio->Release();\r
+                       lpdrv->asiodrv = 0;\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize)\r
+{      \r
+       LPASIODRVSTRUCT                 lpdrv = 0;\r
+\r
+       if (!drvname) return DRVERR_INVALID_PARAM;\r
+\r
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
+               if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) {\r
+                       strcpy(drvname,lpdrv->drvname);\r
+               }\r
+               else {\r
+                       memcpy(drvname,lpdrv->drvname,drvnamesize-4);\r
+                       drvname[drvnamesize-4] = '.';\r
+                       drvname[drvnamesize-3] = '.';\r
+                       drvname[drvnamesize-2] = '.';\r
+                       drvname[drvnamesize-1] = 0;\r
+               }\r
+               return 0;\r
+       }\r
+       return DRVERR_DEVICE_NOT_FOUND;\r
+}\r
+\r
+LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize)\r
+{\r
+       LPASIODRVSTRUCT                 lpdrv = 0;\r
+\r
+       if (!dllpath) return DRVERR_INVALID_PARAM;\r
+\r
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
+               if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) {\r
+                       strcpy(dllpath,lpdrv->dllpath);\r
+                       return 0;\r
+               }\r
+               dllpath[0] = 0;\r
+               return DRVERR_INVALID_PARAM;\r
+       }\r
+       return DRVERR_DEVICE_NOT_FOUND;\r
+}\r
+\r
+LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid)\r
+{\r
+       LPASIODRVSTRUCT                 lpdrv = 0;\r
+\r
+       if (!clsid) return DRVERR_INVALID_PARAM;\r
+\r
+       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
+               memcpy(clsid,&lpdrv->clsid,sizeof(CLSID));\r
+               return 0;\r
+       }\r
+       return DRVERR_DEVICE_NOT_FOUND;\r
+}\r
+\r
+\r
diff --git a/tests/Windows/asiolist.h b/tests/Windows/asiolist.h
new file mode 100644 (file)
index 0000000..01c64f0
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __asiolist__\r
+#define __asiolist__\r
+\r
+#define DRVERR                 -5000\r
+#define DRVERR_INVALID_PARAM           DRVERR-1\r
+#define DRVERR_DEVICE_ALREADY_OPEN     DRVERR-2\r
+#define DRVERR_DEVICE_NOT_FOUND                DRVERR-3\r
+\r
+#define MAXPATHLEN                     512\r
+#define MAXDRVNAMELEN          128\r
+\r
+struct asiodrvstruct\r
+{\r
+       int                                             drvID;\r
+       CLSID                                   clsid;\r
+       char                                    dllpath[MAXPATHLEN];\r
+       char                                    drvname[MAXDRVNAMELEN];\r
+       LPVOID                                  asiodrv;\r
+       struct asiodrvstruct    *next;\r
+};\r
+\r
+typedef struct asiodrvstruct ASIODRVSTRUCT;\r
+typedef ASIODRVSTRUCT  *LPASIODRVSTRUCT;\r
+\r
+class AsioDriverList {\r
+public:\r
+       AsioDriverList();\r
+       ~AsioDriverList();\r
+       \r
+       LONG asioOpenDriver (int,VOID **);\r
+       LONG asioCloseDriver (int);\r
+\r
+       // nice to have\r
+       LONG asioGetNumDev (VOID);\r
+       LONG asioGetDriverName (int,char *,int);                \r
+       LONG asioGetDriverPath (int,char *,int);\r
+       LONG asioGetDriverCLSID (int,CLSID *);\r
+\r
+       // or use directly access\r
+       LPASIODRVSTRUCT lpdrvlist;\r
+       int                             numdrv;\r
+};\r
+\r
+typedef class AsioDriverList *LPASIODRIVERLIST;\r
+\r
+#endif\r
diff --git a/tests/Windows/asiosys.h b/tests/Windows/asiosys.h
new file mode 100644 (file)
index 0000000..37f7a48
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __asiosys__\r
+       #define __asiosys__\r
+\r
+       #ifdef WIN32\r
+               #undef MAC \r
+               #define PPC 0\r
+               #define WINDOWS 1\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+\r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+       \r
+       #elif BEOS\r
+               #define MAC 0\r
+               #define PPC 0\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               \r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+               \r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+\r
+       #elif SGI\r
+               #define MAC 0\r
+               #define PPC 0\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+               \r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+               \r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+\r
+       #else   // MAC\r
+\r
+               #define MAC 1\r
+               #define PPC 1\r
+               #define WINDOWS 0\r
+               #define PC 0\r
+               #define SGI 0\r
+               #define SUN 0\r
+               #define LINUX 0\r
+               #define BEOS 0\r
+\r
+               #define NATIVE_INT64 0\r
+               #define IEEE754_64FLOAT 1\r
+\r
+               #ifndef DEBUG\r
+                       #define DEBUG 0\r
+                       #if DEBUG\r
+                               void DEBUGGERMESSAGE(char *string);\r
+                       #else\r
+                               #define DEBUGGERMESSAGE(a)\r
+                       #endif\r
+               #endif\r
+       #endif\r
+\r
+#endif\r
diff --git a/tests/Windows/call_inout.dsp b/tests/Windows/call_inout.dsp
new file mode 100644 (file)
index 0000000..6af5e2e
--- /dev/null
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="call_inout" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=call_inout - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "call_inout.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "call_inout.mak" CFG="call_inout - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "call_inout - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "call_inout - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "call_inout - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "call_inout - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "call_inout - Win32 Release"\r
+# Name "call_inout - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\call_inout.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrvr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiosys.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ginclude.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iasiodrv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/call_playtwo.dsp b/tests/Windows/call_playtwo.dsp
new file mode 100644 (file)
index 0000000..1c9966b
--- /dev/null
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="call_playtwo" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=call_playtwo - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "call_playtwo.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "call_playtwo.mak" CFG="call_playtwo - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "call_playtwo - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "call_playtwo - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "call_playtwo - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "call_playtwo - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "call_playtwo - Win32 Release"\r
+# Name "call_playtwo - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\call_playtwo.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/call_saw.dsp b/tests/Windows/call_saw.dsp
new file mode 100644 (file)
index 0000000..8db91ca
--- /dev/null
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="call_saw" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=call_saw - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "call_saw.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "call_saw.mak" CFG="call_saw - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "call_saw - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "call_saw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "call_saw - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "call_saw - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "call_saw - Win32 Release"\r
+# Name "call_saw - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\call_saw.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrvr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiosys.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ginclude.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iasiodrv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/call_twostreams.dsp b/tests/Windows/call_twostreams.dsp
new file mode 100644 (file)
index 0000000..16da2e5
--- /dev/null
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Project File - Name="call_twostreams" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=call_twostreams - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "call_twostreams.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "call_twostreams.mak" CFG="call_twostreams - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "call_twostreams - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "call_twostreams - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "call_twostreams - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "call_twostreams - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "call_twostreams - Win32 Release"\r
+# Name "call_twostreams - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=..\call_twostreams.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/ginclude.h b/tests/Windows/ginclude.h
new file mode 100644 (file)
index 0000000..b627dc2
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __gInclude__\r
+#define __gInclude__\r
+\r
+#if SGI \r
+       #undef BEOS \r
+       #undef MAC \r
+       #undef WINDOWS\r
+       //\r
+       #define ASIO_BIG_ENDIAN 1\r
+       #define ASIO_CPU_MIPS 1\r
+#elif defined WIN32\r
+       #undef BEOS \r
+       #undef MAC \r
+       #undef SGI\r
+       #define WINDOWS 1\r
+       #define ASIO_LITTLE_ENDIAN 1\r
+       #define ASIO_CPU_X86 1\r
+#elif BEOS\r
+       #undef MAC \r
+       #undef SGI\r
+       #undef WINDOWS\r
+       #define ASIO_LITTLE_ENDIAN 1\r
+       #define ASIO_CPU_X86 1\r
+       //\r
+#else\r
+       #define MAC 1\r
+       #undef BEOS \r
+       #undef WINDOWS\r
+       #undef SGI\r
+       #define ASIO_BIG_ENDIAN 1\r
+       #define ASIO_CPU_PPC 1\r
+#endif\r
+\r
+// always\r
+#define NATIVE_INT64 0\r
+#define IEEE754_64FLOAT 1\r
+\r
+#endif // __gInclude__\r
diff --git a/tests/Windows/iasiodrv.h b/tests/Windows/iasiodrv.h
new file mode 100644 (file)
index 0000000..64d2dbb
--- /dev/null
@@ -0,0 +1,37 @@
+#include "asiosys.h"\r
+#include "asio.h"\r
+\r
+/* Forward Declarations */ \r
+\r
+#ifndef __ASIODRIVER_FWD_DEFINED__\r
+#define __ASIODRIVER_FWD_DEFINED__\r
+typedef interface IASIO IASIO;\r
+#endif         /* __ASIODRIVER_FWD_DEFINED__ */\r
+\r
+interface IASIO : public IUnknown\r
+{\r
+\r
+       virtual ASIOBool init(void *sysHandle) = 0;\r
+       virtual void getDriverName(char *name) = 0;     \r
+       virtual long getDriverVersion() = 0;\r
+       virtual void getErrorMessage(char *string) = 0; \r
+       virtual ASIOError start() = 0;\r
+       virtual ASIOError stop() = 0;\r
+       virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0;\r
+       virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0;\r
+       virtual ASIOError getBufferSize(long *minSize, long *maxSize,\r
+               long *preferredSize, long *granularity) = 0;\r
+       virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0;\r
+       virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0;\r
+       virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0;\r
+       virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0;\r
+       virtual ASIOError setClockSource(long reference) = 0;\r
+       virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;\r
+       virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0;\r
+       virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
+               long bufferSize, ASIOCallbacks *callbacks) = 0;\r
+       virtual ASIOError disposeBuffers() = 0;\r
+       virtual ASIOError controlPanel() = 0;\r
+       virtual ASIOError future(long selector,void *opt) = 0;\r
+       virtual ASIOError outputReady() = 0;\r
+};\r
diff --git a/tests/Windows/in_out.dsp b/tests/Windows/in_out.dsp
new file mode 100644 (file)
index 0000000..4113ca1
--- /dev/null
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="in_out" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=in_out - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "in_out.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "in_out.mak" CFG="in_out - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "in_out - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "in_out - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "in_out - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "in_out - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "in_out - Win32 Release"\r
+# Name "in_out - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\in_out.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrvr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiosys.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ginclude.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iasiodrv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/info.dsp b/tests/Windows/info.dsp
new file mode 100644 (file)
index 0000000..02facd8
--- /dev/null
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="info" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=info - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "info.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "info.mak" CFG="info - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "info - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "info - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "info - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "info - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "info - Win32 Release"\r
+# Name "info - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\info.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrvr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiosys.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ginclude.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iasiodrv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/play_raw.dsp b/tests/Windows/play_raw.dsp
new file mode 100644 (file)
index 0000000..5f3eba9
--- /dev/null
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="play_raw" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=play_raw - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "play_raw.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "play_raw.mak" CFG="play_raw - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "play_raw - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "play_raw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "play_raw - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "play_raw - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "play_raw - Win32 Release"\r
+# Name "play_raw - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\play_raw.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrvr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiosys.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ginclude.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iasiodrv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/play_saw.dsp b/tests/Windows/play_saw.dsp
new file mode 100644 (file)
index 0000000..92bff12
--- /dev/null
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="play_saw" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=play_saw - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "play_saw.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "play_saw.mak" CFG="play_saw - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "play_saw - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "play_saw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "play_saw - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "play_saw - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "play_saw - Win32 Release"\r
+# Name "play_saw - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\play_saw.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrvr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiosys.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ginclude.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iasiodrv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/record_raw.dsp b/tests/Windows/record_raw.dsp
new file mode 100644 (file)
index 0000000..65f8285
--- /dev/null
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="record_raw" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=record_raw - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "record_raw.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "record_raw.mak" CFG="record_raw - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "record_raw - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "record_raw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "record_raw - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "record_raw - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "record_raw - Win32 Release"\r
+# Name "record_raw - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\record_raw.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrvr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiosys.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ginclude.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iasiodrv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/Windows/rtaudio.dsw b/tests/Windows/rtaudio.dsw
new file mode 100644 (file)
index 0000000..26b9d4f
--- /dev/null
@@ -0,0 +1,113 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "call_inout"=".\call_inout.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "call_saw"=".\call_saw.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "in_out"=".\in_out.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "info"=".\info.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "play_raw"=".\play_raw.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "play_saw"=".\play_saw.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "record_raw"=".\record_raw.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "twostreams"=".\twostreams.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
diff --git a/tests/Windows/twostreams.dsp b/tests/Windows/twostreams.dsp
new file mode 100644 (file)
index 0000000..9e67e02
--- /dev/null
@@ -0,0 +1,150 @@
+# Microsoft Developer Studio Project File - Name="twostreams" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
+\r
+CFG=twostreams - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "twostreams.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "twostreams.mak" CFG="twostreams - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "twostreams - Win32 Release" (based on "Win32 (x86) Console Application")\r
+!MESSAGE "twostreams - Win32 Debug" (based on "Win32 (x86) Console Application")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "twostreams - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386\r
+\r
+!ELSEIF  "$(CFG)" == "twostreams - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir ""\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "twostreams - Win32 Release"\r
+# Name "twostreams - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\twostreams.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\asio.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrivers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiodrvr.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiolist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\asiosys.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ginclude.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\iasiodrv.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\RtAudio.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/tests/asio/Debug/.placeholder b/tests/asio/Debug/.placeholder
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tests/asio/Release/.placeholder b/tests/asio/Release/.placeholder
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tests/asio/asio.cpp b/tests/asio/asio.cpp
deleted file mode 100644 (file)
index b241663..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/*\r
-       Steinberg Audio Stream I/O API\r
-       (c) 1996, Steinberg Soft- und Hardware GmbH\r
-\r
-       asio.cpp\r
-       \r
-       asio functions entries which translate the\r
-       asio interface to the asiodrvr class methods\r
-*/ \r
-       \r
-#include <string.h>\r
-#include "asiosys.h"           // platform definition\r
-#include "asio.h"\r
-\r
-#if MAC\r
-#include "asiodrvr.h"\r
-\r
-#pragma export on\r
-\r
-AsioDriver *theAsioDriver = 0;\r
-\r
-extern "C"\r
-{\r
-\r
-long main()\r
-{\r
-       return 'ASIO';\r
-}\r
-\r
-#elif WINDOWS\r
-\r
-#include "windows.h"\r
-#include "iasiodrv.h"\r
-#include "asiodrivers.h"\r
-\r
-IASIO *theAsioDriver = 0;\r
-extern AsioDrivers *asioDrivers;\r
-\r
-#elif SGI || SUN || BEOS || LINUX\r
-#include "asiodrvr.h"\r
-static AsioDriver *theAsioDriver = 0;\r
-#endif\r
-\r
-//-----------------------------------------------------------------------------------------------------\r
-ASIOError ASIOInit(ASIODriverInfo *info)\r
-{\r
-#if MAC || SGI || SUN || BEOS || LINUX\r
-       if(theAsioDriver)\r
-       {\r
-               delete theAsioDriver;\r
-               theAsioDriver = 0;\r
-       }               \r
-       info->driverVersion = 0;\r
-       strcpy(info->name, "No ASIO Driver");\r
-       theAsioDriver = getDriver();\r
-       if(!theAsioDriver)\r
-       {\r
-               strcpy(info->errorMessage, "Not enough memory for the ASIO driver!"); \r
-               return ASE_NotPresent;\r
-       }\r
-       if(!theAsioDriver->init(info->sysRef))\r
-       {\r
-               theAsioDriver->getErrorMessage(info->errorMessage);\r
-               delete theAsioDriver;\r
-               theAsioDriver = 0;\r
-               return ASE_NotPresent;\r
-       }\r
-       strcpy(info->errorMessage, "No ASIO Driver Error");\r
-       theAsioDriver->getDriverName(info->name);\r
-       info->driverVersion = theAsioDriver->getDriverVersion();\r
-       return ASE_OK;\r
-\r
-#else\r
-\r
-       info->driverVersion = 0;\r
-       strcpy(info->name, "No ASIO Driver");\r
-       if(theAsioDriver)       // must be loaded!\r
-       {\r
-               if(!theAsioDriver->init(info->sysRef))\r
-               {\r
-                       theAsioDriver->getErrorMessage(info->errorMessage);\r
-                       theAsioDriver = 0;\r
-                       return ASE_NotPresent;\r
-               }               \r
-\r
-               strcpy(info->errorMessage, "No ASIO Driver Error");\r
-               theAsioDriver->getDriverName(info->name);\r
-               info->driverVersion = theAsioDriver->getDriverVersion();\r
-               return ASE_OK;\r
-       }\r
-       return ASE_NotPresent;\r
-\r
-#endif // !MAC\r
-}\r
-\r
-ASIOError ASIOExit(void)\r
-{\r
-       if(theAsioDriver)\r
-       {\r
-#if WINDOWS\r
-               asioDrivers->removeCurrentDriver();\r
-#else\r
-               delete theAsioDriver;\r
-#endif\r
-       }               \r
-       theAsioDriver = 0;\r
-       return ASE_OK;\r
-}\r
-\r
-ASIOError ASIOStart(void)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->start();\r
-}\r
-\r
-ASIOError ASIOStop(void)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->stop();\r
-}\r
-\r
-ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels)\r
-{\r
-       if(!theAsioDriver)\r
-       {\r
-               *numInputChannels = *numOutputChannels = 0;\r
-               return ASE_NotPresent;\r
-       }\r
-       return theAsioDriver->getChannels(numInputChannels, numOutputChannels);\r
-}\r
-\r
-ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency)\r
-{\r
-       if(!theAsioDriver)\r
-       {\r
-               *inputLatency = *outputLatency = 0;\r
-               return ASE_NotPresent;\r
-       }\r
-       return theAsioDriver->getLatencies(inputLatency, outputLatency);\r
-}\r
-\r
-ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity)\r
-{\r
-       if(!theAsioDriver)\r
-       {\r
-               *minSize = *maxSize = *preferredSize = *granularity = 0;\r
-               return ASE_NotPresent;\r
-       }\r
-       return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity);\r
-}\r
-\r
-ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->canSampleRate(sampleRate);\r
-}\r
-\r
-ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->getSampleRate(currentRate);\r
-}\r
-\r
-ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->setSampleRate(sampleRate);\r
-}\r
-\r
-ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources)\r
-{\r
-       if(!theAsioDriver)\r
-       {\r
-               *numSources = 0;\r
-               return ASE_NotPresent;\r
-       }\r
-       return theAsioDriver->getClockSources(clocks, numSources);\r
-}\r
-\r
-ASIOError ASIOSetClockSource(long reference)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->setClockSource(reference);\r
-}\r
-\r
-ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->getSamplePosition(sPos, tStamp);\r
-}\r
-\r
-ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info)\r
-{\r
-       if(!theAsioDriver)\r
-       {\r
-               info->channelGroup = -1;\r
-               info->type = ASIOSTInt16MSB;\r
-               strcpy(info->name, "None");\r
-               return ASE_NotPresent;\r
-       }\r
-       return theAsioDriver->getChannelInfo(info);\r
-}\r
-\r
-ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
-       long bufferSize, ASIOCallbacks *callbacks)\r
-{\r
-       if(!theAsioDriver)\r
-       {\r
-               ASIOBufferInfo *info = bufferInfos;\r
-               for(long i = 0; i < numChannels; i++, info++)\r
-                       info->buffers[0] = info->buffers[1] = 0;\r
-               return ASE_NotPresent;\r
-       }\r
-       return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks);\r
-}\r
-\r
-ASIOError ASIODisposeBuffers(void)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->disposeBuffers();\r
-}\r
-\r
-ASIOError ASIOControlPanel(void)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->controlPanel();\r
-}\r
-\r
-ASIOError ASIOFuture(long selector, void *opt)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->future(selector, opt);\r
-}\r
-\r
-ASIOError ASIOOutputReady(void)\r
-{\r
-       if(!theAsioDriver)\r
-               return ASE_NotPresent;\r
-       return theAsioDriver->outputReady();\r
-}\r
-\r
-#if MAC\r
-}      // extern "C"\r
-#pragma export off\r
-#endif\r
-\r
-\r
diff --git a/tests/asio/asio.h b/tests/asio/asio.h
deleted file mode 100644 (file)
index 3003130..0000000
+++ /dev/null
@@ -1,955 +0,0 @@
-//---------------------------------------------------------------------------------------------------\r
-//---------------------------------------------------------------------------------------------------\r
-\r
-/*\r
-       Steinberg Audio Stream I/O API\r
-       (c) 1997 - 1999, Steinberg Soft- und Hardware GmbH\r
-\r
-       ASIO Interface Specification v 2.0\r
-\r
-       basic concept is an i/o synchronous double-buffer scheme:\r
-       \r
-       on bufferSwitch(index == 0), host will read/write:\r
-\r
-               after ASIOStart(), the\r
-  read  first input buffer A (index 0)\r
-       |   will be invalid (empty)\r
-       *   ------------------------\r
-       |------------------------|-----------------------|\r
-       |                        |                       |\r
-       |  Input Buffer A (0)    |   Input Buffer B (1)  |\r
-       |                        |                       |\r
-       |------------------------|-----------------------|\r
-       |                        |                       |\r
-       |  Output Buffer A (0)   |   Output Buffer B (1) |\r
-       |                        |                       |\r
-       |------------------------|-----------------------|\r
-       *                        -------------------------\r
-       |                        before calling ASIOStart(),\r
-  write                      host will have filled output\r
-                             buffer B (index 1) already\r
-\r
-  *please* take special care of proper statement of input\r
-  and output latencies (see ASIOGetLatencies()), these\r
-  control sequencer sync accuracy\r
-\r
-*/\r
-\r
-//---------------------------------------------------------------------------------------------------\r
-//---------------------------------------------------------------------------------------------------\r
-\r
-/*\r
-\r
-prototypes summary:\r
-\r
-ASIOError ASIOInit(ASIODriverInfo *info);\r
-ASIOError ASIOExit(void);\r
-ASIOError ASIOStart(void);\r
-ASIOError ASIOStop(void);\r
-ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);\r
-ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);\r
-ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
-ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);\r
-ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);\r
-ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);\r
-ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);\r
-ASIOError ASIOSetClockSource(long reference);\r
-ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
-ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);\r
-ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
-       long bufferSize, ASIOCallbacks *callbacks);\r
-ASIOError ASIODisposeBuffers(void);\r
-ASIOError ASIOControlPanel(void);\r
-void *ASIOFuture(long selector, void *params);\r
-ASIOError ASIOOutputReady(void);\r
-\r
-*/\r
-\r
-//---------------------------------------------------------------------------------------------------\r
-//---------------------------------------------------------------------------------------------------\r
-\r
-#ifndef __ASIO_H\r
-#define __ASIO_H\r
-\r
-// force 4 byte alignment\r
-#if defined(_MSC_VER) && !defined(__MWERKS__) \r
-#pragma pack(push,4)\r
-#elif PRAGMA_ALIGN_SUPPORTED\r
-#pragma options align = native\r
-#endif\r
-\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-// Type definitions\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-\r
-// number of samples data type is 64 bit integer\r
-#if NATIVE_INT64\r
-       typedef long long int ASIOSamples;\r
-#else\r
-       typedef struct ASIOSamples {\r
-               unsigned long hi;\r
-               unsigned long lo;\r
-       } ASIOSamples;\r
-#endif\r
-\r
-// Timestamp data type is 64 bit integer,\r
-// Time format is Nanoseconds.\r
-#if NATIVE_INT64\r
-       typedef long long int ASIOTimeStamp ;\r
-#else\r
-       typedef struct ASIOTimeStamp {\r
-               unsigned long hi;\r
-               unsigned long lo;\r
-       } ASIOTimeStamp;\r
-#endif\r
-\r
-// Samplerates are expressed in IEEE 754 64 bit double float,\r
-// native format as host computer\r
-#if IEEE754_64FLOAT\r
-       typedef double ASIOSampleRate;\r
-#else\r
-       typedef struct ASIOSampleRate {\r
-               char ieee[8];\r
-       } ASIOSampleRate;\r
-#endif\r
-\r
-// Boolean values are expressed as long\r
-typedef long ASIOBool;\r
-enum {\r
-       ASIOFalse = 0,\r
-       ASIOTrue = 1\r
-};\r
-\r
-// Sample Types are expressed as long\r
-typedef long ASIOSampleType;\r
-enum {\r
-       ASIOSTInt16MSB   = 0,\r
-       ASIOSTInt24MSB   = 1,           // used for 20 bits as well\r
-       ASIOSTInt32MSB   = 2,\r
-       ASIOSTFloat32MSB = 3,           // IEEE 754 32 bit float\r
-       ASIOSTFloat64MSB = 4,           // IEEE 754 64 bit double float\r
-\r
-       // these are used for 32 bit data buffer, with different alignment of the data inside\r
-       // 32 bit PCI bus systems can be more easily used with these\r
-       ASIOSTInt32MSB16 = 8,           // 32 bit data with 18 bit alignment\r
-       ASIOSTInt32MSB18 = 9,           // 32 bit data with 18 bit alignment\r
-       ASIOSTInt32MSB20 = 10,          // 32 bit data with 20 bit alignment\r
-       ASIOSTInt32MSB24 = 11,          // 32 bit data with 24 bit alignment\r
-       \r
-       ASIOSTInt16LSB   = 16,\r
-       ASIOSTInt24LSB   = 17,          // used for 20 bits as well\r
-       ASIOSTInt32LSB   = 18,\r
-       ASIOSTFloat32LSB = 19,          // IEEE 754 32 bit float, as found on Intel x86 architecture\r
-       ASIOSTFloat64LSB = 20,          // IEEE 754 64 bit double float, as found on Intel x86 architecture\r
-\r
-       // these are used for 32 bit data buffer, with different alignment of the data inside\r
-       // 32 bit PCI bus systems can more easily used with these\r
-       ASIOSTInt32LSB16 = 24,          // 32 bit data with 18 bit alignment\r
-       ASIOSTInt32LSB18 = 25,          // 32 bit data with 18 bit alignment\r
-       ASIOSTInt32LSB20 = 26,          // 32 bit data with 20 bit alignment\r
-       ASIOSTInt32LSB24 = 27           // 32 bit data with 24 bit alignment\r
-};\r
-\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-// Error codes\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-\r
-typedef long ASIOError;\r
-enum {\r
-       ASE_OK = 0,             // This value will be returned whenever the call succeeded\r
-       ASE_SUCCESS = 0x3f4847a0,       // unique success return value for ASIOFuture calls\r
-       ASE_NotPresent = -1000, // hardware input or output is not present or available\r
-       ASE_HWMalfunction,      // hardware is malfunctioning (can be returned by any ASIO function)\r
-       ASE_InvalidParameter,   // input parameter invalid\r
-       ASE_InvalidMode,        // hardware is in a bad mode or used in a bad mode\r
-       ASE_SPNotAdvancing,     // hardware is not running when sample position is inquired\r
-       ASE_NoClock,            // sample clock or rate cannot be determined or is not present\r
-       ASE_NoMemory            // not enough memory for completing the request\r
-};\r
-\r
-//---------------------------------------------------------------------------------------------------\r
-//---------------------------------------------------------------------------------------------------\r
-\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-// Time Info support\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-\r
-typedef struct ASIOTimeCode\r
-{       \r
-       double          speed;                  // speed relation (fraction of nominal speed)\r
-                                               // optional; set to 0. or 1. if not supported\r
-       ASIOSamples     timeCodeSamples;        // time in samples\r
-       unsigned long   flags;                  // some information flags (see below)\r
-       char future[64];\r
-} ASIOTimeCode;\r
-\r
-typedef enum ASIOTimeCodeFlags\r
-{\r
-       kTcValid                = 1,\r
-       kTcRunning              = 1 << 1,\r
-       kTcReverse              = 1 << 2,\r
-       kTcOnspeed              = 1 << 3,\r
-       kTcStill                = 1 << 4,\r
-       \r
-       kTcSpeedValid           = 1 << 8\r
-}  ASIOTimeCodeFlags;\r
-\r
-typedef struct AsioTimeInfo\r
-{\r
-       double          speed;                  // absolute speed (1. = nominal)\r
-       ASIOTimeStamp   systemTime;             // system time related to samplePosition, in nanoseconds\r
-                                               // on mac, must be derived from Microseconds() (not UpTime()!)\r
-                                               // on windows, must be derived from timeGetTime()\r
-       ASIOSamples     samplePosition;\r
-       ASIOSampleRate  sampleRate;             // current rate\r
-       unsigned long flags;                    // (see below)\r
-       char reserved[12];\r
-} AsioTimeInfo;\r
-\r
-typedef enum AsioTimeInfoFlags\r
-{\r
-       kSystemTimeValid        = 1,            // must always be valid\r
-       kSamplePositionValid    = 1 << 1,       // must always be valid\r
-       kSampleRateValid        = 1 << 2,\r
-       kSpeedValid             = 1 << 3,\r
-       \r
-       kSampleRateChanged      = 1 << 4,\r
-       kClockSourceChanged     = 1 << 5\r
-} AsioTimeInfoFlags;\r
-\r
-typedef struct ASIOTime                          // both input/output\r
-{\r
-       long reserved[4];                       // must be 0\r
-       struct AsioTimeInfo     timeInfo;       // required\r
-       struct ASIOTimeCode     timeCode;       // optional, evaluated if (timeCode.flags & kTcValid)\r
-} ASIOTime;\r
-\r
-/*\r
-\r
-using time info:\r
-it is recommended to use the new method with time info even if the asio\r
-device does not support timecode; continuous calls to ASIOGetSamplePosition\r
-and ASIOGetSampleRate are avoided, and there is a more defined relationship\r
-between callback time and the time info.\r
-\r
-see the example below.\r
-to initiate time info mode, after you have received the callbacks pointer in\r
-ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo\r
-as the argument. if this returns 1, host has accepted time info mode.\r
-now host expects the new callback bufferSwitchTimeInfo to be used instead\r
-of the old bufferSwitch method. the ASIOTime structure is assumed to be valid\r
-and accessible until the callback returns.\r
-\r
-using time code:\r
-if the device supports reading time code, it will call host's asioMessage callback\r
-with kAsioSupportsTimeCode as the selector. it may then fill the according\r
-fields and set the kTcValid flag.\r
-host will call the future method with the kAsioEnableTimeCodeRead selector when\r
-it wants to enable or disable tc reading by the device. you should also support\r
-the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example).\r
-\r
-note:\r
-the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions.\r
-as a matter of convention, the relationship between the sample\r
-position counter and the time code at buffer switch time is\r
-(ignoring offset between tc and sample pos when tc is running):\r
-\r
-on input:      sample 0 -> input  buffer sample 0 -> time code 0\r
-on output:     sample 0 -> output buffer sample 0 -> time code 0\r
-\r
-this means that for 'real' calculations, one has to take into account\r
-the according latencies.\r
-\r
-example:\r
-\r
-ASIOTime asioTime;\r
-\r
-in createBuffers()\r
-{\r
-       memset(&asioTime, 0, sizeof(ASIOTime));\r
-       AsioTimeInfo* ti = &asioTime.timeInfo;\r
-       ti->sampleRate = theSampleRate;\r
-       ASIOTimeCode* tc = &asioTime.timeCode;\r
-       tc->speed = 1.;\r
-       timeInfoMode = false;\r
-       canTimeCode = false;\r
-       if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1)\r
-       {\r
-               timeInfoMode = true;\r
-#if kCanTimeCode\r
-               if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1)\r
-                       canTimeCode = true;\r
-#endif\r
-       }\r
-}\r
-\r
-void switchBuffers(long doubleBufferIndex, bool processNow)\r
-{\r
-       if(timeInfoMode)\r
-       {\r
-               AsioTimeInfo* ti = &asioTime.timeInfo;\r
-               ti->flags =     kSystemTimeValid | kSamplePositionValid | kSampleRateValid;\r
-               ti->systemTime = theNanoSeconds;\r
-               ti->samplePosition = theSamplePosition;\r
-               if(ti->sampleRate != theSampleRate)\r
-                       ti->flags |= kSampleRateChanged;\r
-               ti->sampleRate = theSampleRate;\r
-\r
-#if kCanTimeCode\r
-               if(canTimeCode && timeCodeEnabled)\r
-               {\r
-                       ASIOTimeCode* tc = &asioTime.timeCode;\r
-                       tc->timeCodeSamples = tcSamples;                                                // tc in samples\r
-                       tc->flags = kTcValid | kTcRunning | kTcOnspeed;                 // if so...\r
-               }\r
-               ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);\r
-#else\r
-               callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse);\r
-#endif\r
-       }\r
-       else\r
-               callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse);\r
-}\r
-\r
-ASIOError ASIOFuture(long selector, void *params)\r
-{\r
-       switch(selector)\r
-       {\r
-               case kAsioEnableTimeCodeRead:\r
-                       timeCodeEnabled = true;\r
-                       return ASE_SUCCESS;\r
-               case kAsioDisableTimeCodeRead:\r
-                       timeCodeEnabled = false;\r
-                       return ASE_SUCCESS;\r
-               case kAsioCanTimeInfo:\r
-                       return ASE_SUCCESS;\r
-               #if kCanTimeCode\r
-               case kAsioCanTimeCode:\r
-                       return ASE_SUCCESS;\r
-               #endif\r
-       }\r
-       return ASE_NotPresent;\r
-};\r
-\r
-*/\r
-\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-// application's audio stream handler callbacks\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-\r
-typedef struct ASIOCallbacks\r
-{\r
-       void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess);\r
-               // bufferSwitch indicates that both input and output are to be processed.\r
-               // the current buffer half index (0 for A, 1 for B) determines\r
-               // - the output buffer that the host should start to fill. the other buffer\r
-               //   will be passed to output hardware regardless of whether it got filled\r
-               //   in time or not.\r
-               // - the input buffer that is now filled with incoming data. Note that\r
-               //   because of the synchronicity of i/o, the input always has at\r
-               //   least one buffer latency in relation to the output.\r
-               // directProcess suggests to the host whether it should immedeately\r
-               // start processing (directProcess == ASIOTrue), or whether its process\r
-               // should be deferred because the call comes from a very low level\r
-               // (for instance, a high level priority interrupt), and direct processing\r
-               // would cause timing instabilities for the rest of the system. If in doubt,\r
-               // directProcess should be set to ASIOFalse.\r
-               // Note: bufferSwitch may be called at interrupt time for highest efficiency.\r
-\r
-       void (*sampleRateDidChange) (ASIOSampleRate sRate);\r
-               // gets called when the AudioStreamIO detects a sample rate change\r
-               // If sample rate is unknown, 0 is passed (for instance, clock loss\r
-               // when externally synchronized).\r
-\r
-       long (*asioMessage) (long selector, long value, void* message, double* opt);\r
-               // generic callback for various purposes, see selectors below.\r
-               // note this is only present if the asio version is 2 or higher\r
-\r
-       ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess);\r
-               // new callback with time info. makes ASIOGetSamplePosition() and various\r
-               // calls to ASIOGetSampleRate obsolete,\r
-               // and allows for timecode sync etc. to be preferred; will be used if\r
-               // the driver calls asioMessage with selector kAsioSupportsTimeInfo.\r
-} ASIOCallbacks;\r
-\r
-// asioMessage selectors\r
-enum\r
-{\r
-       kAsioSelectorSupported = 1,     // selector in <value>, returns 1L if supported,\r
-                                                               // 0 otherwise\r
-    kAsioEngineVersion,                        // returns engine (host) asio implementation version,\r
-                                                               // 2 or higher\r
-       kAsioResetRequest,                      // request driver reset. if accepted, this\r
-                                                               // will close the driver (ASIO_Exit() ) and\r
-                                                               // re-open it again (ASIO_Init() etc). some\r
-                                                               // drivers need to reconfigure for instance\r
-                                                               // when the sample rate changes, or some basic\r
-                                                               // changes have been made in ASIO_ControlPanel().\r
-                                                               // returns 1L; note the request is merely passed\r
-                                                               // to the application, there is no way to determine\r
-                                                               // if it gets accepted at this time (but it usually\r
-                                                               // will be).\r
-       kAsioBufferSizeChange,          // not yet supported, will currently always return 0L.\r
-                                                               // for now, use kAsioResetRequest instead.\r
-                                                               // once implemented, the new buffer size is expected\r
-                                                               // in <value>, and on success returns 1L\r
-       kAsioResyncRequest,                     // the driver went out of sync, such that\r
-                                                               // the timestamp is no longer valid. this\r
-                                                               // is a request to re-start the engine and\r
-                                                               // slave devices (sequencer). returns 1 for ok,\r
-                                                               // 0 if not supported.\r
-       kAsioLatenciesChanged,          // the drivers latencies have changed. The engine\r
-                                                               // will refetch the latencies.\r
-       kAsioSupportsTimeInfo,          // if host returns true here, it will expect the\r
-                                                               // callback bufferSwitchTimeInfo to be called instead\r
-                                                               // of bufferSwitch\r
-       kAsioSupportsTimeCode,          // supports time code reading/writing\r
-\r
-       kAsioSupportsInputMonitor,      // supports input monitoring\r
-\r
-       kAsioNumMessageSelectors\r
-};\r
-\r
-//---------------------------------------------------------------------------------------------------\r
-//---------------------------------------------------------------------------------------------------\r
-\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-// (De-)Construction\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-\r
-typedef struct ASIODriverInfo\r
-{\r
-       long asioVersion;               // currently, 2\r
-       long driverVersion;             // driver specific\r
-       char name[32];\r
-       char errorMessage[124];\r
-       void *sysRef;                   // on input: system reference\r
-                                                       // (Windows: application main window handle, Mac & SGI: 0)\r
-} ASIODriverInfo;\r
-\r
-ASIOError ASIOInit(ASIODriverInfo *info);\r
-/* Purpose:\r
-         Initialize the AudioStreamIO.\r
-       Parameter:\r
-         info: pointer to an ASIODriver structure:\r
-           - asioVersion:\r
-                       - on input, the host version. *** Note *** this is 0 for earlier asio\r
-                       implementations, and the asioMessage callback is implemeted\r
-                       only if asioVersion is 2 or greater. sorry but due to a design fault\r
-                       the driver doesn't have access to the host version in ASIOInit :-(\r
-                       added selector for host (engine) version in the asioMessage callback\r
-                       so we're ok from now on.\r
-                       - on return, asio implementation version.\r
-                         older versions are 1\r
-                         if you support this version (namely, ASIO_outputReady() )\r
-                         this should be 2 or higher. also see the note in\r
-                         ASIO_getTimeStamp() !\r
-           - version: on return, the driver version (format is driver specific)\r
-           - name: on return, a null-terminated string containing the driver's name\r
-               - error message: on return, should contain a user message describing\r
-                 the type of error that occured during ASIOInit(), if any.\r
-               - sysRef: platform specific\r
-       Returns:\r
-         If neither input nor output is present ASE_NotPresent\r
-         will be returned.\r
-         ASE_NoMemory, ASE_HWMalfunction are other possible error conditions\r
-*/\r
-\r
-ASIOError ASIOExit(void);\r
-/* Purpose:\r
-         Terminates the AudioStreamIO.\r
-       Parameter:\r
-         None.\r
-       Returns:\r
-         If neither input nor output is present ASE_NotPresent\r
-         will be returned.\r
-       Notes: this implies ASIOStop() and ASIODisposeBuffers(),\r
-         meaning that no host callbacks must be accessed after ASIOExit().\r
-*/\r
-\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-// Start/Stop\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-\r
-ASIOError ASIOStart(void);\r
-/* Purpose:\r
-         Start input and output processing synchronously.\r
-         This will\r
-         - reset the sample counter to zero\r
-         - start the hardware (both input and output)\r
-           The first call to the hosts' bufferSwitch(index == 0) then tells\r
-           the host to read from input buffer A (index 0), and start\r
-           processing to output buffer A while output buffer B (which\r
-           has been filled by the host prior to calling ASIOStart())\r
-           is possibly sounding (see also ASIOGetLatencies()) \r
-       Parameter:\r
-         None.\r
-       Returns:\r
-         If neither input nor output is present, ASE_NotPresent\r
-         will be returned.\r
-         If the hardware fails to start, ASE_HWMalfunction will be returned.\r
-       Notes:\r
-         There is no restriction on the time that ASIOStart() takes\r
-         to perform (that is, it is not considered a realtime trigger).\r
-*/\r
-\r
-ASIOError ASIOStop(void);\r
-/* Purpose:\r
-         Stops input and output processing altogether.\r
-       Parameter:\r
-         None.\r
-       Returns:\r
-         If neither input nor output is present ASE_NotPresent\r
-         will be returned.\r
-       Notes:\r
-         On return from ASIOStop(), the driver must in no\r
-         case call the hosts' bufferSwitch() routine.\r
-*/\r
-\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-// Inquiry methods and sample rate\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-\r
-ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels);\r
-/* Purpose:\r
-         Returns number of individual input/output channels.\r
-       Parameter:\r
-         numInputChannels will hold the number of available input channels\r
-         numOutputChannels will hold the number of available output channels\r
-       Returns:\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-         If only inputs, or only outputs are available, the according\r
-         other parameter will be zero, and ASE_OK is returned.\r
-*/\r
-\r
-ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency);\r
-/* Purpose:\r
-         Returns the input and output latencies. This includes\r
-         device specific delays, like FIFOs etc.\r
-       Parameter:\r
-         inputLatency will hold the 'age' of the first sample frame\r
-         in the input buffer when the hosts reads it in bufferSwitch()\r
-         (this is theoretical, meaning it does not include the overhead\r
-         and delay between the actual physical switch, and the time\r
-         when bufferSitch() enters).\r
-         This will usually be the size of one block in sample frames, plus\r
-         device specific latencies.\r
-\r
-         outputLatency will specify the time between the buffer switch,\r
-         and the time when the next play buffer will start to sound.\r
-         The next play buffer is defined as the one the host starts\r
-         processing after (or at) bufferSwitch(), indicated by the\r
-         index parameter (0 for buffer A, 1 for buffer B).\r
-         It will usually be either one block, if the host writes directly\r
-         to a dma buffer, or two or more blocks if the buffer is 'latched' by\r
-         the driver. As an example, on ASIOStart(), the host will have filled\r
-         the play buffer at index 1 already; when it gets the callback (with\r
-         the parameter index == 0), this tells it to read from the input\r
-         buffer 0, and start to fill the play buffer 0 (assuming that now\r
-         play buffer 1 is already sounding). In this case, the output\r
-         latency is one block. If the driver decides to copy buffer 1\r
-         at that time, and pass it to the hardware at the next slot (which\r
-         is most commonly done, but should be avoided), the output latency\r
-         becomes two blocks instead, resulting in a total i/o latency of at least\r
-         3 blocks. As memory access is the main bottleneck in native dsp processing,\r
-         and to acheive less latency, it is highly recommended to try to avoid\r
-         copying (this is also why the driver is the owner of the buffers). To\r
-         summarize, the minimum i/o latency can be acheived if the input buffer\r
-         is processed by the host into the output buffer which will physically\r
-         start to sound on the next time slice. Also note that the host expects\r
-         the bufferSwitch() callback to be accessed for each time slice in order\r
-         to retain sync, possibly recursively; if it fails to process a block in\r
-         time, it will suspend its operation for some time in order to recover.\r
-       Returns:\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-*/\r
-\r
-ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);\r
-/* Purpose:\r
-         Returns min, max, and preferred buffer sizes for input/output\r
-       Parameter:\r
-         minSize will hold the minimum buffer size\r
-         maxSize will hold the maxium possible buffer size\r
-         preferredSize will hold the preferred buffer size (a size which\r
-         best fits performance and hardware requirements)\r
-         granularity will hold the granularity at which buffer sizes\r
-         may differ. Usually, the buffer size will be a power of 2;\r
-         in this case, granularity will hold -1 on return, signalling\r
-         possible buffer sizes starting from minSize, increased in\r
-         powers of 2 up to maxSize.\r
-       Returns:\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-       Notes:\r
-         When minimum and maximum buffer size are equal,\r
-         the preferred buffer size has to be the same value as well; granularity\r
-         should be 0 in this case.\r
-*/\r
-\r
-ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate);\r
-/* Purpose:\r
-         Inquires the hardware for the available sample rates.\r
-       Parameter:\r
-         sampleRate is the rate in question.\r
-       Returns:\r
-         If the inquired sample rate is not supported, ASE_NoClock will be returned.\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-*/\r
-ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate);\r
-/* Purpose:\r
-         Get the current sample Rate.\r
-       Parameter:\r
-         currentRate will hold the current sample rate on return.\r
-       Returns:\r
-         If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned.\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-       Notes:\r
-*/\r
-\r
-ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate);\r
-/* Purpose:\r
-         Set the hardware to the requested sample Rate. If sampleRate == 0,\r
-         enable external sync.\r
-       Parameter:\r
-         sampleRate: on input, the requested rate\r
-       Returns:\r
-         If sampleRate is unknown ASE_NoClock will be returned.\r
-         If the current clock is external, and sampleRate is != 0,\r
-         ASE_InvalidMode will be returned\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-       Notes:\r
-*/\r
-\r
-typedef struct ASIOClockSource\r
-{\r
-       long index;                                     // as used for ASIOSetClockSource()\r
-       long associatedChannel;         // for instance, S/PDIF or AES/EBU\r
-       long associatedGroup;           // see channel groups (ASIOGetChannelInfo())\r
-       ASIOBool isCurrentSource;       // ASIOTrue if this is the current clock source\r
-       char name[32];                          // for user selection\r
-} ASIOClockSource;\r
-\r
-ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources);\r
-/* Purpose:\r
-         Get the available external audio clock sources\r
-       Parameter:\r
-         clocks points to an array of ASIOClockSource structures:\r
-               - index: this is used to identify the clock source\r
-                 when ASIOSetClockSource() is accessed, should be\r
-                 an index counting from zero\r
-               - associatedInputChannel: the first channel of an associated\r
-                 input group, if any.\r
-               - associatedGroup: the group index of that channel.\r
-                 groups of channels are defined to seperate for\r
-                 instance analog, S/PDIF, AES/EBU, ADAT connectors etc,\r
-                 when present simultaniously. Note that associated channel\r
-                 is enumerated according to numInputs/numOutputs, means it\r
-                 is independant from a group (see also ASIOGetChannelInfo())\r
-                 inputs are associated to a clock if the physical connection\r
-                 transfers both data and clock (like S/PDIF, AES/EBU, or\r
-                 ADAT inputs). if there is no input channel associated with\r
-                 the clock source (like Word Clock, or internal oscillator), both\r
-                 associatedChannel and associatedGroup should be set to -1.\r
-               - isCurrentSource: on exit, ASIOTrue if this is the current clock\r
-                 source, ASIOFalse else\r
-               - name: a null-terminated string for user selection of the available sources.\r
-         numSources:\r
-             on input: the number of allocated array members\r
-             on output: the number of available clock sources, at least\r
-             1 (internal clock generator).\r
-       Returns:\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-       Notes:\r
-*/\r
-\r
-ASIOError ASIOSetClockSource(long index);\r
-/* Purpose:\r
-         Set the audio clock source\r
-       Parameter:\r
-         index as obtained from an inquiry to ASIOGetClockSources()\r
-       Returns:\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-         If the clock can not be selected because an input channel which\r
-         carries the current clock source is active, ASE_InvalidMode\r
-         *may* be returned (this depends on the properties of the driver\r
-         and/or hardware).\r
-       Notes:\r
-         Should *not* return ASE_NoClock if there is no clock signal present\r
-         at the selected source; this will be inquired via ASIOGetSampleRate().\r
-         It should call the host callback procedure sampleRateHasChanged(),\r
-         if the switch causes a sample rate change, or if no external clock\r
-         is present at the selected source.\r
-*/\r
-\r
-ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
-/* Purpose:\r
-         Inquires the sample position/time stamp pair.\r
-       Parameter:\r
-         sPos will hold the sample position on return. The sample\r
-         position is reset to zero when ASIOStart() gets called.\r
-         tStamp will hold the system time when the sample position\r
-         was latched.\r
-       Returns:\r
-         If no input/output is present, ASE_NotPresent will be returned.\r
-         If there is no clock, ASE_SPNotAdvancing will be returned.\r
-       Notes:\r
-\r
-         in order to be able to synchronise properly,\r
-         the sample position / time stamp pair must refer to the current block,\r
-         that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch()\r
-         callback and expect the time for the current block. thus, when requested\r
-         in the very first bufferSwitch after ASIO_Start(), the sample position\r
-         should be zero, and the time stamp should refer to the very time where\r
-         the stream was started. it also means that the sample position must be\r
-         block aligned. the driver must ensure proper interpolation if the system\r
-         time can not be determined for the block position. the driver is responsible\r
-         for precise time stamps as it usually has most direct access to lower\r
-         level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies()\r
-         are essential for precise media synchronization!\r
-*/\r
-\r
-typedef struct ASIOChannelInfo\r
-{\r
-       long channel;                   // on input, channel index\r
-       ASIOBool isInput;               // on input\r
-       ASIOBool isActive;              // on exit\r
-       long channelGroup;              // dto\r
-       ASIOSampleType type;    // dto\r
-       char name[32];                  // dto\r
-} ASIOChannelInfo;\r
-\r
-ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info);\r
-/* Purpose:\r
-         retreive information about the nature of a channel\r
-       Parameter:\r
-         info: pointer to a ASIOChannelInfo structure with\r
-               - channel: on input, the channel index of the channel in question.\r
-               - isInput: on input, ASIOTrue if info for an input channel is\r
-                 requested, else output\r
-               - channelGroup: on return, the channel group that the channel\r
-                 belongs to. For drivers which support different types of\r
-                 channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces,\r
-                 there should be a reasonable grouping of these types. Groups\r
-                 are always independant form a channel index, that is, a channel\r
-                 index always counts from 0 to numInputs/numOutputs regardless\r
-                 of the group it may belong to.\r
-                 There will always be at least one group (group 0). Please\r
-                 also note that by default, the host may decide to activate\r
-                 channels 0 and 1; thus, these should belong to the most\r
-                 useful type (analog i/o, if present).\r
-               - type: on return, contains the sample type of the channel\r
-               - isActive: on return, ASIOTrue if channel is active as it was\r
-                 installed by ASIOCreateBuffers(), ASIOFalse else\r
-               - name:  describing the type of channel in question. Used to allow\r
-                 for user selection, and enabling of specific channels. examples:\r
-             "Analog In", "SPDIF Out" etc\r
-       Returns:\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-       Notes:\r
-         If possible, the string should be organised such that the first\r
-         characters are most significantly describing the nature of the\r
-         port, to allow for identification even if the view showing the\r
-         port name is too small to display more than 8 characters, for\r
-         instance.\r
-*/\r
-\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-// Buffer preparation\r
-//- - - - - - - - - - - - - - - - - - - - - - - - -\r
-\r
-typedef struct ASIOBufferInfo\r
-{\r
-       ASIOBool isInput;                       // on input:  ASIOTrue: input, else output\r
-       long channelNum;                        // on input:  channel index\r
-       void *buffers[2];                       // on output: double buffer addresses\r
-} ASIOBufferInfo;\r
-\r
-ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
-       long bufferSize, ASIOCallbacks *callbacks);\r
-\r
-/* Purpose:\r
-         Allocates input/output buffers for all input and output channels to be activated.\r
-       Parameter:\r
-         bufferInfos is a pointer to an array of ASIOBufferInfo structures:\r
-           - isInput: on input, ASIOTrue if the buffer is to be allocated\r
-             for an input, output buffer else\r
-           - channelNum: on input, the index of the channel in question\r
-             (counting from 0)\r
-           - buffers: on exit, 2 pointers to the halves of the channels' double-buffer.\r
-             the size of the buffer(s) of course depend on both the ASIOSampleType\r
-             as obtained from ASIOGetChannelInfo(), and bufferSize\r
-         numChannels is the sum of all input and output channels to be created;\r
-         thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo\r
-         structures.\r
-         bufferSize selects one of the possible buffer sizes as obtained from\r
-         ASIOGetBufferSizes().\r
-         callbacks is a pointer to an ASIOCallbacks structure.\r
-       Returns:\r
-         If not enough memory is available ASE_NoMemory will be returned.\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-         If bufferSize is not supported, or one or more of the bufferInfos elements\r
-         contain invalid settings, ASE_InvalidMode will be returned.\r
-       Notes:\r
-         If individual channel selection is not possible but requested,\r
-         the driver has to handle this. namely, bufferSwitch() will only\r
-         have filled buffers of enabled outputs. If possible, processing\r
-         and buss activities overhead should be avoided for channels which\r
-         were not enabled here.\r
-*/\r
-\r
-ASIOError ASIODisposeBuffers(void);\r
-/* Purpose:\r
-         Releases all buffers for the device.\r
-       Parameter:\r
-         None.\r
-       Returns:\r
-         If no buffer were ever prepared, ASE_InvalidMode will be returned.\r
-         If no input/output is present ASE_NotPresent will be returned.\r
-       Notes:\r
-         This implies ASIOStop().\r
-*/\r
-\r
-ASIOError ASIOControlPanel(void);\r
-/* Purpose:\r
-         request the driver to start a control panel component\r
-         for device specific user settings. This will not be\r
-         accessed on some platforms (where the component is accessed\r
-         instead).\r
-       Parameter:\r
-         None.\r
-       Returns:\r
-         If no panel is available ASE_NotPresent will be returned.\r
-         Actually, the return code is ignored.\r
-       Notes:\r
-         if the user applied settings which require a re-configuration\r
-         of parts or all of the enigine and/or driver (such as a change of\r
-         the block size), the asioMessage callback can be used (see\r
-         ASIO_Callbacks).\r
-*/\r
-\r
-ASIOError ASIOFuture(long selector, void *params);\r
-/* Purpose:\r
-         various\r
-       Parameter:\r
-         selector: operation Code as to be defined. zero is reserved for\r
-         testing purposes.\r
-         params: depends on the selector; usually pointer to a structure\r
-         for passing and retreiving any type and amount of parameters.\r
-       Returns:\r
-         the return value is also selector dependant. if the selector\r
-         is unknown, ASE_InvalidParameter should be returned to prevent\r
-         further calls with this selector. on success, ASE_SUCCESS\r
-         must be returned (note: ASE_OK is *not* sufficient!)\r
-       Notes:\r
-         see selectors defined below.    \r
-*/\r
-\r
-enum\r
-{\r
-       kAsioEnableTimeCodeRead = 1,    // no arguments\r
-       kAsioDisableTimeCodeRead,               // no arguments\r
-       kAsioSetInputMonitor,                   // ASIOInputMonitor* in params\r
-       kAsioTransport,                                 // ASIOTransportParameters* in params\r
-       kAsioSetInputGain,                              // ASIOChannelControls* in params, apply gain\r
-       kAsioGetInputMeter,                             // ASIOChannelControls* in params, fill meter\r
-       kAsioSetOutputGain,                             // ASIOChannelControls* in params, apply gain\r
-       kAsioGetOutputMeter,                    // ASIOChannelControls* in params, fill meter\r
-       kAsioCanInputMonitor,                   // no arguments for kAsioCanXXX selectors\r
-       kAsioCanTimeInfo,\r
-       kAsioCanTimeCode,\r
-       kAsioCanTransport,\r
-       kAsioCanInputGain,\r
-       kAsioCanInputMeter,\r
-       kAsioCanOutputGain,\r
-       kAsioCanOutputMeter\r
-};\r
-\r
-typedef struct ASIOInputMonitor\r
-{\r
-       long input;             // this input was set to monitor (or off), -1: all\r
-       long output;    // suggested output for monitoring the input (if so)\r
-       long gain;              // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB)\r
-       ASIOBool state; // ASIOTrue => on, ASIOFalse => off\r
-       long pan;               // suggested pan, 0 => all left, 0x7fffffff => right\r
-} ASIOInputMonitor;\r
-\r
-typedef struct ASIOChannelControls\r
-{\r
-       long channel;                   // on input, channel index\r
-       ASIOBool isInput;               // on input\r
-       long gain;                              // on input,  ranges 0 thru 0x7fffffff\r
-       long meter;                             // on return, ranges 0 thru 0x7fffffff\r
-       char future[32];\r
-} ASIOChannelControls;\r
-\r
-typedef struct ASIOTransportParameters\r
-{\r
-       long command;           // see enum below\r
-       ASIOSamples samplePosition;\r
-       long track;\r
-       long trackSwitches[16];         // 512 tracks on/off\r
-       char future[64];\r
-} ASIOTransportParameters;\r
-\r
-enum\r
-{\r
-       kTransStart = 1,\r
-       kTransStop,\r
-       kTransLocate,           // to samplePosition\r
-       kTransPunchIn,\r
-       kTransPunchOut,\r
-       kTransArmOn,            // track\r
-       kTransArmOff,           // track\r
-       kTransMonitorOn,        // track\r
-       kTransMonitorOff,       // track\r
-       kTransArm,                      // trackSwitches\r
-       kTransMonitor           // trackSwitches\r
-};\r
-\r
-ASIOError ASIOOutputReady(void);\r
-/* Purpose:\r
-         this tells the driver that the host has completed processing\r
-         the output buffers. if the data format required by the hardware\r
-         differs from the supported asio formats, but the hardware\r
-         buffers are DMA buffers, the driver will have to convert\r
-         the audio stream data; as the bufferSwitch callback is\r
-         usually issued at dma block switch time, the driver will\r
-         have to convert the *previous* host buffer, which increases\r
-         the output latency by one block.\r
-         when the host finds out that ASIOOutputReady() returns\r
-         true, it will issue this call whenever it completed\r
-         output processing. then the driver can convert the\r
-         host data directly to the dma buffer to be played next,\r
-         reducing output latency by one block.\r
-         another way to look at it is, that the buffer switch is called\r
-         in order to pass the *input* stream to the host, so that it can\r
-         process the input into the output, and the output stream is passed\r
-         to the driver when the host has completed its process.\r
-       Parameter:\r
-               None\r
-       Returns:\r
-         only if the above mentioned scenario is given, and a reduction\r
-         of output latency can be acheived by this mechanism, should\r
-         ASE_OK be returned. otherwise (and usually), ASE_NotPresent\r
-         should be returned in order to prevent further calls to this\r
-         function. note that the host may want to determine if it is\r
-         to use this when the system is not yet fully initialized, so\r
-         ASE_OK should always be returned if the mechanism makes sense.          \r
-       Notes:\r
-         please remeber to adjust ASIOGetLatencies() according to\r
-         whether ASIOOutputReady() was ever called or not, if your\r
-         driver supports this scenario.\r
-         also note that the engine may fail to call ASIO_OutputReady()\r
-         in time in overload cases. as already mentioned, bufferSwitch\r
-      should be called for every block regardless of whether a block\r
-      could be processed in time.\r
-*/\r
-\r
-// restore old alignment\r
-#if defined(_MSC_VER) && !defined(__MWERKS__) \r
-#pragma pack(pop)\r
-#elif PRAGMA_ALIGN_SUPPORTED\r
-#pragma options align = reset\r
-#endif\r
-\r
-#endif\r
-\r
diff --git a/tests/asio/asiodrivers.cpp b/tests/asio/asiodrivers.cpp
deleted file mode 100644 (file)
index 5f56454..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-#include <string.h>\r
-#include "asiodrivers.h"\r
-\r
-AsioDrivers* asioDrivers = 0;\r
-\r
-bool loadAsioDriver(char *name);\r
-\r
-bool loadAsioDriver(char *name)\r
-{\r
-       if(!asioDrivers)\r
-               asioDrivers = new AsioDrivers();\r
-       if(asioDrivers)\r
-               return asioDrivers->loadDriver(name);\r
-       return false;\r
-}\r
-\r
-//------------------------------------------------------------------------------------\r
-\r
-#if MAC\r
-\r
-bool resolveASIO(unsigned long aconnID);\r
-\r
-AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio')\r
-{\r
-       connID = -1;\r
-       curIndex = -1;\r
-}\r
-\r
-AsioDrivers::~AsioDrivers()\r
-{\r
-       removeCurrentDriver();\r
-}\r
-\r
-bool AsioDrivers::getCurrentDriverName(char *name)\r
-{\r
-       if(curIndex >= 0)\r
-               return getName(curIndex, name);\r
-       return false;\r
-}\r
-\r
-long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
-{\r
-       for(long i = 0; i < getNumFragments() && i < maxDrivers; i++)\r
-               getName(i, names[i]);\r
-       return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers;\r
-}\r
-\r
-bool AsioDrivers::loadDriver(char *name)\r
-{\r
-       char dname[64];\r
-       unsigned long newID;\r
-\r
-       for(long i = 0; i < getNumFragments(); i++)\r
-       {\r
-               if(getName(i, dname) && !strcmp(name, dname))\r
-               {\r
-                       if(newInstance(i, &newID))\r
-                       {\r
-                               if(resolveASIO(newID))\r
-                               {\r
-                                       if(connID != -1)\r
-                                               removeInstance(curIndex, connID);\r
-                                       curIndex = i;\r
-                                       connID = newID;\r
-                                       return true;\r
-                               }\r
-                       }\r
-                       break;\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-void AsioDrivers::removeCurrentDriver()\r
-{\r
-       if(connID != -1)\r
-               removeInstance(curIndex, connID);\r
-       connID = -1;\r
-       curIndex = -1;\r
-}\r
-\r
-//------------------------------------------------------------------------------------\r
-\r
-#elif WINDOWS\r
-\r
-#include "iasiodrv.h"\r
-\r
-extern IASIO* theAsioDriver;\r
-\r
-AsioDrivers::AsioDrivers() : AsioDriverList()\r
-{\r
-       curIndex = -1;\r
-}\r
-\r
-AsioDrivers::~AsioDrivers()\r
-{\r
-}\r
-\r
-bool AsioDrivers::getCurrentDriverName(char *name)\r
-{\r
-       if(curIndex >= 0)\r
-               return asioGetDriverName(curIndex, name, 32) == 0 ? true : false;\r
-       name[0] = 0;\r
-       return false;\r
-}\r
-\r
-long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
-{\r
-       for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++)\r
-               asioGetDriverName(i, names[i], 32);\r
-       return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers;\r
-}\r
-\r
-bool AsioDrivers::loadDriver(char *name)\r
-{\r
-       char dname[64];\r
-       char curName[64];\r
-\r
-       for(long i = 0; i < asioGetNumDev(); i++)\r
-       {\r
-               if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname))\r
-               {\r
-                       curName[0] = 0;\r
-                       getCurrentDriverName(curName);  // in case we fail...\r
-                       removeCurrentDriver();\r
-\r
-                       if(!asioOpenDriver(i, (void **)&theAsioDriver))\r
-                       {\r
-                               curIndex = i;\r
-                               return true;\r
-                       }\r
-                       else\r
-                       {\r
-                               theAsioDriver = 0;\r
-                               if(curName[0] && strcmp(dname, curName))\r
-                                       loadDriver(curName);    // try restore\r
-                       }\r
-                       break;\r
-               }\r
-       }\r
-       return false;\r
-}\r
-\r
-void AsioDrivers::removeCurrentDriver()\r
-{\r
-       if(curIndex != -1)\r
-               asioCloseDriver(curIndex);\r
-       curIndex = -1;\r
-}\r
-\r
-#elif SGI || BEOS\r
-\r
-#include "asiolist.h"\r
-\r
-AsioDrivers::AsioDrivers() \r
-       : AsioDriverList()\r
-{\r
-       curIndex = -1;\r
-}\r
-\r
-AsioDrivers::~AsioDrivers()\r
-{\r
-}\r
-\r
-bool AsioDrivers::getCurrentDriverName(char *name)\r
-{\r
-       return false;\r
-}\r
-\r
-long AsioDrivers::getDriverNames(char **names, long maxDrivers)\r
-{\r
-       return 0;\r
-}\r
-\r
-bool AsioDrivers::loadDriver(char *name)\r
-{\r
-       return false;\r
-}\r
-\r
-void AsioDrivers::removeCurrentDriver()\r
-{\r
-}\r
-\r
-#else\r
-#error implement me\r
-#endif\r
diff --git a/tests/asio/asiodrivers.h b/tests/asio/asiodrivers.h
deleted file mode 100644 (file)
index 2ddf7ad..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __AsioDrivers__\r
-#define __AsioDrivers__\r
-\r
-#include "ginclude.h"\r
-\r
-#if MAC\r
-#include "CodeFragments.hpp"\r
-\r
-class AsioDrivers : public CodeFragments\r
-\r
-#elif WINDOWS\r
-#include <windows.h>\r
-#include "asiolist.h"\r
-\r
-class AsioDrivers : public AsioDriverList\r
-\r
-#elif SGI || BEOS\r
-#include "asiolist.h"\r
-\r
-class AsioDrivers : public AsioDriverList\r
-\r
-#else\r
-#error implement me\r
-#endif\r
-\r
-{\r
-public:\r
-       AsioDrivers();\r
-       ~AsioDrivers();\r
-       \r
-       bool getCurrentDriverName(char *name);\r
-       long getDriverNames(char **names, long maxDrivers);\r
-       bool loadDriver(char *name);\r
-       void removeCurrentDriver();\r
-       long getCurrentDriverIndex() {return curIndex;}\r
-protected:\r
-       unsigned long connID;\r
-       long curIndex;\r
-};\r
-\r
-#endif\r
diff --git a/tests/asio/asiodrvr.h b/tests/asio/asiodrvr.h
deleted file mode 100644 (file)
index 663f75a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*\r
-       Steinberg Audio Stream I/O API\r
-       (c) 1996, Steinberg Soft- und Hardware GmbH\r
-       charlie (May 1996)\r
-\r
-       asiodrvr.h\r
-       c++ superclass to implement asio functionality. from this,\r
-       you can derive whatever required\r
-*/\r
-\r
-#ifndef _asiodrvr_\r
-#define _asiodrvr_\r
-\r
-// cpu and os system we are running on\r
-#include "asiosys.h"\r
-// basic "C" interface\r
-#include "asio.h"\r
-\r
-class AsioDriver;\r
-extern AsioDriver *getDriver();                // for generic constructor \r
-\r
-#if WINDOWS\r
-#include <windows.h>\r
-#include "combase.h"\r
-#include "iasiodrv.h"\r
-class AsioDriver : public IASIO ,public CUnknown\r
-{\r
-public:\r
-       AsioDriver(LPUNKNOWN pUnk, HRESULT *phr);\r
-\r
-       DECLARE_IUNKNOWN\r
-       // Factory method\r
-       static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);\r
-       // IUnknown\r
-       virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject);\r
-\r
-#else\r
-\r
-class AsioDriver\r
-{\r
-public:\r
-       AsioDriver();\r
-#endif\r
-       virtual ~AsioDriver();\r
-\r
-       virtual ASIOBool init(void* sysRef);\r
-       virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero\r
-       virtual long getDriverVersion();\r
-       virtual void getErrorMessage(char *string);     // max 124 bytes incl.\r
-\r
-       virtual ASIOError start();\r
-       virtual ASIOError stop();\r
-\r
-       virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);\r
-       virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);\r
-       virtual ASIOError getBufferSize(long *minSize, long *maxSize,\r
-               long *preferredSize, long *granularity);\r
-\r
-       virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);\r
-       virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);\r
-       virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);\r
-       virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);\r
-       virtual ASIOError setClockSource(long reference);\r
-\r
-       virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);\r
-       virtual ASIOError getChannelInfo(ASIOChannelInfo *info);\r
-\r
-       virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
-               long bufferSize, ASIOCallbacks *callbacks);\r
-       virtual ASIOError disposeBuffers();\r
-\r
-       virtual ASIOError controlPanel();\r
-       virtual ASIOError future(long selector, void *opt);\r
-       virtual ASIOError outputReady();\r
-};\r
-#endif\r
diff --git a/tests/asio/asiolist.cpp b/tests/asio/asiolist.cpp
deleted file mode 100644 (file)
index 5a62f5b..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-#include <windows.h>\r
-#include "iasiodrv.h"\r
-#include "asiolist.h"\r
-\r
-#define ASIODRV_DESC           "description"\r
-#define INPROC_SERVER          "InprocServer32"\r
-#define ASIO_PATH                      "software\\asio"\r
-#define COM_CLSID                      "clsid"\r
-\r
-// ******************************************************************\r
-// Local Functions \r
-// ******************************************************************\r
-static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)\r
-{\r
-       HKEY                    hkEnum,hksub,hkpath;\r
-       char                    databuf[512];\r
-       LONG                    cr,rc = -1;\r
-       DWORD                   datatype,datasize;\r
-       DWORD                   index;\r
-       OFSTRUCT                ofs;\r
-       HFILE                   hfile;\r
-       BOOL                    found = FALSE;\r
-\r
-       CharLowerBuff(clsidstr,strlen(clsidstr));\r
-       if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {\r
-\r
-               index = 0;\r
-               while (cr == ERROR_SUCCESS && !found) {\r
-                       cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512);\r
-                       if (cr == ERROR_SUCCESS) {\r
-                               CharLowerBuff(databuf,strlen(databuf));\r
-                               if (!(strcmp(databuf,clsidstr))) {\r
-                                       if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {\r
-                                               if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {\r
-                                                       datatype = REG_SZ; datasize = (DWORD)dllpathsize;\r
-                                                       cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);\r
-                                                       if (cr == ERROR_SUCCESS) {\r
-                                                               memset(&ofs,0,sizeof(OFSTRUCT));\r
-                                                               ofs.cBytes = sizeof(OFSTRUCT); \r
-                                                               hfile = OpenFile(dllpath,&ofs,OF_EXIST);\r
-                                                               if (hfile) rc = 0; \r
-                                                       }\r
-                                                       RegCloseKey(hkpath);\r
-                                               }\r
-                                               RegCloseKey(hksub);\r
-                                       }\r
-                                       found = TRUE;   // break out \r
-                               }\r
-                       }\r
-               }                               \r
-               RegCloseKey(hkEnum);\r
-       }\r
-       return rc;\r
-}\r
-\r
-\r
-static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)\r
-{\r
-       HKEY    hksub;\r
-       char    databuf[256];\r
-       char    dllpath[MAXPATHLEN];\r
-       WORD    wData[100];\r
-       CLSID   clsid;\r
-       DWORD   datatype,datasize;\r
-       LONG    cr,rc;\r
-\r
-       if (!lpdrv) {\r
-               if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {\r
-\r
-                       datatype = REG_SZ; datasize = 256;\r
-                       cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);\r
-                       if (cr == ERROR_SUCCESS) {\r
-                               rc = findDrvPath (databuf,dllpath,MAXPATHLEN);\r
-                               if (rc == 0) {\r
-                                       lpdrv = new ASIODRVSTRUCT[1];\r
-                                       if (lpdrv) {\r
-                                               memset(lpdrv,0,sizeof(ASIODRVSTRUCT));\r
-                                               lpdrv->drvID = drvID;\r
-                                               MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);\r
-                                               if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {\r
-                                                       memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));\r
-                                               }\r
-\r
-                                               datatype = REG_SZ; datasize = 256;\r
-                                               cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);\r
-                                               if (cr == ERROR_SUCCESS) {\r
-                                                       strcpy(lpdrv->drvname,databuf);\r
-                                               }\r
-                                               else strcpy(lpdrv->drvname,keyname);\r
-                                       }\r
-                               }\r
-                       }\r
-                       RegCloseKey(hksub);\r
-               }\r
-       }       \r
-       else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);\r
-\r
-       return lpdrv;\r
-}\r
-\r
-static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv)\r
-{\r
-       IASIO   *iasio;\r
-\r
-       if (lpdrv != 0) {\r
-               deleteDrvStruct(lpdrv->next);\r
-               if (lpdrv->asiodrv) {\r
-                       iasio = (IASIO *)lpdrv->asiodrv;\r
-                       iasio->Release();\r
-               }\r
-               delete lpdrv;\r
-       }\r
-}\r
-\r
-\r
-static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv)\r
-{\r
-       while (lpdrv) {\r
-               if (lpdrv->drvID == drvID) return lpdrv;\r
-               lpdrv = lpdrv->next;\r
-       }\r
-       return 0;\r
-}\r
-// ******************************************************************\r
-\r
-\r
-// ******************************************************************\r
-//     AsioDriverList\r
-// ******************************************************************\r
-AsioDriverList::AsioDriverList ()\r
-{\r
-       HKEY                    hkEnum = 0;\r
-       char                    keyname[MAXDRVNAMELEN];\r
-       LPASIODRVSTRUCT pdl;\r
-       LONG                    cr;\r
-       DWORD                   index = 0;\r
-       BOOL                    fin = FALSE;\r
-\r
-       numdrv          = 0;\r
-       lpdrvlist       = 0;\r
-\r
-       cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);\r
-       while (cr == ERROR_SUCCESS) {\r
-               if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {\r
-                       lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);\r
-               }\r
-               else fin = TRUE;\r
-       }\r
-       if (hkEnum) RegCloseKey(hkEnum);\r
-\r
-       pdl = lpdrvlist;\r
-       while (pdl) {\r
-               numdrv++;\r
-               pdl = pdl->next;\r
-       }\r
-\r
-       if (numdrv) CoInitialize(0);    // initialize COM\r
-}\r
-\r
-AsioDriverList::~AsioDriverList ()\r
-{\r
-       if (numdrv) {\r
-               deleteDrvStruct(lpdrvlist);\r
-               CoUninitialize();\r
-       }\r
-}\r
-\r
-\r
-LONG AsioDriverList::asioGetNumDev (VOID)\r
-{\r
-       return (LONG)numdrv;\r
-}\r
-\r
-\r
-LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv)\r
-{\r
-       LPASIODRVSTRUCT lpdrv = 0;\r
-       long                    rc;\r
-\r
-       if (!asiodrv) return DRVERR_INVALID_PARAM;\r
-\r
-       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
-               if (!lpdrv->asiodrv) {\r
-                       rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv);\r
-                       if (rc == S_OK) {\r
-                               lpdrv->asiodrv = *asiodrv;\r
-                               return 0;\r
-                       }\r
-                       // else if (rc == REGDB_E_CLASSNOTREG)\r
-                       //      strcpy (info->messageText, "Driver not registered in the Registration Database!");\r
-               }\r
-               else rc = DRVERR_DEVICE_ALREADY_OPEN;\r
-       }\r
-       else rc = DRVERR_DEVICE_NOT_FOUND;\r
-       \r
-       return rc;\r
-}\r
-\r
-\r
-LONG AsioDriverList::asioCloseDriver (int drvID)\r
-{\r
-       LPASIODRVSTRUCT lpdrv = 0;\r
-       IASIO                   *iasio;\r
-\r
-       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
-               if (lpdrv->asiodrv) {\r
-                       iasio = (IASIO *)lpdrv->asiodrv;\r
-                       iasio->Release();\r
-                       lpdrv->asiodrv = 0;\r
-               }\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize)\r
-{      \r
-       LPASIODRVSTRUCT                 lpdrv = 0;\r
-\r
-       if (!drvname) return DRVERR_INVALID_PARAM;\r
-\r
-       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
-               if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) {\r
-                       strcpy(drvname,lpdrv->drvname);\r
-               }\r
-               else {\r
-                       memcpy(drvname,lpdrv->drvname,drvnamesize-4);\r
-                       drvname[drvnamesize-4] = '.';\r
-                       drvname[drvnamesize-3] = '.';\r
-                       drvname[drvnamesize-2] = '.';\r
-                       drvname[drvnamesize-1] = 0;\r
-               }\r
-               return 0;\r
-       }\r
-       return DRVERR_DEVICE_NOT_FOUND;\r
-}\r
-\r
-LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize)\r
-{\r
-       LPASIODRVSTRUCT                 lpdrv = 0;\r
-\r
-       if (!dllpath) return DRVERR_INVALID_PARAM;\r
-\r
-       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
-               if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) {\r
-                       strcpy(dllpath,lpdrv->dllpath);\r
-                       return 0;\r
-               }\r
-               dllpath[0] = 0;\r
-               return DRVERR_INVALID_PARAM;\r
-       }\r
-       return DRVERR_DEVICE_NOT_FOUND;\r
-}\r
-\r
-LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid)\r
-{\r
-       LPASIODRVSTRUCT                 lpdrv = 0;\r
-\r
-       if (!clsid) return DRVERR_INVALID_PARAM;\r
-\r
-       if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {\r
-               memcpy(clsid,&lpdrv->clsid,sizeof(CLSID));\r
-               return 0;\r
-       }\r
-       return DRVERR_DEVICE_NOT_FOUND;\r
-}\r
-\r
-\r
diff --git a/tests/asio/asiolist.h b/tests/asio/asiolist.h
deleted file mode 100644 (file)
index 01c64f0..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __asiolist__\r
-#define __asiolist__\r
-\r
-#define DRVERR                 -5000\r
-#define DRVERR_INVALID_PARAM           DRVERR-1\r
-#define DRVERR_DEVICE_ALREADY_OPEN     DRVERR-2\r
-#define DRVERR_DEVICE_NOT_FOUND                DRVERR-3\r
-\r
-#define MAXPATHLEN                     512\r
-#define MAXDRVNAMELEN          128\r
-\r
-struct asiodrvstruct\r
-{\r
-       int                                             drvID;\r
-       CLSID                                   clsid;\r
-       char                                    dllpath[MAXPATHLEN];\r
-       char                                    drvname[MAXDRVNAMELEN];\r
-       LPVOID                                  asiodrv;\r
-       struct asiodrvstruct    *next;\r
-};\r
-\r
-typedef struct asiodrvstruct ASIODRVSTRUCT;\r
-typedef ASIODRVSTRUCT  *LPASIODRVSTRUCT;\r
-\r
-class AsioDriverList {\r
-public:\r
-       AsioDriverList();\r
-       ~AsioDriverList();\r
-       \r
-       LONG asioOpenDriver (int,VOID **);\r
-       LONG asioCloseDriver (int);\r
-\r
-       // nice to have\r
-       LONG asioGetNumDev (VOID);\r
-       LONG asioGetDriverName (int,char *,int);                \r
-       LONG asioGetDriverPath (int,char *,int);\r
-       LONG asioGetDriverCLSID (int,CLSID *);\r
-\r
-       // or use directly access\r
-       LPASIODRVSTRUCT lpdrvlist;\r
-       int                             numdrv;\r
-};\r
-\r
-typedef class AsioDriverList *LPASIODRIVERLIST;\r
-\r
-#endif\r
diff --git a/tests/asio/asiosys.h b/tests/asio/asiosys.h
deleted file mode 100644 (file)
index 37f7a48..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef __asiosys__\r
-       #define __asiosys__\r
-\r
-       #ifdef WIN32\r
-               #undef MAC \r
-               #define PPC 0\r
-               #define WINDOWS 1\r
-               #define SGI 0\r
-               #define SUN 0\r
-               #define LINUX 0\r
-               #define BEOS 0\r
-\r
-               #define NATIVE_INT64 0\r
-               #define IEEE754_64FLOAT 1\r
-       \r
-       #elif BEOS\r
-               #define MAC 0\r
-               #define PPC 0\r
-               #define WINDOWS 0\r
-               #define PC 0\r
-               #define SGI 0\r
-               #define SUN 0\r
-               #define LINUX 0\r
-               \r
-               #define NATIVE_INT64 0\r
-               #define IEEE754_64FLOAT 1\r
-               \r
-               #ifndef DEBUG\r
-                       #define DEBUG 0\r
-                       #if DEBUG\r
-                               void DEBUGGERMESSAGE(char *string);\r
-                       #else\r
-                               #define DEBUGGERMESSAGE(a)\r
-                       #endif\r
-               #endif\r
-\r
-       #elif SGI\r
-               #define MAC 0\r
-               #define PPC 0\r
-               #define WINDOWS 0\r
-               #define PC 0\r
-               #define SUN 0\r
-               #define LINUX 0\r
-               #define BEOS 0\r
-               \r
-               #define NATIVE_INT64 0\r
-               #define IEEE754_64FLOAT 1\r
-               \r
-               #ifndef DEBUG\r
-                       #define DEBUG 0\r
-                       #if DEBUG\r
-                               void DEBUGGERMESSAGE(char *string);\r
-                       #else\r
-                               #define DEBUGGERMESSAGE(a)\r
-                       #endif\r
-               #endif\r
-\r
-       #else   // MAC\r
-\r
-               #define MAC 1\r
-               #define PPC 1\r
-               #define WINDOWS 0\r
-               #define PC 0\r
-               #define SGI 0\r
-               #define SUN 0\r
-               #define LINUX 0\r
-               #define BEOS 0\r
-\r
-               #define NATIVE_INT64 0\r
-               #define IEEE754_64FLOAT 1\r
-\r
-               #ifndef DEBUG\r
-                       #define DEBUG 0\r
-                       #if DEBUG\r
-                               void DEBUGGERMESSAGE(char *string);\r
-                       #else\r
-                               #define DEBUGGERMESSAGE(a)\r
-                       #endif\r
-               #endif\r
-       #endif\r
-\r
-#endif\r
diff --git a/tests/asio/call_inout.dsp b/tests/asio/call_inout.dsp
deleted file mode 100755 (executable)
index 97cc4d9..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-# Microsoft Developer Studio Project File - Name="call_inout" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=call_inout - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_inout.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_inout.mak" CFG="call_inout - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "call_inout - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "call_inout - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "call_inout - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "call_inout - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "call_inout - Win32 Release"\r
-# Name "call_inout - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\call_inout.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrvr.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiosys.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\ginclude.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\iasiodrv.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/asio/call_saw.dsp b/tests/asio/call_saw.dsp
deleted file mode 100755 (executable)
index 09fff2d..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-# Microsoft Developer Studio Project File - Name="call_saw" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=call_saw - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_saw.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "call_saw.mak" CFG="call_saw - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "call_saw - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "call_saw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "call_saw - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "call_saw - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "call_saw - Win32 Release"\r
-# Name "call_saw - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\call_saw.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrvr.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiosys.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\ginclude.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\iasiodrv.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/asio/ginclude.h b/tests/asio/ginclude.h
deleted file mode 100644 (file)
index b627dc2..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __gInclude__\r
-#define __gInclude__\r
-\r
-#if SGI \r
-       #undef BEOS \r
-       #undef MAC \r
-       #undef WINDOWS\r
-       //\r
-       #define ASIO_BIG_ENDIAN 1\r
-       #define ASIO_CPU_MIPS 1\r
-#elif defined WIN32\r
-       #undef BEOS \r
-       #undef MAC \r
-       #undef SGI\r
-       #define WINDOWS 1\r
-       #define ASIO_LITTLE_ENDIAN 1\r
-       #define ASIO_CPU_X86 1\r
-#elif BEOS\r
-       #undef MAC \r
-       #undef SGI\r
-       #undef WINDOWS\r
-       #define ASIO_LITTLE_ENDIAN 1\r
-       #define ASIO_CPU_X86 1\r
-       //\r
-#else\r
-       #define MAC 1\r
-       #undef BEOS \r
-       #undef WINDOWS\r
-       #undef SGI\r
-       #define ASIO_BIG_ENDIAN 1\r
-       #define ASIO_CPU_PPC 1\r
-#endif\r
-\r
-// always\r
-#define NATIVE_INT64 0\r
-#define IEEE754_64FLOAT 1\r
-\r
-#endif // __gInclude__\r
diff --git a/tests/asio/iasiodrv.h b/tests/asio/iasiodrv.h
deleted file mode 100644 (file)
index 64d2dbb..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "asiosys.h"\r
-#include "asio.h"\r
-\r
-/* Forward Declarations */ \r
-\r
-#ifndef __ASIODRIVER_FWD_DEFINED__\r
-#define __ASIODRIVER_FWD_DEFINED__\r
-typedef interface IASIO IASIO;\r
-#endif         /* __ASIODRIVER_FWD_DEFINED__ */\r
-\r
-interface IASIO : public IUnknown\r
-{\r
-\r
-       virtual ASIOBool init(void *sysHandle) = 0;\r
-       virtual void getDriverName(char *name) = 0;     \r
-       virtual long getDriverVersion() = 0;\r
-       virtual void getErrorMessage(char *string) = 0; \r
-       virtual ASIOError start() = 0;\r
-       virtual ASIOError stop() = 0;\r
-       virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0;\r
-       virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0;\r
-       virtual ASIOError getBufferSize(long *minSize, long *maxSize,\r
-               long *preferredSize, long *granularity) = 0;\r
-       virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0;\r
-       virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0;\r
-       virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0;\r
-       virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0;\r
-       virtual ASIOError setClockSource(long reference) = 0;\r
-       virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;\r
-       virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0;\r
-       virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,\r
-               long bufferSize, ASIOCallbacks *callbacks) = 0;\r
-       virtual ASIOError disposeBuffers() = 0;\r
-       virtual ASIOError controlPanel() = 0;\r
-       virtual ASIOError future(long selector,void *opt) = 0;\r
-       virtual ASIOError outputReady() = 0;\r
-};\r
diff --git a/tests/asio/in_out.dsp b/tests/asio/in_out.dsp
deleted file mode 100755 (executable)
index a1036bc..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-# Microsoft Developer Studio Project File - Name="in_out" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=in_out - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "in_out.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "in_out.mak" CFG="in_out - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "in_out - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "in_out - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "in_out - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "in_out - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "in_out - Win32 Release"\r
-# Name "in_out - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\in_out.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrvr.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiosys.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\ginclude.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\iasiodrv.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/asio/info.dsp b/tests/asio/info.dsp
deleted file mode 100755 (executable)
index 1d18051..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-# Microsoft Developer Studio Project File - Name="info" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=info - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "info.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "info.mak" CFG="info - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "info - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "info - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "info - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "info - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "info - Win32 Release"\r
-# Name "info - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\info.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrvr.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiosys.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\ginclude.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\iasiodrv.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/asio/play_raw.dsp b/tests/asio/play_raw.dsp
deleted file mode 100755 (executable)
index 96ddffb..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-# Microsoft Developer Studio Project File - Name="play_raw" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=play_raw - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "play_raw.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "play_raw.mak" CFG="play_raw - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "play_raw - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "play_raw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "play_raw - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "play_raw - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "play_raw - Win32 Release"\r
-# Name "play_raw - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\play_raw.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrvr.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiosys.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\ginclude.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\iasiodrv.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/asio/play_saw.dsp b/tests/asio/play_saw.dsp
deleted file mode 100755 (executable)
index 7aab9f1..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-# Microsoft Developer Studio Project File - Name="play_saw" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=play_saw - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "play_saw.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "play_saw.mak" CFG="play_saw - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "play_saw - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "play_saw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "play_saw - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "play_saw - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c\r
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "play_saw - Win32 Release"\r
-# Name "play_saw - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\play_saw.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrvr.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiosys.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\ginclude.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\iasiodrv.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/asio/record_raw.dsp b/tests/asio/record_raw.dsp
deleted file mode 100755 (executable)
index f39827a..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-# Microsoft Developer Studio Project File - Name="record_raw" - Package Owner=<4>\r
-# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-# ** DO NOT EDIT **\r
-\r
-# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
-\r
-CFG=record_raw - Win32 Debug\r
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "record_raw.mak".\r
-!MESSAGE \r
-!MESSAGE You can specify a configuration when running NMAKE\r
-!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
-!MESSAGE NMAKE /f "record_raw.mak" CFG="record_raw - Win32 Debug"\r
-!MESSAGE \r
-!MESSAGE Possible choices for configuration are:\r
-!MESSAGE \r
-!MESSAGE "record_raw - Win32 Release" (based on "Win32 (x86) Console Application")\r
-!MESSAGE "record_raw - Win32 Debug" (based on "Win32 (x86) Console Application")\r
-!MESSAGE \r
-\r
-# Begin Project\r
-# PROP AllowPerConfigDependencies 0\r
-# PROP Scc_ProjName ""\r
-# PROP Scc_LocalPath ""\r
-CPP=cl.exe\r
-RSC=rc.exe\r
-\r
-!IF  "$(CFG)" == "record_raw - Win32 Release"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 0\r
-# PROP BASE Output_Dir "Release"\r
-# PROP BASE Intermediate_Dir "Release"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 0\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Release"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /W3 /GX /O2 /I "../../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /YX /FD /c\r
-# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-# ADD RSC /l 0x409 /d "NDEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r
-\r
-!ELSEIF  "$(CFG)" == "record_raw - Win32 Debug"\r
-\r
-# PROP BASE Use_MFC 0\r
-# PROP BASE Use_Debug_Libraries 1\r
-# PROP BASE Output_Dir "Debug"\r
-# PROP BASE Intermediate_Dir "Debug"\r
-# PROP BASE Target_Dir ""\r
-# PROP Use_MFC 0\r
-# PROP Use_Debug_Libraries 1\r
-# PROP Output_Dir ""\r
-# PROP Intermediate_Dir "Debug"\r
-# PROP Target_Dir ""\r
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c\r
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__RTAUDIO_DEBUG__" /YX /FD /GZ  /c\r
-# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-# ADD RSC /l 0x409 /d "_DEBUG"\r
-BSC32=bscmake.exe\r
-# ADD BASE BSC32 /nologo\r
-# ADD BSC32 /nologo\r
-LINK32=link.exe\r
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r
-\r
-!ENDIF \r
-\r
-# Begin Target\r
-\r
-# Name "record_raw - Win32 Release"\r
-# Name "record_raw - Win32 Debug"\r
-# Begin Group "Source Files"\r
-\r
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\record_raw.cpp\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.cpp\r
-# End Source File\r
-# End Group\r
-# Begin Group "Header Files"\r
-\r
-# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-# Begin Source File\r
-\r
-SOURCE=.\asio.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrivers.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiodrvr.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiolist.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\asiosys.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\ginclude.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\iasiodrv.h\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\RtAudio.h\r
-# End Source File\r
-# End Group\r
-# Begin Group "Resource Files"\r
-\r
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-# End Group\r
-# End Target\r
-# End Project\r
diff --git a/tests/asio/rtaudio.dsw b/tests/asio/rtaudio.dsw
deleted file mode 100755 (executable)
index c070e92..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00\r
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
-\r
-###############################################################################\r
-\r
-Project: "call_inout"=.\call_inout.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "call_saw"=.\call_saw.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "in_out"=.\in_out.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "info"=.\info.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "play_raw"=.\play_raw.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "play_saw"=.\play_saw.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Project: "record_raw"=.\record_raw.dsp - Package Owner=<4>\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<4>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
-Global:\r
-\r
-Package=<5>\r
-{{{\r
-}}}\r
-\r
-Package=<3>\r
-{{{\r
-}}}\r
-\r
-###############################################################################\r
-\r
index 787a85658a023cf574fbb30360ccb1c6a66c2247..e941e1e3f92280c0eefef52bfa06c9fd9eaeb7a3 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************/
 /*
-  call_inout.c
+  call_inout.cpp
   by Gary P. Scavone, 2001
 
   Records from default input and passes it
 /******************************************/
 
 #include "RtAudio.h"
-#include <iostream.h>
+#include <iostream>
 
 /*
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
+#define FORMAT RTAUDIO_SINT24
 
 typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
+#define FORMAT RTAUDIO_SINT8
 
 typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
+#define FORMAT RTAUDIO_SINT16
 
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
+#define FORMAT RTAUDIO_SINT32
 
 typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
+#define FORMAT RTAUDIO_FLOAT32
 */
 
 typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
+#define FORMAT RTAUDIO_FLOAT64
 
 void usage(void) {
   /* Error function in case of incorrect command-line
      argument specifications
   */
-  cout << "\nuseage: call_inout N fs device\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    fs = the sample rate,\n";
-  cout << "    and device = the device to use (default = 0).\n\n";
+  std::cout << "\nuseage: call_inout N fs device\n";
+  std::cout << "    where N = number of channels,\n";
+  std::cout << "    fs = the sample rate,\n";
+  std::cout << "    and device = the device to use (default = 0).\n\n";
   exit(0);
 }
 
@@ -52,7 +52,7 @@ int inout(char *buffer, int buffer_size, void *)
 
 int main(int argc, char *argv[])
 {
-  int stream, chans, fs, device = 0;
+  int chans, fs, device = 0;
   RtAudio *audio;
   char input;
 
@@ -67,32 +67,35 @@ int main(int argc, char *argv[])
   // Open the realtime output device
   int buffer_size = 512;
   try {
-    audio = new RtAudio(&stream, device, chans, device, chans,
+    audio = new RtAudio(device, chans, device, chans,
                         FORMAT, fs, &buffer_size, 8);
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     exit(EXIT_FAILURE);
   }
 
   try {
-    audio->setStreamCallback(stream, &inout, NULL);
-    audio->startStream(stream);
+    audio->setStreamCallback(&inout, NULL);
+    audio->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
-  cout << "\nRunning ... press <enter> to quit (buffer size = " << buffer_size << ").\n";
-  cin.get(input);
+  std::cout << "\nRunning ... press <enter> to quit (buffer size = " << buffer_size << ").\n";
+  std::cin.get(input);
 
   try {
-    audio->stopStream(stream);
+    audio->stopStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
   }
 
  cleanup:
-  audio->closeStream(stream);
+  audio->closeStream();
   delete audio;
 
   return 0;
diff --git a/tests/call_playtwo.cpp b/tests/call_playtwo.cpp
deleted file mode 100644 (file)
index 4364262..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/******************************************/
-/*
-  call_playtwo.cpp
-  by Gary P. Scavone, 2002.
-
-  Test executable using two streams with
-  callbacks.
-*/
-/******************************************/
-
-#include "RtAudio.h"
-#include <iostream.h>
-
-/*
-typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
-#define SCALE  2147483647.0
-
-typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
-#define SCALE  127.0
-
-typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
-#define SCALE  32767.0
-
-typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
-#define SCALE  2147483647.0
-
-typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
-#define SCALE  1.0
-*/
-
-typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
-#define SCALE  1.0
-#define BASE_RATE1 0.005
-#define BASE_RATE2 0.004
-
-void usage(void) {
-  /* Error function in case of incorrect command-line
-     argument specifications
-  */
-  cout << "\nuseage: call_twostreams N fs\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    and fs = the sample rate.\n\n";
-  exit(0);
-}
-
-int chans;
-
-int saw1(char *buffer, int buffer_size, void *data)
-{
-  int i, j;
-  extern int chans;
-  MY_TYPE *my_buffer = (MY_TYPE *) buffer;
-  double *my_data = (double *) data;
-
-  for (i=0; i<buffer_size; i++) {
-    for (j=0; j<chans; j++) {
-      *my_buffer++ = (MY_TYPE) (my_data[j] * SCALE);
-      my_data[j] += BASE_RATE1 * (j+1+(j*0.1));
-      if (my_data[j] >= 1.0) my_data[j] -= 2.0;
-    }
-  }
-
-  return 0;
-}
-
-int saw2(char *buffer, int buffer_size, void *data)
-{
-  int i, j;
-  extern int chans;
-  MY_TYPE *my_buffer = (MY_TYPE *) buffer;
-  double *my_data = (double *) data;
-
-  for (i=0; i<buffer_size; i++) {
-    for (j=0; j<chans; j++) {
-      *my_buffer++ = (MY_TYPE) (my_data[j] * SCALE);
-      my_data[j] += BASE_RATE2 * (j+1+(j*0.1));
-      if (my_data[j] >= 1.0) my_data[j] -= 2.0;
-    }
-  }
-
-  return 0;
-}
-
-int main(int argc, char *argv[])
-{
-  int device, buffer_size, stream1 = 0, stream2 = 0, fs;
-  double *data1 = 0;
-  double *data2 = 0;
-  RtAudio *audio;
-  char input;
-
-  // minimal command-line checking
-  if (argc != 3) usage();
-
-  chans = (int) atoi(argv[1]);
-  fs = (int) atoi(argv[2]);
-
-  // Open the realtime output device
-  buffer_size = 512;
-  device = 0; // default device
-  try {
-    audio = new RtAudio();
-  }
-  catch (RtError &) {
-    exit(EXIT_FAILURE);
-  }
-
-  try {
-    stream1 = audio->openStream(device, chans, 0, 0,
-                                FORMAT, fs, &buffer_size, 8);
-    stream2 = audio->openStream(device, chans, 0, 0,
-                                FORMAT, fs, &buffer_size, 8);
-  }
-  catch (RtError &) {
-    goto cleanup;
-  }
-
-  data1 = (double *) calloc(chans, sizeof(double));
-  data2 = (double *) calloc(chans, sizeof(double));
-
-  try {
-    audio->setStreamCallback(stream1, &saw1, (void *)data1);
-    audio->setStreamCallback(stream2, &saw2, (void *)data2);
-    audio->startStream(stream1);
-    audio->startStream(stream2);
-  }
-  catch (RtError &) {
-    goto cleanup;
-  }
-
-  cout << "\nRunning two streams ... press <enter> to quit.\n";
-  cin.get(input);
-
-  cout << "\nStopping both streams.\n";
-  try {
-    audio->stopStream(stream1);
-    audio->stopStream(stream2);
-  }
-  catch (RtError &) {
-    goto cleanup;
-  }
-
-  cout << "\nPress <enter> to restart streams:\n";
-  cin.get(input);
-
-  try {
-    audio->startStream(stream1);
-    audio->startStream(stream2);
-  }
-  catch (RtError &) {
-    goto cleanup;
-  }
-
-  cout << "\nRunning two streams (quasi-duplex) ... press <enter> to quit.\n";
-  cin.get(input);
-
-  try {
-    audio->stopStream(stream1);
-    audio->stopStream(stream2);
-  }
-  catch (RtError &) {
-  }
-
- cleanup:
-  audio->closeStream(stream1);
-  audio->closeStream(stream2);
-  delete audio;
-  if (data1) free(data1);
-  if (data2) free(data2);
-
-  return 0;
-}
index fa1ca6594940876c3cf7ba85a078cfbc2ae6d6e2..57f225c91f17cfbc29ed5daa845b0c628759b280 100644 (file)
 /******************************************/
 
 #include "RtAudio.h"
-#include <iostream.h>
+#include <iostream>
 
 /*
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
+#define FORMAT RTAUDIO_SINT24
 #define SCALE  2147483647.0
 
 typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
+#define FORMAT RTAUDIO_SINT8
 #define SCALE  127.0
 
 typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
+#define FORMAT RTAUDIO_SINT16
 #define SCALE  32767.0
 
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
+#define FORMAT RTAUDIO_SINT32
 #define SCALE  2147483647.0
 */
 typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
+#define FORMAT RTAUDIO_FLOAT32
 #define SCALE  1.0
 
 /*
 typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
+#define FORMAT RTAUDIO_FLOAT64
 #define SCALE  1.0
 */
 
@@ -46,10 +46,10 @@ void usage(void) {
   /* Error function in case of incorrect command-line
      argument specifications
   */
-  cout << "\nuseage: call_saw N fs <device>\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    fs = the sample rate,\n";
-  cout << "    and device = the device to use (default = 0).\n\n";
+  std::cout << "\nuseage: call_saw N fs <device>\n";
+  std::cout << "    where N = number of channels,\n";
+  std::cout << "    fs = the sample rate,\n";
+  std::cout << "    and device = the device to use (default = 0).\n\n";
   exit(0);
 }
 
@@ -75,7 +75,7 @@ int saw(char *buffer, int buffer_size, void *data)
 
 int main(int argc, char *argv[])
 {
-  int stream, buffer_size, fs, device = 0;
+  int buffer_size, fs, device = 0;
   RtAudio *audio;
   double *data;
   char input;
@@ -91,35 +91,38 @@ int main(int argc, char *argv[])
   // Open the realtime output device
   buffer_size = 1024;
   try {
-    audio = new RtAudio(&stream, device, chans, 0, 0,
+    audio = new RtAudio(device, chans, 0, 0,
                         FORMAT, fs, &buffer_size, 4);
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     exit(EXIT_FAILURE);
   }
 
   data = (double *) calloc(chans, sizeof(double));
 
   try {
-    audio->setStreamCallback(stream, &saw, (void *)data);
-    audio->startStream(stream);
+    audio->setStreamCallback(&saw, (void *)data);
+    audio->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
-  cout << "\nPlaying ... press <enter> to quit (buffer size = " << buffer_size << ").\n";
-  cin.get(input);
+  std::cout << "\nPlaying ... press <enter> to quit (buffer size = " << buffer_size << ").\n";
+  std::cin.get(input);
 
   // Stop the stream.
   try {
-    audio->stopStream(stream);
+    audio->stopStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
   }
 
  cleanup:
-  audio->closeStream(stream);
+  audio->closeStream();
   delete audio;
   if (data) free(data);
 
diff --git a/tests/call_twostreams.cpp b/tests/call_twostreams.cpp
deleted file mode 100644 (file)
index 4af0eac..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/******************************************/
-/*
-  twostreams.cpp
-  by Gary P. Scavone, 2001
-
-  Test executable using two streams with
-  callbacks.
-*/
-/******************************************/
-
-#include "RtAudio.h"
-#include <iostream.h>
-
-/*
-typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
-#define SCALE  2147483647.0
-
-typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
-#define SCALE  127.0
-
-typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
-#define SCALE  32767.0
-
-typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
-#define SCALE  2147483647.0
-
-typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
-#define SCALE  1.0
-*/
-
-typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
-#define SCALE  1.0
-
-void usage(void) {
-  /* Error function in case of incorrect command-line
-     argument specifications
-  */
-  cout << "\nuseage: call_twostreams N fs <device>\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    fs = the sample rate,\n";
-  cout << "    and device = the device to use (default = 0).\n\n";
-  exit(0);
-}
-
-int chans;
-
-int in(char *buffer, int buffer_size, void *data)
-{
-  extern int chans;
-  MY_TYPE *my_buffer = (MY_TYPE *) buffer;
-  MY_TYPE *my_data = (MY_TYPE *) data;
-  long buffer_bytes = buffer_size * chans * sizeof(MY_TYPE);
-
-  memcpy(my_data, my_buffer, buffer_bytes);
-
-  return 0;
-}
-
-int out(char *buffer, int buffer_size, void *data)
-{
-  extern int chans;
-  MY_TYPE *my_buffer = (MY_TYPE *) buffer;
-  MY_TYPE *my_data = (MY_TYPE *) data;
-  long buffer_bytes = buffer_size * chans * sizeof(MY_TYPE);
-
-  memcpy(my_buffer, my_data, buffer_bytes);
-
-  return 0;
-}
-
-int main(int argc, char *argv[])
-{
-  int buffer_size, stream1 = 0, stream2 = 0, fs, device = 0;
-  MY_TYPE *data = 0;
-  RtAudio *audio;
-  char input;
-
-  // minimal command-line checking
-  if (argc != 3 && argc != 4 ) usage();
-
-  chans = (int) atoi(argv[1]);
-  fs = (int) atoi(argv[2]);
-  if ( argc == 4 )
-    device = (int) atoi(argv[3]);
-
-  // Open the realtime output device
-  buffer_size = 512;
-  try {
-    audio = new RtAudio();
-  }
-  catch (RtError &) {
-    exit(EXIT_FAILURE);
-  }
-
-  try {
-    stream1 = audio->openStream(0, 0, device, chans,
-                                FORMAT, fs, &buffer_size, 8);
-    stream2 = audio->openStream(device, chans, 0, 0,
-                                FORMAT, fs, &buffer_size, 8);
-  }
-  catch (RtError &) {
-    goto cleanup;
-  }
-
-  data = (MY_TYPE *) calloc(chans*buffer_size, sizeof(MY_TYPE));
-  try {
-    audio->setStreamCallback(stream1, &in, (void *)data);
-    audio->setStreamCallback(stream2, &out, (void *)data);
-    audio->startStream(stream1);
-    audio->startStream(stream2);
-  }
-  catch (RtError &) {
-    goto cleanup;
-  }
-
-  cout << "\nRunning two streams (quasi-duplex) ... press <enter> to quit.\n";
-  cin.get(input);
-
-  cout << "\nStopping both streams.\n";
-  try {
-    audio->stopStream(stream1);
-    audio->stopStream(stream2);
-  }
-  catch (RtError &) {
-    goto cleanup;
-  }
-
-  cout << "\nPress <enter> to restart streams:\n";
-  cin.get(input);
-
-  try {
-    audio->startStream(stream1);
-    audio->startStream(stream2);
-  }
-  catch (RtError &) {
-    goto cleanup;
-  }
-
-  cout << "\nRunning two streams (quasi-duplex) ... press <enter> to quit.\n";
-  cin.get(input);
-
-  try {
-    audio->stopStream(stream1);
-    audio->stopStream(stream2);
-  }
-  catch (RtError &) {
-  }
-
- cleanup:
-  audio->closeStream(stream1);
-  audio->closeStream(stream2);
-  delete audio;
-  if (data) free(data);
-
-  return 0;
-}
index 053f620561e036e8335628819942c21608a17a4a..bba4d737d4c94e86d9d52a58a04628268f459449 100644 (file)
 /******************************************/
 
 #include "RtAudio.h"
-#include <iostream.h>
+#include <iostream>
 
 /*
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
+#define FORMAT RTAUDIO_SINT24
 
 typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
+#define FORMAT RTAUDIO_SINT8
 
 typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
+#define FORMAT RTAUDIO_SINT16
 
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
+#define FORMAT RTAUDIO_SINT32
 
 typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
+#define FORMAT RTAUDIO_FLOAT32
 */
 
 typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
+#define FORMAT RTAUDIO_FLOAT64
 
 #define TIME   4.0
 
@@ -39,16 +39,16 @@ void usage(void) {
   /* Error function in case of incorrect command-line
      argument specifications
   */
-  cout << "\nuseage: in_out N fs <device>\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    fs = the sample rate,\n";
-  cout << "    and device = the device to use (default = 0).\n\n";
+  std::cout << "\nuseage: in_out N fs <device>\n";
+  std::cout << "    where N = number of channels,\n";
+  std::cout << "    fs = the sample rate,\n";
+  std::cout << "    and device = the device to use (default = 0).\n\n";
   exit(0);
 }
 
 int main(int argc, char *argv[])
 {
-  int chans, fs, buffer_size, stream, device = 0;
+  int chans, fs, buffer_size, device = 0;
   long frames, counter = 0;
   MY_TYPE *buffer;
   RtAudio *audio;
@@ -64,43 +64,47 @@ int main(int argc, char *argv[])
   // Open the realtime output device
   buffer_size = 512;
   try {
-    audio = new RtAudio(&stream, device, chans, device, chans,
+    audio = new RtAudio(device, chans, device, chans,
                         FORMAT, fs, &buffer_size, 8);
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     exit(EXIT_FAILURE);
   }
 
   frames = (long) (fs * TIME);
 
   try {
-    buffer = (MY_TYPE *) audio->getStreamBuffer(stream);
-    audio->startStream(stream);
+    buffer = (MY_TYPE *) audio->getStreamBuffer();
+    audio->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
-  cout << "\nRunning for " << TIME << " seconds ... fragment_size = " << buffer_size << endl;
+  std::cout << "\nRunning for " << TIME << " seconds ... fragment_size = " << buffer_size << std::endl;
   while (counter < frames) {
 
     try {
-      audio->tickStream(stream);
+      audio->tickStream();
     }
-    catch (RtError &) {
+    catch (RtError &error) {
+      error.printMessage();
       goto cleanup;
     }
     counter += buffer_size;
   }
 
   try {
-    audio->stopStream(stream);
+    audio->stopStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
   }
 
  cleanup:
-  audio->closeStream(stream);
+  audio->closeStream();
   delete audio;
 
   return 0;
index fdde04982dc3d0e68691e9bbda49c1c4345fdd13..81a4234d68f6def3a3e2ecc19c600c131e5f77ee 100644 (file)
@@ -8,61 +8,70 @@
 /******************************************/
 
 #include "RtAudio.h"
-#include <iostream.h>
+#include <iostream>
 
 int main(int argc, char *argv[])
 {
   RtAudio *audio;
-  RtAudio::RTAUDIO_DEVICE my_info;
+  RtAudioDeviceInfo info;
   try {
     audio = new RtAudio();
   }
-  catch (RtError &m) {
-    m.printMessage();
+  catch (RtError &error) {
+    error.printMessage();
     exit(EXIT_FAILURE);
   }
 
   int devices = audio->getDeviceCount();
-  cout << "\nFound " << devices << " devices ...\n";
+  std::cout << "\nFound " << devices << " device(s) ...\n";
 
   for (int i=1; i<=devices; i++) {
     try {
-      audio->getDeviceInfo(i, &my_info);
+      info = audio->getDeviceInfo(i);
     }
-    catch (RtError &m) {
-      m.printMessage();
+    catch (RtError &error) {
+      error.printMessage();
       break;
     }
 
-    cout << "\nname = " << my_info.name << '\n';
-    if (my_info.probed == true) {
-      cout << "probe successful\n";
-      cout << "maxOutputChans = " << my_info.maxOutputChannels << '\n';
-      cout << "minOutputChans = " << my_info.minOutputChannels << '\n';
-      cout << "maxInputChans = " << my_info.maxInputChannels << '\n';
-      cout << "minInputChans = " << my_info.minInputChannels << '\n';
-      cout << "maxDuplexChans = " << my_info.maxDuplexChannels << '\n';
-      cout << "minDuplexChans = " << my_info.minDuplexChannels << '\n';
-      if (my_info.hasDuplexSupport) cout << "duplex support = true\n";
-      else cout << "duplex support = false\n";
-      if (my_info.isDefault) cout << "is default device = true\n";
-      else cout << "is default device = false\n";
-      cout << "format = " << my_info.nativeFormats << '\n';
-      if (my_info.nSampleRates == -1) {
-        cout << "min_srate = " << my_info.sampleRates[0];
-        cout << ", max_srate = " << my_info.sampleRates[1] << '\n';
+    std::cout << "\nDevice Name = " << info.name << '\n';
+    if (info.probed == false)
+      std::cout << "Probe Status = UNsuccessful\n";
+    else {
+      std::cout << "Probe Status = Successful\n";
+      std::cout << "Output Channels = " << info.outputChannels << '\n';
+      std::cout << "Input Channels = " << info.inputChannels << '\n';
+      std::cout << "Duplex Channels = " << info.duplexChannels << '\n';
+      if (info.isDefault) std::cout << "This is the default device.\n";
+      else std::cout << "This is NOT the default device.\n";
+      if ( info.nativeFormats == 0 )
+        std::cout << "No natively supported data formats(?)!";
+      else {
+        std::cout << "Natively supported data formats:\n";
+        if ( info.nativeFormats & RTAUDIO_SINT8 )
+          std::cout << "  8-bit int\n";
+        if ( info.nativeFormats & RTAUDIO_SINT16 )
+          std::cout << "  16-bit int\n";
+        if ( info.nativeFormats & RTAUDIO_SINT24 )
+          std::cout << "  24-bit int\n";
+        if ( info.nativeFormats & RTAUDIO_SINT32 )
+          std::cout << "  32-bit int\n";
+        if ( info.nativeFormats & RTAUDIO_FLOAT32 )
+          std::cout << "  32-bit float\n";
+        if ( info.nativeFormats & RTAUDIO_FLOAT64 )
+          std::cout << "  64-bit float\n";
       }
+      if ( info.sampleRates.size() < 1 )
+        std::cout << "No supported sample rates found!";
       else {
-        cout << "sample rates = ";
-        for (int j=0; j<my_info.nSampleRates; j++)
-          cout << my_info.sampleRates[j] << " ";
-        cout << endl;
+        std::cout << "Supported sample rates = ";
+        for (unsigned int j=0; j<info.sampleRates.size(); j++)
+          std::cout << info.sampleRates[j] << " ";
       }
+      std::cout << std::endl;
     }
-    else
-      cout << "probe unsuccessful\n";
   }
-  cout << endl;
+  std::cout << std::endl;
 
   delete audio;
   return 0;
index f10347486671f40dbc15419db8a4cc373996b9bc..fcc921f08383f111216dac94c3c524e4b95701e9 100644 (file)
 /******************************************/
 
 #include "RtAudio.h"
-#include <iostream.h>
+#include <iostream>
 #include <stdio.h>
 
 /*
 typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
+#define FORMAT RTAUDIO_SINT8
 #define SCALE  127.0
 
 typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
+#define FORMAT RTAUDIO_SINT16
 #define SCALE  32767.0
 
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
+#define FORMAT RTAUDIO_SINT24
 #define SCALE  8388607.0
 
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
+#define FORMAT RTAUDIO_SINT32
 #define SCALE  2147483647.0
 */
 
 typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
+#define FORMAT RTAUDIO_FLOAT32
 #define SCALE  1.0;
 
 /*
 typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
+#define FORMAT RTAUDIO_FLOAT64
 #define SCALE  1.0;
 */
 
@@ -45,17 +45,17 @@ void usage(void) {
   /* Error function in case of incorrect command-line
      argument specifications
   */
-  cout << "\nuseage: play_raw N fs file <device>\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    fs = the sample rate, \n";
-  cout << "    file = the raw file to play,\n";
-  cout << "    and device = the device to use (default = 0).\n\n";
+  std::cout << "\nuseage: play_raw N fs file <device>\n";
+  std::cout << "    where N = number of channels,\n";
+  std::cout << "    fs = the sample rate, \n";
+  std::cout << "    file = the raw file to play,\n";
+  std::cout << "    and device = the device to use (default = 0).\n\n";
   exit(0);
 }
 
 int main(int argc, char *argv[])
 {
-  int chans, fs, buffer_size, count, stream, device = 0;
+  int chans, fs, buffer_size, count, device = 0;
   long counter = 0;
   MY_TYPE *buffer;
   char *file;
@@ -73,26 +73,28 @@ int main(int argc, char *argv[])
 
   fd = fopen(file,"rb");
   if (!fd) {
-    cout << "can't find file!\n";
+    std::cout << "can't find file!\n";
     exit(0);
   }
 
   // Open the realtime output device
   buffer_size = 512;
   try {
-    audio = new RtAudio(&stream, device, chans, 0, 0,
+    audio = new RtAudio(device, chans, 0, 0,
                         FORMAT, fs, &buffer_size, 2);
   }
-  catch (RtError &) {
+  catch (RtError &error) {
     fclose(fd);
+    error.printMessage();
     exit(EXIT_FAILURE);
   }
 
   try {
-    buffer = (MY_TYPE *) audio->getStreamBuffer(stream);
-    audio->startStream(stream);
+    buffer = (MY_TYPE *) audio->getStreamBuffer();
+    audio->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
@@ -101,9 +103,10 @@ int main(int argc, char *argv[])
 
     if (count == buffer_size) {
       try {
-        audio->tickStream(stream);
+        audio->tickStream();
       }
-      catch (RtError &) {
+      catch (RtError &error) {
+        error.printMessage();
         goto cleanup;
       }
     }
@@ -114,13 +117,14 @@ int main(int argc, char *argv[])
   }
 
   try {
-    audio->stopStream(stream);
+    audio->stopStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
   }
 
  cleanup:
-  audio->closeStream(stream);
+  audio->closeStream();
   delete audio;
   fclose(fd);
 
index d028be5f4b28984bec293732045e2925b4b6956a..4b2cbdde6af113f4ce9174c01f124ee60ac651f6 100644 (file)
 /******************************************/
 
 #include "RtAudio.h"
-#include <iostream.h>
+#include <iostream>
 
 /*
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
+#define FORMAT RTAUDIO_SINT24
 #define SCALE  2147483647.0
-*/
 
 typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
+#define FORMAT RTAUDIO_SINT8
 #define SCALE  127.0
+*/
 
-/*
 typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
+#define FORMAT RTAUDIO_SINT16
 #define SCALE  32767.0
 
-
+/*
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
+#define FORMAT RTAUDIO_SINT32
 #define SCALE  2147483647.0
 
 typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
+#define FORMAT RTAUDIO_FLOAT32
 #define SCALE  1.0
 
 typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
+#define FORMAT RTAUDIO_FLOAT64
 #define SCALE  1.0
 */
 
 #define BASE_RATE 0.005
-#define TIME   1.0
+#define TIME   4.0
 
 void usage(void) {
   // Error function in case of incorrect command-line
   // argument specifications.
-  cout << "\nuseage: play_saw N fs <device>\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    fs = the sample rate,\n";
-  cout << "    and device = the device to use (default = 0).\n\n";
+  std::cout << "\nuseage: play_saw N fs <device>\n";
+  std::cout << "    where N = number of channels,\n";
+  std::cout << "    fs = the sample rate,\n";
+  std::cout << "    and device = the device to use (default = 0).\n\n";
   exit(0);
 }
 
 int main(int argc, char *argv[])
 {
-  int chans, fs, buffer_size, stream, device = 0;
+  int chans, fs, buffer_size, device = 0;
   long frames, counter = 0, i, j;
   MY_TYPE *buffer;
   RtAudio *audio;
-  double *data;
+  double *data = 0;
 
   // minimal command-line checking
   if (argc != 3 && argc != 4 ) usage();
@@ -73,10 +72,11 @@ int main(int argc, char *argv[])
   // Open the realtime output device
   buffer_size = 512;
   try {
-    audio = new RtAudio(&stream, device, chans, 0, 0,
+    audio = new RtAudio(device, chans, 0, 0,
                         FORMAT, fs, &buffer_size, 4);
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     exit(EXIT_FAILURE);
   }
 
@@ -84,14 +84,15 @@ int main(int argc, char *argv[])
   data = (double *) calloc(chans, sizeof(double));
 
   try {
-    buffer = (MY_TYPE *) audio->getStreamBuffer(stream);
-    audio->startStream(stream);
+    buffer = (MY_TYPE *) audio->getStreamBuffer();
+    audio->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
-  cout << "\nPlaying for " << TIME << " seconds ... buffer size = " << buffer_size << "." << endl;
+  std::cout << "\nPlaying for " << TIME << " seconds ... buffer size = " << buffer_size << "." << std::endl;
   while (counter < frames) {
     for (i=0; i<buffer_size; i++) {
       for (j=0; j<chans; j++) {
@@ -102,10 +103,10 @@ int main(int argc, char *argv[])
     }
 
     try {
-      //cout << "frames until no block = " << audio->streamWillBlock(stream) << endl;
-      audio->tickStream(stream);
+      audio->tickStream();
     }
-    catch (RtError &) {
+    catch (RtError &error) {
+      error.printMessage();
       goto cleanup;
     }
 
@@ -113,13 +114,14 @@ int main(int argc, char *argv[])
   }
 
   try {
-    audio->stopStream(stream);
+    audio->stopStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
   }
 
  cleanup:
-  audio->closeStream(stream);
+  audio->closeStream();
   delete audio;
   if (data) free(data);
 
index 1b7964498a4b7b2eeb53479ca5cb632d93cc7290..717ce2c1fea7571bbb83dbba0db3830a08b70ab1 100644 (file)
 /******************************************/
 
 #include "RtAudio.h"
-#include <iostream.h>
+#include <iostream>
 #include <stdio.h>
 
 /*
 typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
+#define FORMAT RTAUDIO_SINT8
 
 typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
+#define FORMAT RTAUDIO_SINT16
 
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
+#define FORMAT RTAUDIO_SINT24
 
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
+#define FORMAT RTAUDIO_SINT32
 */
 
 typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
+#define FORMAT RTAUDIO_FLOAT32
 
 /*
 typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
+#define FORMAT RTAUDIO_FLOAT64
 */
 
 #define TIME   2.0
@@ -41,16 +41,16 @@ void usage(void) {
   /* Error function in case of incorrect command-line
      argument specifications
   */
-  cout << "\nuseage: record_raw N fs <device>\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    fs = the sample rate,\n";
-  cout << "    and device = the device to use (default = 0).\n\n";
+  std::cout << "\nuseage: record_raw N fs <device>\n";
+  std::cout << "    where N = number of channels,\n";
+  std::cout << "    fs = the sample rate,\n";
+  std::cout << "    and device = the device to use (default = 0).\n\n";
   exit(0);
 }
 
 int main(int argc, char *argv[])
 {
-  int chans, fs, buffer_size, stream, device = 0;
+  int chans, fs, buffer_size, device = 0;
   long frames, counter = 0;
   MY_TYPE *buffer;
   FILE *fd;
@@ -67,10 +67,11 @@ int main(int argc, char *argv[])
   // Open the realtime output device
   buffer_size = 512;
   try {
-    audio = new RtAudio(&stream, 0, 0, device, chans,
+    audio = new RtAudio(0, 0, device, chans,
                         FORMAT, fs, &buffer_size, 8);
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     exit(EXIT_FAILURE);
   }
 
@@ -78,20 +79,22 @@ int main(int argc, char *argv[])
   frames = (long) (fs * TIME);
 
   try {
-    buffer = (MY_TYPE *) audio->getStreamBuffer(stream);
-    audio->startStream(stream);
+    buffer = (MY_TYPE *) audio->getStreamBuffer();
+    audio->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
-  cout << "\nRecording for " << TIME << " seconds ... writing file test.raw (buffer size = " << buffer_size << ")." << endl;
+  std::cout << "\nRecording for " << TIME << " seconds ... writing file test.raw (buffer size = " << buffer_size << ")." << std::endl;
   while (counter < frames) {
 
     try {
-      audio->tickStream(stream);
+      audio->tickStream();
     }
-    catch (RtError &) {
+    catch (RtError &error) {
+      error.printMessage();
       goto cleanup;
     }
 
@@ -100,13 +103,14 @@ int main(int argc, char *argv[])
   }
 
   try {
-    audio->stopStream(stream);
+    audio->stopStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
   }
 
  cleanup:
-  audio->closeStream(stream);
+  audio->closeStream();
   delete audio;
   fclose(fd);
 
index 94a036cd5ae65bcc3f0dca2ea1885be8251d53a9..508cf4d42dc23dc8eeb3c789688821c9886354a0 100644 (file)
@@ -3,45 +3,43 @@
   twostreams.cpp
   by Gary P. Scavone, 2001
 
-  Test executable for audio playback,
-  recording, duplex operation, stopping,
-  starting, and aborting operations.
-  Takes number of channels and sample
-  rate as input arguments.  Runs input
-  and output through two separate streams.
+  Test executable for audio playback, recording,
+  duplex operation, stopping, starting, and
+  aborting operations.  Takes number of channels
+  and sample rate as input arguments.  Runs input
+  and output through two separate instances of RtAudio.
   Uses blocking functionality.
 */
 /******************************************/
 
 #include "RtAudio.h"
-#include <iostream.h>
-#include <stdio.h>
+#include <iostream>
 
 /*
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT24
+#define FORMAT RTAUDIO_SINT24
 #define SCALE  2147483647.0
 
 typedef char  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT8
+#define FORMAT RTAUDIO_SINT8
 #define SCALE  127.0
 
 typedef signed short  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT16
+#define FORMAT RTAUDIO_SINT16
 #define SCALE  32767.0
 
 typedef signed long  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_SINT32
+#define FORMAT RTAUDIO_SINT32
 #define SCALE  2147483647.0
 */
 
 typedef float  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT32
+#define FORMAT RTAUDIO_FLOAT32
 #define SCALE  1.0
 
 /*
 typedef double  MY_TYPE;
-#define FORMAT RtAudio::RTAUDIO_FLOAT64
+#define FORMAT RTAUDIO_FLOAT64
 #define SCALE  1.0
 */
 
@@ -52,19 +50,19 @@ void usage(void) {
   /* Error function in case of incorrect command-line
      argument specifications
   */
-  cout << "\nuseage: twostreams N fs <device>\n";
-  cout << "    where N = number of channels,\n";
-  cout << "    fs = the sample rate,\n";
-  cout << "    and device = the device to use (default = 0).\n\n";
+  std::cout << "\nuseage: twostreams N fs <device>\n";
+  std::cout << "    where N = number of channels,\n";
+  std::cout << "    fs = the sample rate,\n";
+  std::cout << "    and device = the device to use (default = 0).\n\n";
   exit(0);
 }
 
 int main(int argc, char *argv[])
 {
-  int chans, fs, buffer_size, stream1 = 0, stream2 = 0, device = 0;
+  int chans, fs, buffer_size, device = 0;
   long frames, counter = 0, i, j;
   MY_TYPE *buffer1, *buffer2;
-  RtAudio *audio;
+  RtAudio *stream1, *stream2;
   FILE *fd;
   double *data = 0;
 
@@ -79,27 +77,30 @@ int main(int argc, char *argv[])
   // Open the realtime output device
   buffer_size = 512;
   try {
-    audio = new RtAudio();
+    stream1 = new RtAudio(device, chans, 0, 0,
+                          FORMAT, fs, &buffer_size, 8);
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     exit(EXIT_FAILURE);
   }
 
   try {
-    stream1 = audio->openStream(device, chans, 0, 0,
-                                FORMAT, fs, &buffer_size, 8);
-    stream2 = audio->openStream(0, 0, device, chans,
-                                FORMAT, fs, &buffer_size, 8);
+    stream2 = new RtAudio(0, 0, device, chans,
+                          FORMAT, fs, &buffer_size, 8);
   }
-  catch (RtError &) {
-    goto cleanup;
+  catch (RtError &error) {
+    delete stream1;
+    error.printMessage();
+    exit(EXIT_FAILURE);
   }
 
   try {
-    buffer1 = (MY_TYPE *) audio->getStreamBuffer(stream1);
-    buffer2 = (MY_TYPE *) audio->getStreamBuffer(stream2);
+    buffer1 = (MY_TYPE *) stream1->getStreamBuffer();
+    buffer2 = (MY_TYPE *) stream2->getStreamBuffer();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
@@ -107,13 +108,14 @@ int main(int argc, char *argv[])
   data = (double *) calloc(chans, sizeof(double));
 
   try {
-    audio->startStream(stream1);
+    stream1->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
-  cout << "\nStarting sawtooth playback stream for " << TIME << " seconds." << endl;
+  std::cout << "\nStarting sawtooth playback stream for " << TIME << " seconds." << std::endl;
   while (counter < frames) {
     for (i=0; i<buffer_size; i++) {
       for (j=0; j<chans; j++) {
@@ -124,40 +126,44 @@ int main(int argc, char *argv[])
     }
 
     try {
-      audio->tickStream(stream1);
+      stream1->tickStream();
     }
-    catch (RtError &) {
+    catch (RtError &error) {
+      error.printMessage();
       goto cleanup;
     }
 
     counter += buffer_size;
   }
 
-  cout << "\nStopping playback stream." << endl;
+  std::cout << "\nStopping playback stream." << std::endl;
   try {
-    audio->stopStream(stream1);
+    stream1->stopStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
   fd = fopen("test.raw","wb");
 
   try {
-    audio->startStream(stream2);
+    stream2->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
   counter = 0;
-  cout << "\nStarting recording stream for " << TIME << " seconds." << endl;
+  std::cout << "\nStarting recording stream for " << TIME << " seconds." << std::endl;
   while (counter < frames) {
 
     try {
-      audio->tickStream(stream2);
+      stream2->tickStream();
     }
-    catch (RtError &) {
+    catch (RtError &error) {
+      error.printMessage();
       goto cleanup;
     }
 
@@ -166,45 +172,49 @@ int main(int argc, char *argv[])
   }
 
   fclose(fd);
-  cout << "\nAborting recording." << endl;
+  std::cout << "\nAborting recording." << std::endl;
 
   try {
-    audio->abortStream(stream2);
-    audio->startStream(stream1);
-    audio->startStream(stream2);
+    stream2->abortStream();
+    stream1->startStream();
+    stream2->startStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
     goto cleanup;
   }
 
   counter = 0;
-  cout << "\nStarting playback and record streams (quasi-duplex) for " << TIME << " seconds." << endl;
+  std::cout << "\nStarting playback and record streams (quasi-duplex) for " << TIME << " seconds." << std::endl;
   while (counter < frames) {
 
     try {
-      audio->tickStream(stream2);
+      stream2->tickStream();
       memcpy(buffer1, buffer2, sizeof(MY_TYPE) * chans * buffer_size);
-      audio->tickStream(stream1);
+      stream1->tickStream();
     }
-    catch (RtError &) {
+    catch (RtError &error) {
+      error.printMessage();
       goto cleanup;
     }
 
     counter += buffer_size;
   }
 
-  cout << "\nStopping both streams." << endl;
+  std::cout << "\nStopping both streams." << std::endl;
   try {
-    audio->stopStream(stream1);
-    audio->stopStream(stream2);
+    stream1->stopStream();
+    stream2->stopStream();
   }
-  catch (RtError &) {
+  catch (RtError &error) {
+    error.printMessage();
   }
 
  cleanup:
-  audio->closeStream(stream1);
-  audio->closeStream(stream2);
-  delete audio;
+  stream1->closeStream();
+  stream2->closeStream();
+  delete stream1;
+  delete stream2;
   if (data) free(data);
 
   return 0;