Version 2.1.1
authorGary Scavone <gary@music.mcgill.ca>
Wed, 9 Oct 2013 21:45:50 +0000 (23:45 +0200)
committerStephen Sinclair <sinclair@music.mcgill.ca>
Wed, 9 Oct 2013 23:08:39 +0000 (01:08 +0200)
RtAudio.cpp
doc/doxygen/tutorial.txt
doc/release.txt

index 4a51baf75632e8d52038676d3214d0487c54e630..8e44ba2d4b54f08a070e2e4c8edb99a4f912ab86 100644 (file)
@@ -37,6 +37,7 @@
 */
 /************************************************************************/
 
+// RtAudio: Version 2.1.1, 24 October 2002
 
 #include "RtAudio.h"
 #include <vector>
@@ -1261,44 +1262,10 @@ void RtAudio :: callbackEvent( int streamId, DEVICE_ID deviceId, void *inData, v
 
   MUTEX_LOCK(&stream->mutex);
 
-  if ( stream->mode == INPUT || ( stream->mode == DUPLEX && deviceId == info->device[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 );
-        }
-      }
-      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);
-    }
-  }
-
-  // Don't invoke the user callback if duplex mode, the input/output
-  // devices are different, and this function is called for the output
-  // device.
-  if ( info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[1] ) ) {
+  // 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);
   }
@@ -1339,6 +1306,40 @@ void RtAudio :: callbackEvent( int streamId, DEVICE_ID deviceId, void *inData, v
     }
   }
 
+  if ( stream->mode == INPUT || ( stream->mode == DUPLEX && deviceId == info->device[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 );
+        }
+      }
+      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;
 
@@ -4130,41 +4131,17 @@ void RtAudio :: callbackEvent(int streamId, int bufferIndex, void *inData, void
   }
 
   MUTEX_LOCK(&stream->mutex);
-  int nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
-  int bufferBytes;
-  ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) info->buffers;
-  if ( stream->mode == INPUT || stream->mode == DUPLEX ) {
-
-    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 );
-
-      if ( stream->doByteSwap[1] )
-        byteSwapBuffer(stream->deviceBuffer,
-                       stream->bufferSize * stream->nDeviceChannels[1],
-                       stream->deviceFormat[1]);
-      convertStreamBuffer(stream, INPUT);
-
-    }
-    else { // single channel only
-      memcpy(stream->userBuffer, bufferInfos->buffers[bufferIndex], bufferBytes );
-
-      if (stream->doByteSwap[1])
-        byteSwapBuffer(stream->userBuffer,
-                       stream->bufferSize * stream->nUserChannels[1],
-                       stream->userFormat);
-    }
-  }
 
+  // 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;
   }
 
+  int nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
+  int bufferBytes;
+  ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) info->buffers;
   if ( stream->mode == OUTPUT || stream->mode == DUPLEX ) {
 
     bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[0]);
@@ -4193,6 +4170,32 @@ void RtAudio :: callbackEvent(int streamId, int bufferIndex, void *inData, void
     }
   }
 
+  if ( stream->mode == INPUT || stream->mode == DUPLEX ) {
+
+    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 );
+
+      if ( stream->doByteSwap[1] )
+        byteSwapBuffer(stream->deviceBuffer,
+                       stream->bufferSize * stream->nDeviceChannels[1],
+                       stream->deviceFormat[1]);
+      convertStreamBuffer(stream, INPUT);
+
+    }
+    else { // single channel only
+      memcpy(stream->userBuffer, bufferInfos->buffers[bufferIndex], bufferBytes );
+
+      if (stream->doByteSwap[1])
+        byteSwapBuffer(stream->userBuffer,
+                       stream->bufferSize * stream->nUserChannels[1],
+                       stream->userFormat);
+    }
+  }
+
   if ( !info->usingCallback )
     info->blockTick = false;
 
index db703ac9d40d61ccc096c807085d334a6d0a11a0..49bd4adc265f9c5a2c40486bf0313af95b570cd7 100644 (file)
@@ -41,7 +41,7 @@ The RtAudio API provides both blocking (synchronous) and callback (asyncronous)
 
 \section download Download
 
-Latest Release (7 October 2002): <A href="http://www-ccrma.stanford.edu/~gary/rtaudio/release/rtaudio-2.1.tar.gz">Version 2.1 (165 kB tar/gzipped)</A>
+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 start Getting Started
@@ -467,7 +467,7 @@ In this example, the stream was opened for recording with a non-zero <I>inputCha
 
 \section duplex Duplex Mode
 
-Finally, it is easy to use RtAudio for simultaneous audio input/output, or duplex operation.  In this example, we use a callback function and pass our recorded data directly through for playback.
+Finally, it is easy to use RtAudio for simultaneous audio input/output, or duplex operation.  In this example, we use a callback function and simply scale the input data before sending it back to the output.
 
 \code
 // duplex.cpp
@@ -476,9 +476,18 @@ Finally, it is easy to use RtAudio for simultaneous audio input/output, or duple
 #include "RtAudio.h"
 
 // Pass-through function.
-int pass(char *buffer, int buffer_size, void *)
+int scale(char *buffer, int buffer_size, void *)
 {
-  // Surprise!!  We do nothing to pass the data through.
+  // 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++) {
+    // Do for two channels.
+    *my_buffer++ *= 0.5;
+    *my_buffer++ *= 0.5;
+  }
+
   return 0;
 }
 
@@ -490,7 +499,6 @@ int main()
   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
-  double data[2];
   char input;
   RtAudio *audio;
 
@@ -506,7 +514,7 @@ int main()
 
   try {
     // Set the stream callback function
-    audio->setStreamCallback(stream, &pass, NULL);
+    audio->setStreamCallback(stream, &scale, NULL);
 
     // Start the stream
     audio->startStream(stream);
@@ -537,7 +545,7 @@ int main()
 
 When an RtAudio stream is running in duplex mode (nonzero input <I>AND</I> output channels), the audio write (playback) operation always occurs before the audio read (record) operation.  This sequence allows the use of a single buffer to store both output and input data.
 
-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 played out during the next round of audio processing.
+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.
 
@@ -594,7 +602,7 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
   <TD>CoreAudio</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>CC -Wall -D__MACOSX_CORE__ -o probe probe.cpp RtAudio.cpp -framework CoreAudio -lstdc++ -lpthread</TT></TD>
 </TR>
 <TR>
   <TD>Irix</TD>
index d38825607a2c424f6a41e63b9e1ae595af35ee56..bcd38671967e7ac097141f58c50511dcba5d4f07 100644 (file)
@@ -2,6 +2,10 @@ RtAudio - a C++ class which provides a common API for realtime audio input/outpu
 
 By Gary P. Scavone, 2002.
 
+v2.1.1: (24 October 2002)
+- bug fix in duplex for Mac OS X and Windows ASIO code
+- duplex example change in tutorial 
+
 v2.1: (7 October 2002)
 - added Mac OS X CoreAudio support
 - added Windows ASIO support