drv_osx.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:23k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* MikMod sound library
  2. (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
  3. complete list.
  4. This library is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of
  7. the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  17. 02111-1307, USA.
  18. */
  19. /*==============================================================================
  20.   $Id: drv_osx.c,v 1.5 2004/02/16 17:27:29 raph Exp $
  21.   Driver for output via CoreAudio [MacOS X and Darwin].
  22. ==============================================================================*/
  23. /*
  24.         
  25. Written by Axel Wefers <awe@fruitz-of-dojo.de>
  26.         
  27.         Notes:
  28.         - if HAVE_PTHREAD (config.h) is defined, an extra thread will be created to fill the buffers.
  29.         - if HAVE_PTHREAD is defined, a double buffered method will be used.
  30.         - if an unsupported frequency is selected [md_mixfreq], the native device frequency is used.
  31.         - if mono playback is selected and is not supported by the device, we will emulate mono
  32.           playback.
  33.         - if stereo/surround playback is selected and is not supported by the device, DMODE_STEREO
  34.           will be deactivated automagically.
  35.    
  36.    Bug fixes by Anders F Bjoerklund <afb@algonet.se>
  37.    
  38.     Changes:
  39.     - cleared up in the macro jungle, to see what was going on in the code
  40.     - separated "has ability to use pthreads" from "wish to use pthreads"
  41.     - moved pthread_cond_wait inside the mutex lock, to avoid a deadlock [!]
  42.     - added more than one back buffer, currently left at eight or something
  43.         - gave up on whole thread idea, since it stutters if you rescale a window
  44.     - moved a #pragma mark and added DRV_OSX/MISSING, for non-Darwin compiles
  45.     - added support for float-point buffers, to avoid the conversion and copying
  46. Future ideas: (TODO)
  47. - support possibly partially filled buffers from libmikmod
  48. - clean up the rest of the code and lose even more macros
  49. - use hardware preferred native size for the sample buffers
  50. - Altivec optimizations of the various vector transforms
  51.     - provide a PPC64 version of the library, for PowerMac G5
  52. */
  53. #ifdef HAVE_CONFIG_H
  54. #include "config.h"
  55. #endif
  56. #include "mikmod_internals.h"
  57. #ifdef DRV_OSX
  58. //_______________________________________________________________________________________________INCLUDES
  59. #pragma mark INCLUDES
  60. #include <CoreAudio/AudioHardware.h>
  61. #pragma mark -
  62. //________________________________________________________________________________________________DEFINES
  63. #pragma mark DEFINES
  64. #define SOUND_BUFFER_SCALE_8BIT (1.0f / 128.0f)   /* CoreAudio requires float input.    */
  65. #define SOUND_BUFFER_SCALE_16BIT (1.0f / 32768.0f) /* CoreAudio requires float input.    */
  66. #define SOUND_BUFFER_SIZE 4096 /* The buffersize libmikmod will use. */
  67. #define USE_FILL_THREAD 0 /* Use an extra thread to fill the buffers ? */
  68. #ifndef HAVE_PTHREAD
  69. #undef USE_FILL_THREAD
  70. #define USE_FILL_THREAD 0 /* must have pthread supports to use thread */
  71. #endif
  72. #define NUMBER_BACK_BUFFERS 8 /* Number of back buffers for the thread */
  73. #define DEBUG_TRACE_THREADS 0
  74. #pragma mark -
  75. //_________________________________________________________________________________________________MACROS
  76. #pragma mark MACROS
  77. #define CHECK_ERROR(ERRNO, RESULT) if (RESULT != kAudioHardwareNoError)          
  78.                                         {              
  79.                                             _mm_errno = ERRNO;      
  80.                                             return(1);      
  81.                                         }
  82. #define SET_PROPS() if (AudioDeviceSetProperty (gSoundDeviceID, NULL, 0, 0,    
  83.                                                     kAudioDevicePropertyStreamFormat,    
  84.                                                     myPropertySize, &mySoundBasicDescription))    
  85.                         {    
  86.                             CHECK_ERROR    
  87.                             (    
  88.                                 MMERR_OSX_BAD_PROPERTY,    
  89.                                 AudioDeviceGetProperty (gSoundDeviceID, 0, 0,    
  90.                                                         kAudioDevicePropertyStreamFormat,    
  91.                                                         &myPropertySize, &mySoundBasicDescription) 
  92.                             );    
  93.                         }
  94. #define SET_STEREO()    switch (mySoundBasicDescription.mChannelsPerFrame)     
  95.                         {    
  96.                             case 1:     
  97.                                 md_mode &= ~DMODE_STEREO;    
  98.                                 gBufferMono2Stereo = 0;    
  99.                                 break;    
  100.                             case 2:    
  101.                                 if (md_mode & DMODE_STEREO)    
  102.                                     gBufferMono2Stereo = 0;    
  103.                                 else    
  104.                                     gBufferMono2Stereo = 1;    
  105.                                 break;    
  106.                             default:    
  107.                                 _mm_errno = MMERR_OSX_SET_STEREO;    
  108.                                 return(1);    
  109.                         }
  110. #define FILL_BUFFER(_buffer,_size)
  111. if (Player_Paused())    
  112.                                 {    
  113.                                     MUTEX_LOCK (vars);    
  114.                                     VC_SilenceBytes ((SBYTE*) (_buffer), (ULONG) (_size));    
  115.                                     MUTEX_UNLOCK (vars);    
  116.                                 }    
  117.                                 else    
  118.                                 {    
  119.                                     MUTEX_LOCK (vars);    
  120.                                     VC_WriteBytes ((SBYTE*) (_buffer), (ULONG) ((_size)));    
  121.                                     MUTEX_UNLOCK (vars);    
  122.                                 }
  123. #pragma mark -
  124. //_________________________________________________________________________________________________GLOBALS
  125. #pragma mark GLOBALS
  126. #if USE_FILL_THREAD
  127. static pthread_t gBufferFillThread;
  128. static pthread_mutex_t gBufferMutex;
  129. static pthread_cond_t gBufferCondition;
  130. static Boolean gExitBufferFillThread = 0;
  131. static int gCurrentPlayBuffer;
  132. static int gCurrentFillBuffer;
  133. static unsigned char *gSoundBackBuffer[NUMBER_BACK_BUFFERS];
  134. #else
  135. static unsigned char  *gSoundBuffer = NULL;
  136. #endif /* USE_FILL_THREAD */
  137. static AudioDeviceID  gSoundDeviceID;
  138. static UInt32 gInBufferSize;
  139. static Boolean gIOProcIsInstalled = 0,
  140.                                 gDeviceHasStarted = 0,
  141.                                 gBufferMono2Stereo = 0;
  142. static OSStatus (*gAudioIOProc) (AudioDeviceID, const AudioTimeStamp *,
  143.                                                  const AudioBufferList *, const AudioTimeStamp *,
  144.                                                  AudioBufferList *, const AudioTimeStamp *, void *);
  145. #pragma mark -
  146. //____________________________________________________________________________________FUNCTION_pROTOTYPES
  147. #pragma mark FUNCTION PROTOTYPES
  148. #if USE_FILL_THREAD
  149. static void * OSX_FillBuffer (void *);
  150. #endif /* USE_FILL_THREAD */
  151. static OSStatus OSX_AudioIOProc8Bit (AudioDeviceID, const AudioTimeStamp *,
  152. const AudioBufferList *, const AudioTimeStamp *, AudioBufferList *,
  153. const AudioTimeStamp *, void *);
  154. static OSStatus OSX_AudioIOProc16Bit (AudioDeviceID, const AudioTimeStamp *,
  155. const AudioBufferList *, const AudioTimeStamp *, AudioBufferList *,
  156. const AudioTimeStamp *, void *);
  157. static OSStatus OSX_AudioIOProcFloat (AudioDeviceID, const AudioTimeStamp *,
  158. const AudioBufferList *, const AudioTimeStamp *, AudioBufferList *,
  159. const AudioTimeStamp *, void *);
  160. static BOOL OSX_IsPresent (void);
  161. static BOOL OSX_Init (void);
  162. static void OSX_Exit (void);
  163. static BOOL OSX_PlayStart (void);
  164. static void OSX_PlayStop (void);
  165. static void OSX_Update (void);
  166. #pragma mark -
  167. //_______________________________________________________________________________________OSX_FillBuffer()
  168. #if USE_FILL_THREAD
  169. static void * OSX_FillBuffer (void *theID)
  170. {
  171.     unsigned char *buffer;
  172.     int done;
  173.     
  174.     while (1)
  175.     {
  176. done = 0;
  177. while (!done)
  178. {
  179.         // shall the thread exit?
  180.         if (gExitBufferFillThread) pthread_exit (NULL);
  181. pthread_mutex_lock (&gBufferMutex);
  182.        
  183.         if ((gCurrentFillBuffer+1) % NUMBER_BACK_BUFFERS != gCurrentPlayBuffer)
  184.         {
  185.           #if DEBUG_TRACE_THREADS
  186. fprintf(stderr,"filling buffer #%dn", gCurrentFillBuffer);
  187.   #endif
  188.         buffer = gSoundBackBuffer[gCurrentFillBuffer];
  189.           if (++gCurrentFillBuffer >= NUMBER_BACK_BUFFERS)
  190.      gCurrentFillBuffer = 0;
  191. // fill the buffer...
  192. FILL_BUFFER (buffer, gInBufferSize);
  193. }
  194.         else
  195.         {
  196.         // we are caught up now, give it a rest
  197.         done = 1;
  198.         }
  199.        
  200.         pthread_mutex_unlock (&gBufferMutex);
  201.         }
  202.        
  203. pthread_mutex_lock (&gBufferMutex);
  204.        
  205.          // wait for the next buffer-fill request...
  206. pthread_cond_wait (&gBufferCondition, &gBufferMutex);
  207. pthread_mutex_unlock (&gBufferMutex);
  208.     }
  209.     return (theID);
  210. }
  211. #endif /* USE_FILL_THREAD */
  212. //__________________________________________________________________________________OSX_AudioIOProc8Bit()
  213. static OSStatus OSX_AudioIOProc8Bit (AudioDeviceID  inDevice,
  214.                                      const AudioTimeStamp  *inNow,
  215.                                      const AudioBufferList  *inInputData,
  216.                                      const AudioTimeStamp  *inInputTime,
  217.                                      AudioBufferList *outOutputData, 
  218.                                      const AudioTimeStamp *inOutputTime,
  219.                                      void  *inClientData)
  220. {
  221.     register float *myOutBuffer = (float *) outOutputData->mBuffers[0].mData;
  222.     register UInt8 *myInBuffer;
  223.     register UInt32 i;
  224. #if USE_FILL_THREAD
  225.     pthread_mutex_lock (&gBufferMutex);
  226.  
  227.   #if DEBUG_TRACE_THREADS
  228.   fprintf(stderr,"playing buffer #%dn", gCurrentPlayBuffer);
  229.   #endif
  230.    
  231.     myInBuffer = (UInt8 *) gSoundBackBuffer[gCurrentPlayBuffer];
  232.   if (++gCurrentPlayBuffer >= NUMBER_BACK_BUFFERS)
  233.      gCurrentPlayBuffer = 0;
  234.     // fill her up, please ...
  235.     pthread_cond_signal (&gBufferCondition);
  236. pthread_mutex_unlock (&gBufferMutex);
  237. #else
  238. myInBuffer = (UInt8 *) gSoundBuffer;
  239. FILL_BUFFER(gSoundBuffer, gInBufferSize);
  240. #endif /* USE_FILL_THREAD */
  241. if (gBufferMono2Stereo)
  242. {
  243. for (i = 0; i < SOUND_BUFFER_SIZE >> 1; i++)
  244. {
  245. myOutBuffer[1] = myOutBuffer[0] = (*myInBuffer++) * SOUND_BUFFER_SCALE_8BIT;
  246.             myOutBuffer+=2;
  247.         }
  248.     }
  249.     else
  250.     {
  251.      for (i = 0; i < SOUND_BUFFER_SIZE; i++)
  252.         {
  253.          *myOutBuffer++ = (*myInBuffer++) * SOUND_BUFFER_SCALE_8BIT;
  254.         }
  255. }
  256. return 0;
  257. }
  258. //_________________________________________________________________________________OSX_AudioIOProc16Bit()
  259. static OSStatus OSX_AudioIOProc16Bit (AudioDeviceID  inDevice,
  260.                                       const AudioTimeStamp  *inNow,
  261.                                       const AudioBufferList  *inInputData,
  262.                                       const AudioTimeStamp  *inInputTime,
  263.                                       AudioBufferList *outOutputData, 
  264.                                       const AudioTimeStamp *inOutputTime,
  265.                                       void  *inClientData)
  266. {
  267.     register float *myOutBuffer = (float *) outOutputData->mBuffers[0].mData;
  268.     register SInt16 *myInBuffer;
  269.     register UInt32 i;
  270. #if USE_FILL_THREAD
  271. pthread_mutex_lock (&gBufferMutex);
  272.  
  273.   #if DEBUG_TRACE_THREADS
  274.   fprintf(stderr,"playing buffer #%dn", gCurrentPlayBuffer);
  275.   #endif
  276.                                       
  277.   myInBuffer = (SInt16 *) gSoundBackBuffer[gCurrentPlayBuffer];
  278.   if (++gCurrentPlayBuffer >= NUMBER_BACK_BUFFERS)
  279.      gCurrentPlayBuffer = 0;
  280. // ... and check the oil too
  281.     pthread_cond_signal (&gBufferCondition);
  282. pthread_mutex_unlock (&gBufferMutex);
  283. #else
  284. myInBuffer = (SInt16 *) gSoundBuffer;
  285. FILL_BUFFER(gSoundBuffer, gInBufferSize);
  286. #endif /* USE_FILL_THREAD */
  287. if (gBufferMono2Stereo)
  288. {
  289. for (i = 0; i < SOUND_BUFFER_SIZE >> 1; i++)
  290. {
  291. myOutBuffer[1] = myOutBuffer[0] = (*myInBuffer++) * SOUND_BUFFER_SCALE_16BIT;
  292.             myOutBuffer+=2;
  293.         }
  294.     }
  295.     else
  296.     {
  297.      for (i = 0; i < SOUND_BUFFER_SIZE; i++)
  298.         {
  299.          *myOutBuffer++ = (*myInBuffer++) * SOUND_BUFFER_SCALE_16BIT;
  300.         }
  301. }
  302. return 0;
  303. }
  304. //_________________________________________________________________________________OSX_AudioIOProcFloat()
  305. static OSStatus OSX_AudioIOProcFloat (AudioDeviceID  inDevice,
  306.                                       const AudioTimeStamp  *inNow,
  307.                                       const AudioBufferList  *inInputData,
  308.                                       const AudioTimeStamp  *inInputTime,
  309.                                       AudioBufferList *outOutputData, 
  310.                                       const AudioTimeStamp *inOutputTime,
  311.                                       void  *inClientData)
  312. {
  313.     register float *myOutBuffer = (float *) outOutputData->mBuffers[0].mData;
  314.     register float *myInBuffer;
  315.     register UInt32 i;
  316. #if USE_FILL_THREAD
  317. pthread_mutex_lock (&gBufferMutex);
  318.  
  319.   #if DEBUG_TRACE_THREADS
  320.   fprintf(stderr,"playing buffer #%dn", gCurrentPlayBuffer);
  321.   #endif
  322.                                       
  323.   myInBuffer = (float *) gSoundBackBuffer[gCurrentPlayBuffer];
  324.   if (++gCurrentPlayBuffer >= NUMBER_BACK_BUFFERS)
  325.      gCurrentPlayBuffer = 0;
  326. // ... perhaps wash the windshield
  327.     pthread_cond_signal (&gBufferCondition);
  328. pthread_mutex_unlock (&gBufferMutex);
  329. #else
  330. // avoid copy, if no conversion needed
  331. myInBuffer = (gBufferMono2Stereo) ? (float *) gSoundBuffer : myOutBuffer;
  332. FILL_BUFFER( myInBuffer, gInBufferSize);
  333. #endif /* USE_FILL_THREAD */
  334. if (gBufferMono2Stereo)
  335. {
  336. for (i = 0; i < SOUND_BUFFER_SIZE >> 1; i++)
  337. {
  338. myOutBuffer[1] = myOutBuffer[0] = *myInBuffer++;
  339.             myOutBuffer+=2;
  340.         }
  341.     }
  342.     else if (myInBuffer != myOutBuffer)
  343.     {
  344.      for (i = 0; i < SOUND_BUFFER_SIZE; i++)
  345.         {
  346.          *myOutBuffer++ = *myInBuffer++;
  347.         }
  348. }
  349. return 0;
  350. }
  351. //________________________________________________________________________________________OSX_IsPresent()
  352. static BOOL OSX_IsPresent (void)
  353. {
  354.     // bad boy... have to find a better way!
  355.     if (!AudioHardwareGetProperty)
  356.         return (0);
  357.     return (1);
  358. }
  359. //_____________________________________________________________________________________________OSX_Init()
  360. static BOOL OSX_Init (void)
  361. {
  362.     AudioStreamBasicDescription mySoundBasicDescription;
  363.     UInt32 myPropertySize, myBufferByteCount;
  364.     // get the device...
  365.     myPropertySize = sizeof (gSoundDeviceID);
  366.     CHECK_ERROR
  367.     (
  368.         MMERR_DETECTING_DEVICE,
  369.         AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice,
  370.                                   &myPropertySize, &gSoundDeviceID)
  371.     );
  372.     if (gSoundDeviceID == kAudioDeviceUnknown)
  373.     {
  374.         _mm_errno = MMERR_OSX_UNKNOWN_DEVICE;
  375.         return(1);
  376.     }
  377.     // get the device format...
  378.     myPropertySize = sizeof (mySoundBasicDescription);
  379.     CHECK_ERROR
  380.     (
  381.         MMERR_OSX_BAD_PROPERTY,
  382.         AudioDeviceGetProperty (gSoundDeviceID, 0, 0, kAudioDevicePropertyStreamFormat,
  383.                                 &myPropertySize, &mySoundBasicDescription)
  384.     );
  385.     // set up basic md_mode, just to be secure...
  386.     md_mode |= DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;
  387.     // try the selected mix frequency, if failure, fall back to native frequency...
  388.     if (mySoundBasicDescription.mSampleRate != md_mixfreq)
  389.     {
  390.         mySoundBasicDescription.mSampleRate = md_mixfreq;
  391.         SET_PROPS ();
  392.         md_mixfreq = mySoundBasicDescription.mSampleRate;
  393.     }
  394.     // try selected channels, if failure select native channels...
  395.     switch (md_mode & DMODE_STEREO)
  396.     {
  397.         case 0:
  398.             if (mySoundBasicDescription.mChannelsPerFrame != 1)
  399.             {
  400.                 mySoundBasicDescription.mChannelsPerFrame = 1;
  401.                 SET_PROPS ();
  402.                 SET_STEREO ();
  403.             }
  404.             break;
  405.         case 1:
  406.             if (mySoundBasicDescription.mChannelsPerFrame != 2)
  407.             {
  408.                 mySoundBasicDescription.mChannelsPerFrame = 2;
  409.                 SET_PROPS();
  410.                 SET_STEREO();
  411.             }
  412.             break;
  413.     }
  414.     // linear PCM is required...
  415.     if (mySoundBasicDescription.mFormatID != kAudioFormatLinearPCM)
  416.     {
  417.         _mm_errno = MMERR_OSX_UNSUPPORTED_FORMAT;
  418.         return(1);
  419.     }
  420.     // prepare the buffers...
  421.     if (gBufferMono2Stereo)
  422.     {
  423.         gInBufferSize = SOUND_BUFFER_SIZE >> 1;
  424.     }
  425.     else
  426.     {
  427.         gInBufferSize = SOUND_BUFFER_SIZE;
  428.     }
  429.     if (md_mode & DMODE_FLOAT)
  430.     {
  431.         gInBufferSize *= sizeof(float);
  432.         gAudioIOProc = OSX_AudioIOProcFloat;
  433.     }
  434.     else if (md_mode & DMODE_16BITS)
  435.     {
  436.         gInBufferSize *= sizeof(SInt16);
  437.         gAudioIOProc = OSX_AudioIOProc16Bit;
  438.     }
  439.     else
  440.     {
  441.         gInBufferSize *= sizeof(UInt8);
  442.         gAudioIOProc = OSX_AudioIOProc8Bit;
  443.     }
  444.     myBufferByteCount = SOUND_BUFFER_SIZE * sizeof(float);
  445.     CHECK_ERROR
  446.     (
  447.         MMERR_OSX_BUFFER_ALLOC,
  448.         AudioDeviceSetProperty (gSoundDeviceID, NULL, 0, 0, kAudioDevicePropertyBufferSize,
  449.                                 sizeof(myBufferByteCount), &myBufferByteCount)
  450.     );
  451.     
  452.     // add our audio IO procedure....
  453.     CHECK_ERROR
  454.     (
  455.         MMERR_OSX_ADD_IO_PROC,
  456.         AudioDeviceAddIOProc (gSoundDeviceID, gAudioIOProc, NULL)
  457.     );
  458.     gIOProcIsInstalled = 1;
  459.  #if !USE_FILL_THREAD
  460.    // get the buffer memory...
  461.     if ((gSoundBuffer = malloc(gInBufferSize)) == NULL)
  462.     {
  463.         _mm_errno = MMERR_OUT_OF_MEMORY;
  464.         return (1);
  465.     }
  466. #else
  467.     // some thread init...
  468.     if (pthread_mutex_init (&gBufferMutex, NULL) ||
  469.         pthread_cond_init (&gBufferCondition, NULL))
  470.     {
  471.         _mm_errno = MMERR_OSX_PTHREAD;
  472.         return (1);
  473.     }
  474.     
  475.     {
  476.      int i;
  477.     
  478.      for (i = 0; i < NUMBER_BACK_BUFFERS; i++)
  479.    if ((gSoundBackBuffer[i] = malloc(gInBufferSize)) == NULL)
  480.      {
  481.          _mm_errno = MMERR_OUT_OF_MEMORY;
  482.          return (1);
  483.      }
  484.     
  485.      gCurrentPlayBuffer = 0;
  486. gCurrentFillBuffer = 0;
  487. }
  488. #endif /* USE_FILL_THREAD */
  489.     // last not least init mikmod...
  490.     return VC_Init ();
  491. }
  492. //_____________________________________________________________________________________________OSX_Exit()
  493. static void OSX_Exit (void)
  494. {
  495.     if (gDeviceHasStarted)
  496.     {
  497.         // stop the audio device...
  498.         AudioDeviceStop (gSoundDeviceID, gAudioIOProc);
  499.         gDeviceHasStarted = 0;
  500. #if USE_FILL_THREAD
  501.         // finish the fill buffer thread off...
  502.         pthread_mutex_lock (&gBufferMutex);
  503.         gExitBufferFillThread = 1;
  504.         pthread_mutex_unlock (&gBufferMutex);
  505.         pthread_cond_signal(&gBufferCondition);
  506.         pthread_join (gBufferFillThread, NULL);
  507.     }
  508.     
  509.     // destroy other thread related stuff...
  510.     pthread_mutex_destroy (&gBufferMutex);
  511.     pthread_cond_destroy (&gBufferCondition);
  512. #else
  513.     }
  514. #endif /* USE_FILL_THREAD */
  515.     // remove the audio IO proc...
  516.     if (gIOProcIsInstalled)
  517.     {
  518.         AudioDeviceRemoveIOProc (gSoundDeviceID, gAudioIOProc);
  519.         gIOProcIsInstalled = 0;
  520.     }
  521. #if !USE_FILL_THREAD
  522.  
  523.     // free up the sound buffer...
  524.     if (gSoundBuffer)
  525.     {
  526.         free (gSoundBuffer);
  527.         gSoundBuffer = NULL;
  528.     }
  529. #else
  530. {
  531. int i;
  532.     for ( i = 0; i < NUMBER_BACK_BUFFERS; i++ )
  533.     {
  534. // free up the back buffer...
  535. if (gSoundBackBuffer[i])
  536. {
  537. free (gSoundBackBuffer[i]);
  538. gSoundBackBuffer[i] = NULL;
  539. }
  540.     }
  541.     }
  542. #endif /* USE_FILL_THREAD */
  543.     
  544.     VC_Exit ();
  545. }
  546. //________________________________________________________________________________________OSX_PlayStart()
  547. static BOOL OSX_PlayStart (void)
  548. {
  549.     // start virtch...
  550.     if (VC_PlayStart ())
  551.     {
  552.         return (1);
  553.     }
  554.     
  555.     // just for security: audio device already playing?
  556.     if (gDeviceHasStarted) return (0);
  557. #if USE_FILL_THREAD
  558.     // start the buffer fill thread...
  559.     gExitBufferFillThread = 0;
  560.     if (pthread_create (&gBufferFillThread, NULL, OSX_FillBuffer , NULL))
  561.     {
  562.         _mm_errno = MMERR_OSX_PTHREAD;
  563.         return (1);
  564.     }
  565. #endif /* USE_FILL_THREAD */
  566.     // start the audio IO Proc...
  567.     if (AudioDeviceStart (gSoundDeviceID, gAudioIOProc))
  568.     {
  569.         _mm_errno = MMERR_OSX_DEVICE_START;
  570.         return (1);
  571.     }
  572.     gDeviceHasStarted = 1;
  573.     
  574.     return (0);
  575. }
  576. //_________________________________________________________________________________________OSX_PlayStop()
  577. static void OSX_PlayStop (void)
  578. {
  579.  
  580.     if (gDeviceHasStarted)
  581.     {
  582.         // stop the audio IO Proc...
  583.         AudioDeviceStop (gSoundDeviceID, gAudioIOProc);
  584.         gDeviceHasStarted = 0;
  585. #if USE_FILL_THREAD
  586.         // finish the fill buffer thread off...
  587.         pthread_mutex_lock (&gBufferMutex);
  588.         gExitBufferFillThread = 1;
  589.         pthread_mutex_unlock (&gBufferMutex);
  590.         pthread_cond_signal (&gBufferCondition);
  591.         pthread_join (gBufferFillThread, NULL);
  592.     
  593. #endif /* USE_FILL_THREAD */
  594.     }
  595.     
  596.     // finally tell virtch that playback has stopped...
  597.     VC_PlayStop ();
  598. }
  599. //___________________________________________________________________________________________OSX_Update()
  600. static void OSX_Update (void)
  601. {
  602.     // do nothing...
  603. }
  604. //________________________________________________________________________________________________drv_osx
  605. MIKMODAPI MDRIVER drv_osx={
  606.         NULL,
  607.         "CoreAudio Driver",
  608.         "CoreAudio Driver v2.1",
  609.         0,255,
  610.         "osx",
  611.         NULL,
  612.         NULL,
  613.         OSX_IsPresent,
  614.         VC_SampleLoad,
  615.         VC_SampleUnload,
  616.         VC_SampleSpace,
  617.         VC_SampleLength,
  618.         OSX_Init,
  619.         OSX_Exit,
  620.         NULL,
  621.         VC_SetNumVoices,
  622.         OSX_PlayStart,
  623.         OSX_PlayStop,
  624.         OSX_Update,
  625.         NULL,
  626.         VC_VoiceSetVolume,
  627.         VC_VoiceGetVolume,
  628.         VC_VoiceSetFrequency,
  629.         VC_VoiceGetFrequency,
  630.         VC_VoiceSetPanning,
  631.         VC_VoiceGetPanning,
  632.         VC_VoicePlay,
  633.         VC_VoiceStop,
  634.         VC_VoiceStopped,
  635.         VC_VoiceGetPosition,
  636.         VC_VoiceRealVolume
  637. };
  638. //____________________________________________________________________________________________________EOF
  639. #else
  640. MISSING(drv_osx);
  641. #endif /* DRV_OSX */