src/audio/dart/SDL_dart.c
author Ozkan Sezer <sezeroz@gmail.com>
Sat, 24 Mar 2018 22:25:33 +0300
branchSDL-1.2
changeset 11964 6c37a15030e7
parent 6137 4720145f848b
permissions -rw-r--r--
OS/2 fixes:

- update SDL_platform.h to handle __EMX__
- update SDL_config_os2.h
- fix a typo in SDL_dart.c (bitwise AND, not logical AND)
- fix NULL / NULLHANDLE confusion in SDL_sysloadso.c and SDL_os2fslib.c
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2012 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* Allow access to a raw mixing buffer */
    25 
    26 #include "SDL_timer.h"
    27 #include "SDL_audio.h"
    28 #include "../SDL_audio_c.h"
    29 #include "SDL_dart.h"
    30 
    31 // Buffer states:
    32 #define BUFFER_EMPTY       0
    33 #define BUFFER_USED        1
    34 
    35 typedef struct _tMixBufferDesc {
    36   int              iBufferUsage;      // BUFFER_EMPTY or BUFFER_USED
    37   SDL_AudioDevice *pSDLAudioDevice;
    38 } tMixBufferDesc, *pMixBufferDesc;
    39 
    40 
    41 //---------------------------------------------------------------------
    42 // DARTEventFunc
    43 //
    44 // This function is called by DART, when an event occures, like end of 
    45 // playback of a buffer, etc...
    46 //---------------------------------------------------------------------
    47 LONG APIENTRY DARTEventFunc(ULONG ulStatus,
    48 			    PMCI_MIX_BUFFER pBuffer,
    49 			    ULONG ulFlags)
    50 {
    51   if (ulFlags & MIX_WRITE_COMPLETE)
    52   { // Playback of buffer completed!
    53 
    54     // Get pointer to buffer description
    55     pMixBufferDesc pBufDesc;
    56 
    57     if (pBuffer)
    58     {
    59       pBufDesc = (pMixBufferDesc) (*pBuffer).ulUserParm;
    60 
    61       if (pBufDesc)
    62       {
    63         SDL_AudioDevice *pSDLAudioDevice = pBufDesc->pSDLAudioDevice;
    64         // Set the buffer to be empty
    65         pBufDesc->iBufferUsage = BUFFER_EMPTY;
    66         // And notify DART feeder thread that it will have to work a bit.
    67         if (pSDLAudioDevice)
    68         DosPostEventSem(pSDLAudioDevice->hidden->hevAudioBufferPlayed);
    69       }
    70     }
    71   }
    72   return TRUE;
    73 }
    74 
    75 
    76 int DART_OpenAudio(_THIS, SDL_AudioSpec *spec)
    77 {
    78   Uint16 test_format = SDL_FirstAudioFormat(spec->format);
    79   int valid_datatype = 0;
    80   MCI_AMP_OPEN_PARMS AmpOpenParms;
    81   MCI_GENERIC_PARMS GenericParms;
    82   int iDeviceOrd = 0; // Default device to be used
    83   int bOpenShared = 1; // Try opening it shared
    84   int iBits = 16; // Default is 16 bits signed
    85   int iFreq = 44100; // Default is 44KHz
    86   int iChannels = 2; // Default is 2 channels (Stereo)
    87   int iNumBufs = 2;  // Number of audio buffers: 2
    88   int iBufSize;
    89   int iOpenMode;
    90   int iSilence;
    91   int rc;
    92 
    93   // First thing is to try to open a given DART device!
    94   SDL_memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
    95   // pszDeviceType should contain the device type in low word, and device ordinal in high word!
    96   AmpOpenParms.pszDeviceType = (PSZ) (MCI_DEVTYPE_AUDIO_AMPMIX | (iDeviceOrd << 16));
    97 
    98   iOpenMode = MCI_WAIT | MCI_OPEN_TYPE_ID;
    99   if (bOpenShared) iOpenMode |= MCI_OPEN_SHAREABLE;
   100 
   101   rc = mciSendCommand( 0, MCI_OPEN,
   102                        iOpenMode,
   103 		       (PVOID) &AmpOpenParms, 0);
   104   if (rc!=MCIERR_SUCCESS) // No audio available??
   105     return (-1);
   106   // Save the device ID we got from DART!
   107   // We will use this in the next calls!
   108   iDeviceOrd = AmpOpenParms.usDeviceID;
   109 
   110   // Determine the audio parameters from the AudioSpec
   111   if (spec->channels > 2)
   112     spec->channels = 2;  // !!! FIXME: more than stereo support in OS/2?
   113 
   114   while ((!valid_datatype) && (test_format)) {
   115     spec->format = test_format;
   116     valid_datatype = 1;
   117     switch (test_format) {
   118       case AUDIO_U8:
   119         // Unsigned 8 bit audio data
   120         iSilence = 0x80;
   121         iBits = 8;
   122         break;
   123 
   124       case AUDIO_S16LSB:
   125         // Signed 16 bit audio data
   126         iSilence = 0x00;
   127         iBits = 16;
   128         break;
   129 
   130       default:
   131         valid_datatype = 0;
   132         test_format = SDL_NextAudioFormat();
   133         break;
   134     }
   135   }
   136 
   137   if (!valid_datatype) { // shouldn't happen, but just in case...
   138     // Close DART, and exit with error code!
   139     mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
   140     SDL_SetError("Unsupported audio format");
   141     return (-1);
   142   }
   143 
   144   iFreq = spec->freq;
   145   iChannels = spec->channels;
   146   /* Update the fragment size as size in bytes */
   147   SDL_CalculateAudioSpec(spec);
   148   iBufSize = spec->size;
   149 
   150   // Now query this device if it supports the given freq/bits/channels!
   151   SDL_memset(&(_this->hidden->MixSetupParms), 0, sizeof(MCI_MIXSETUP_PARMS));
   152   _this->hidden->MixSetupParms.ulBitsPerSample = iBits;
   153   _this->hidden->MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
   154   _this->hidden->MixSetupParms.ulSamplesPerSec = iFreq;
   155   _this->hidden->MixSetupParms.ulChannels = iChannels;
   156   _this->hidden->MixSetupParms.ulFormatMode = MCI_PLAY;
   157   _this->hidden->MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
   158   _this->hidden->MixSetupParms.pmixEvent = DARTEventFunc;
   159   rc = mciSendCommand (iDeviceOrd, MCI_MIXSETUP,
   160                        MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
   161                        &(_this->hidden->MixSetupParms), 0);
   162   if (rc!=MCIERR_SUCCESS)
   163   { // The device cannot handle this format!
   164     // Close DART, and exit with error code!
   165     mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
   166     SDL_SetError("Audio device doesn't support requested audio format");
   167     return(-1);
   168   }
   169   // The device can handle this format, so initialize!
   170   rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
   171                       MCI_WAIT | MCI_MIXSETUP_INIT,
   172                       &(_this->hidden->MixSetupParms), 0);
   173   if (rc!=MCIERR_SUCCESS)
   174   { // The device could not be opened!
   175     // Close DART, and exit with error code!
   176     mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
   177     SDL_SetError("Audio device could not be set up");
   178     return(-1);
   179   }
   180   // Ok, the device is initialized.
   181   // Now we should allocate buffers. For this, we need a place where
   182   // the buffer descriptors will be:
   183   _this->hidden->pMixBuffers = (MCI_MIX_BUFFER *) SDL_malloc(sizeof(MCI_MIX_BUFFER)*iNumBufs);
   184   if (!(_this->hidden->pMixBuffers))
   185   { // Not enough memory!
   186     // Close DART, and exit with error code!
   187     mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
   188     SDL_SetError("Not enough memory for audio buffer descriptors");
   189     return(-1);
   190   }
   191   // Now that we have the place for buffer list, we can ask DART for the
   192   // buffers!
   193   _this->hidden->BufferParms.ulNumBuffers = iNumBufs;               // Number of buffers
   194   _this->hidden->BufferParms.ulBufferSize = iBufSize;               // each with this size
   195   _this->hidden->BufferParms.pBufList = _this->hidden->pMixBuffers; // getting descriptorts into this list
   196   // Allocate buffers!
   197   rc = mciSendCommand(iDeviceOrd, MCI_BUFFER,
   198                       MCI_WAIT | MCI_ALLOCATE_MEMORY,
   199                       &(_this->hidden->BufferParms), 0);
   200   if ((rc!=MCIERR_SUCCESS) || (iNumBufs != _this->hidden->BufferParms.ulNumBuffers) || (_this->hidden->BufferParms.ulBufferSize==0))
   201   { // Could not allocate memory!
   202     // Close DART, and exit with error code!
   203     SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
   204     mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
   205     SDL_SetError("DART could not allocate buffers");
   206     return(-1);
   207   }
   208   // Ok, we have all the buffers allocated, let's mark them!
   209   {
   210     int i;
   211     for (i=0; i<iNumBufs; i++)
   212     {
   213       pMixBufferDesc pBufferDesc = (pMixBufferDesc) SDL_malloc(sizeof(tMixBufferDesc));;
   214       // Check if this buffer was really allocated by DART
   215       if ((!(_this->hidden->pMixBuffers[i].pBuffer)) || (!pBufferDesc))
   216       { // Wrong buffer!
   217         // Close DART, and exit with error code!
   218         // Free buffer descriptions
   219         { int j;
   220           for (j=0; j<i; j++) SDL_free((void *)(_this->hidden->pMixBuffers[j].ulUserParm));
   221         }
   222         // and cleanup
   223         mciSendCommand(iDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
   224         SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
   225         mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
   226         SDL_SetError("Error at internal buffer check");
   227         return(-1);
   228       }
   229       pBufferDesc->iBufferUsage = BUFFER_EMPTY;
   230       pBufferDesc->pSDLAudioDevice = _this;
   231 
   232       _this->hidden->pMixBuffers[i].ulBufferLength = _this->hidden->BufferParms.ulBufferSize;
   233       _this->hidden->pMixBuffers[i].ulUserParm = (ULONG) pBufferDesc; // User parameter: Description of buffer
   234       _this->hidden->pMixBuffers[i].ulFlags = 0; // Some stuff should be flagged here for DART, like end of
   235                                             // audio data, but as we will continously send
   236                                             // audio data, there will be no end.:)
   237       SDL_memset(_this->hidden->pMixBuffers[i].pBuffer, iSilence, iBufSize);
   238     }
   239   }
   240   _this->hidden->iNextFreeBuffer = 0;
   241   _this->hidden->iLastPlayedBuf = -1;
   242   // Create event semaphore
   243   if (DosCreateEventSem(NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE)!=NO_ERROR)
   244   {
   245     // Could not create event semaphore!
   246     {
   247       int i;
   248       for (i=0; i<iNumBufs; i++) SDL_free((void *)(_this->hidden->pMixBuffers[i].ulUserParm));
   249     }
   250     mciSendCommand(iDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
   251     SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
   252     mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
   253     SDL_SetError("Could not create event semaphore");
   254     return(-1);
   255   }
   256 
   257   // Store the new settings in global variables
   258   _this->hidden->iCurrDeviceOrd = iDeviceOrd;
   259   _this->hidden->iCurrFreq = iFreq;
   260   _this->hidden->iCurrBits = iBits;
   261   _this->hidden->iCurrChannels = iChannels;
   262   _this->hidden->iCurrNumBufs = iNumBufs;
   263   _this->hidden->iCurrBufSize = iBufSize;
   264 
   265   return (0);
   266 }
   267 
   268 
   269 
   270 void DART_ThreadInit(_THIS)
   271 {
   272   return;
   273 }
   274 
   275 /* This function waits until it is possible to write a full sound buffer */
   276 void DART_WaitAudio(_THIS)
   277 {
   278   int i;
   279   pMixBufferDesc pBufDesc;
   280   ULONG ulPostCount;
   281 
   282   DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
   283   // If there is already an empty buffer, then return now!
   284   for (i=0; i<_this->hidden->iCurrNumBufs; i++)
   285   {
   286     pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[i].ulUserParm;
   287     if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
   288       return;
   289   }
   290   // If there is no empty buffer, wait for one to be empty!
   291   DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // Wait max 1 sec!!! Important!
   292   return;
   293 }
   294 
   295 void DART_PlayAudio(_THIS)
   296 {
   297   int iFreeBuf = _this->hidden->iNextFreeBuffer;
   298   pMixBufferDesc pBufDesc;
   299 
   300   pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
   301   pBufDesc->iBufferUsage = BUFFER_USED;
   302   // Send it to DART to be queued
   303   _this->hidden->MixSetupParms.pmixWrite(_this->hidden->MixSetupParms.ulMixHandle,
   304                                         &(_this->hidden->pMixBuffers[iFreeBuf]), 1);
   305 
   306   _this->hidden->iLastPlayedBuf = iFreeBuf;
   307   iFreeBuf = (iFreeBuf+1) % _this->hidden->iCurrNumBufs;
   308   _this->hidden->iNextFreeBuffer = iFreeBuf;
   309 }
   310 
   311 Uint8 *DART_GetAudioBuf(_THIS)
   312 {
   313   int iFreeBuf;
   314   Uint8 *pResult;
   315   pMixBufferDesc pBufDesc;
   316 
   317   if (_this)
   318   {
   319     if (_this->hidden)
   320     {
   321       iFreeBuf = _this->hidden->iNextFreeBuffer;
   322       pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
   323       
   324       if (pBufDesc)
   325       {
   326         if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
   327         {
   328           pResult = _this->hidden->pMixBuffers[iFreeBuf].pBuffer;
   329           return pResult; 
   330         }
   331       } else
   332         printf("[DART_GetAudioBuf] : ERROR! pBufDesc = %p\n", pBufDesc);
   333     } else
   334       printf("[DART_GetAudioBuf] : ERROR! _this->hidden = %p\n", _this->hidden);
   335   } else
   336     printf("[DART_GetAudioBuf] : ERROR! _this = %p\n", _this);
   337   return NULL;
   338 }
   339 
   340 void DART_WaitDone(_THIS)
   341 {
   342   pMixBufferDesc pBufDesc;
   343   ULONG ulPostCount;
   344   APIRET rc;
   345 
   346   pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[_this->hidden->iLastPlayedBuf].ulUserParm;
   347   rc = NO_ERROR;
   348   while ((pBufDesc->iBufferUsage != BUFFER_EMPTY) && (rc==NO_ERROR))
   349   {
   350     DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
   351     rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important!
   352   }
   353 }
   354 
   355 void DART_CloseAudio(_THIS)
   356 {
   357   MCI_GENERIC_PARMS GenericParms;
   358   int rc;
   359 
   360   // Stop DART playback
   361   rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP, MCI_WAIT, &GenericParms, 0);
   362   if (rc!=MCIERR_SUCCESS)
   363   {
   364 #ifdef SFX_DEBUG_BUILD
   365     printf("Could not stop DART playback!\n");
   366     fflush(stdout);
   367 #endif
   368   }
   369 
   370   // Close event semaphore
   371   DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
   372 
   373   // Free memory of buffer descriptions
   374   {
   375     int i;
   376     for (i=0; i<_this->hidden->iCurrNumBufs; i++) SDL_free((void *)(_this->hidden->pMixBuffers[i].ulUserParm));
   377   }
   378 
   379   // Deallocate buffers
   380   rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
   381 
   382   // Free bufferlist
   383   SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
   384 
   385   // Close dart
   386   rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE, MCI_WAIT, &(GenericParms), 0);
   387 }
   388 
   389 /* Audio driver bootstrap functions */
   390 
   391 int Audio_Available(void)
   392 {
   393   return(1);
   394 }
   395 
   396 void Audio_DeleteDevice(SDL_AudioDevice *device)
   397 {
   398   SDL_free(device->hidden);
   399   SDL_free(device);
   400 }
   401 
   402 SDL_AudioDevice *Audio_CreateDevice(int devindex)
   403 {
   404   SDL_AudioDevice *this;
   405 
   406   /* Initialize all variables that we clean on shutdown */
   407   this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
   408   if ( this )
   409   {
   410     SDL_memset(this, 0, (sizeof *this));
   411     this->hidden = (struct SDL_PrivateAudioData *)
   412       SDL_malloc((sizeof *this->hidden));
   413   }
   414   if ( (this == NULL) || (this->hidden == NULL) )
   415   {
   416     SDL_OutOfMemory();
   417     if ( this )
   418       SDL_free(this);
   419     return(0);
   420   }
   421   SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   422 
   423   /* Set the function pointers */
   424   this->OpenAudio = DART_OpenAudio;
   425   this->ThreadInit = DART_ThreadInit;
   426   this->WaitAudio = DART_WaitAudio;
   427   this->PlayAudio = DART_PlayAudio;
   428   this->GetAudioBuf = DART_GetAudioBuf;
   429   this->WaitDone = DART_WaitDone;
   430   this->CloseAudio = DART_CloseAudio;
   431 
   432   this->free = Audio_DeleteDevice;
   433 
   434   return this;
   435 }
   436 
   437 AudioBootStrap DART_bootstrap = {
   438 	"dart", "OS/2 Direct Audio RouTines (DART)",
   439 	Audio_Available, Audio_CreateDevice
   440 };
   441