Advertisement
Kitomas

kit_w32_audio.c with winmm

Jun 29th, 2023
854
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.52 KB | Source Code | 0 0
  1. //(compile with kernel32, ole32, and optionally winmm (define "KIT_AUDIO_USE_WINMM" to use waveIn/Out functionality)
  2.  /**
  3.   * \file kit_w32_audio.c
  4.   * \brief Header file for KIT Win32's audio module
  5.   */
  6. #ifndef KIT_AUDIO_USE_WINMM
  7. #  define KIT_AUDIO_USE_WINMM
  8. #endif
  9. #include <kit_w32_audio.h>
  10.  
  11.  
  12. static inline int _kit_audioCountBits(long long unsigned int bitState){
  13.   int bitCount=0;
  14.   while(bitState){ bitCount+=bitState&1; bitState>>=1; }
  15.   return bitCount;
  16. }
  17.  
  18.  
  19.  
  20. /* WASAPI */
  21.  
  22.  
  23.  
  24. /* WINMM */
  25. #ifdef KIT_AUDIO_USE_WINMM
  26.  
  27.  
  28. //thread process to trigger user-defined callback, before writing to waveOut
  29. DWORD WINAPI _kit_audioWaveOutFillBuffer(LPVOID device_void_ptr){
  30.   kit_audioDevice* device=device_void_ptr;
  31.   KIT_AUDIO_AUDITANDLOCK(device,KIT_AUDIO_DEVTYPE_WAVEOUT,0);
  32.   device->src.callback(device->src.userdata,
  33.                        device->_stream,
  34.                        device->src.buffer_len
  35.   );
  36.   unsigned int buffer_len=device->cvt.buffer_len, which=device->_which;
  37.   uint8_t* dst_u8; int16_t* dst_i16; float* src_flt;
  38.   float vol_l=device->volume[0], vol_r=device->volume[device->src.channels-1];
  39.   switch(device->src.format){
  40.   case KIT_AUDIO_FMT_U8:
  41.     dst_u8=device->_buffer[which];
  42.     memcpy(dst_u8, device->_stream, device->cvt.buffer_size);
  43.     for(unsigned int i=0; i<buffer_len;){
  44.       dst_u8[i]*=vol_l; ++i;
  45.       dst_u8[i]*=vol_r; ++i;
  46.     }
  47.     break;
  48.   case KIT_AUDIO_FMT_I16:
  49.     dst_i16=device->_buffer[which];
  50.     memcpy(dst_i16, device->_stream, device->cvt.buffer_size);
  51.     for(unsigned int i=0; i<buffer_len;){
  52.       dst_i16[i]*=vol_l; ++i;
  53.       dst_i16[i]*=vol_r; ++i;
  54.     }
  55.     break;
  56.   case KIT_AUDIO_FMT_F32: //internally converted to i16
  57.     src_flt=device->_stream;
  58.     dst_i16=device->_buffer[which];
  59.     for(unsigned int i=0; i<buffer_len;){
  60.       dst_i16[i]=(int16_t)(src_flt[i]*32767.0f*vol_l); ++i;
  61.       dst_i16[i]=(int16_t)(src_flt[i]*32767.0f*vol_r); ++i;
  62.     }
  63.     break;
  64.   default: goto skip; //invalid format
  65.   }
  66.   waveOutWrite(device->_handle_waveOut, &device->_buffer_info[which], sizeof(WAVEHDR));
  67.   device->_which^=1; //switch output buffer for next time this function is called
  68.   skip:
  69.   KIT_AUDIO_UNLOCK(device);
  70.   return 0;
  71. }
  72.  
  73.  
  74. void CALLBACK _kit_audioWaveOutProc(HWAVEOUT waveOutHandle, UINT message, DWORD_PTR instance,
  75.                                     DWORD_PTR param1, DWORD_PTR param2){
  76.   kit_audioDevice* device=(kit_audioDevice*)instance;
  77.   switch(message){
  78.   case WOM_CLOSE: //closing has its own function, and is handled separately
  79.   case WOM_OPEN: return;
  80.   case WOM_DONE:
  81.     _KIT_AUDIO_LOCKCALLBACKTHREAD(device);
  82.     _kit_audioWaveOutFillBuffer(device);
  83.     _KIT_AUDIO_UNLOCKCALLBACKTHREAD(device);
  84.   }
  85. }
  86.  
  87. //public waveout functions
  88.  
  89. uint32_t kit_audioWaveOutPlay(kit_audioDevice* device, int playState){
  90.   playState&=1; //only keep bit 0
  91.   KIT_AUDIO_AUDITANDLOCK(device,KIT_AUDIO_DEVTYPE_WAVEOUT,MMSYSERR_INVALHANDLE);
  92.   if(device->_playing==playState){ KIT_AUDIO_UNLOCK(device); return MMSYSERR_NOERROR; }
  93.   uint32_t result;
  94.   if(playState) result=waveOutRestart(device->_handle_waveOut);
  95.   else result=waveOutPause(device->_handle_waveOut);
  96.   if(result==MMSYSERR_NOERROR){
  97.     device->_playing=playState;
  98.   }
  99.   KIT_AUDIO_UNLOCK(device);
  100.   return result;
  101. }
  102.  
  103. /* bah humbug i'll do this later
  104. uint32_t kit_audioWaveOutReset(kit_audioDevice* device){//, uint32_t timeoutMilliseconds){
  105.   KIT_AUDIO_IFDEVICEINVALID(device,KIT_AUDIO_DEVTYPE_WAVEOUT) return MMSYSERR_INVALHANDLE;
  106.   _KIT_AUDIO_LOCKCALLBACKTHREAD(device);
  107.    //i'll implement an actual timeout later
  108.    //if(!timeoutMilliseconds) timeoutMilliseconds=device->_callback_timeout;
  109.   uint32_t result=0;
  110.   if(device->_callback_thread != NULL){
  111.     result=WaitForSingleObject(device->_callback_thread,INFINITE);//(DWORD)timeoutMilliseconds);
  112.     CloseHandle(device->_callback_thread);
  113.   }
  114.   device->_callback_thread=NULL;
  115.   _KIT_AUDIO_UNLOCKCALLBACKTHREAD(device);
  116.   if(result) return result;
  117.  
  118.   KIT_AUDIO_LOCK(device);
  119.   result=(uint32_t)waveOutReset(device->_handle_waveOut);
  120.   if(result == MMSYSERR_NOERROR){
  121.     device->_playing=0;
  122.     KIT_AUDIO_UNLOCK(device);
  123.     //
  124.     _KIT_AUDIO_LOCKCALLBACKTHREAD(device);
  125.     HANDLE thread=CreateThread(NULL,0,_kit_audioWaveOutFillBuffer,(LPVOID)device,0,NULL);
  126.     CloseHandle(thread); //close handle to thread immediately
  127.     device->_callback_thread=CreateThread(NULL,0,_kit_audioWaveOutFillBuffer,(LPVOID)device,0,NULL);
  128.     _KIT_AUDIO_UNLOCKCALLBACKTHREAD(device);
  129.   } else KIT_AUDIO_UNLOCK(device);
  130.   return result;
  131. }*/
  132.  
  133.  
  134. #define _kit_audioWaveOutOpenERROR(_condition,_rcode,_before) \
  135.   if(_condition){ _before; returnStatus=_rcode; goto skip; }
  136. kit_audioDevice* kit_audioWaveOutOpen(kit_audioSpec* desiredSpec, uint32_t deviceID, int* returnStatus_ptr){
  137.   int returnStatus=0;
  138.   //allocate space for device struct
  139.   kit_audioDevice* device=_kit_audioMalloc(kit_audioDevice,1);
  140.   _kit_audioWaveOutOpenERROR(!device,1,;);
  141.   _kit_audioWaveOutOpenERROR(desiredSpec->callback==NULL,2,_kit_audioFree(device));
  142.   memset(device,0,sizeof(kit_audioDevice));
  143.   device->_magic.num=0x007665446F69647561; //="audioDev\x00"
  144.   device->device_type=KIT_AUDIO_DEVTYPE_WAVEOUT;
  145.   device->cvt = device->src = *desiredSpec; //copy spec info
  146.  
  147.   //fetch capabilities of device
  148.   switch(waveOutGetDevCaps(deviceID,&device->_waveOutCaps,sizeof(WAVEOUTCAPS))){
  149.   case MMSYSERR_BADDEVICEID: _kit_audioWaveOutOpenERROR(1,3,_kit_audioFree(device)); break;
  150.   case MMSYSERR_NODRIVER:    _kit_audioWaveOutOpenERROR(1,4,_kit_audioFree(device)); break;
  151.   case MMSYSERR_NOMEM:       _kit_audioWaveOutOpenERROR(1,5,_kit_audioFree(device)); break;
  152.   case MMSYSERR_NOERROR:; //continue as normal
  153.   }
  154.   _kit_audioWaveOutOpenERROR(!device->_waveOutCaps.dwFormats,6,_kit_audioFree(device));
  155.  
  156.   //is buffer_len a power of 2 (and not equal to 0)?
  157.   _kit_audioWaveOutOpenERROR(!desiredSpec->buffer_len,7,_kit_audioFree(device));
  158.   _kit_audioWaveOutOpenERROR(_kit_audioCountBits(desiredSpec->buffer_len)!=1,8,_kit_audioFree(device));
  159.  
  160.   //simplify type of spec
  161.   union { struct {
  162.     uint8_t   dataType : 1; //0, 1  =  signed 8-bit, signed 16-bit (float handled separately)
  163.     uint8_t   channels : 1; //0, 1  =  mono, stereo
  164.     uint8_t  frequency : 2; //0, 1, 2, 3  =  11025, 22050, 44100, 96000 kHz
  165.     uint8_t   _padding : 4;
  166.    }; uint8_t value;
  167.   } audioSpec={.value=0};
  168.    //check sample rate
  169.   switch(desiredSpec->frequency){
  170.   case 11025: audioSpec.frequency=0; break;
  171.   case 22050: audioSpec.frequency=1; break;
  172.   case 44100: audioSpec.frequency=2; break;
  173.   case 96000: audioSpec.frequency=3; break;
  174.   default: _kit_audioWaveOutOpenERROR(1,9,_kit_audioFree(device));
  175.   }
  176.    //check number of channels
  177.   switch(desiredSpec->channels){
  178.   case 1: audioSpec.channels=0; break;
  179.   case 2: audioSpec.channels=1; break;
  180.   default: _kit_audioWaveOutOpenERROR(1,10,_kit_audioFree(device));
  181.   }
  182.    //check data type (and calculate buffer_size, now that the data type is known)
  183.   device->src.buffer_size=device->src.buffer_len;
  184.   device->cvt.buffer_size=device->cvt.buffer_len;
  185.   switch(desiredSpec->format){
  186.   case KIT_AUDIO_FMT_U8: audioSpec.dataType=0; break;
  187.   case KIT_AUDIO_FMT_F32: //internally converted to int16 before passing to waveOutWrite
  188.     device->src.buffer_size<<=1;
  189.     device->cvt.format=KIT_AUDIO_FMT_I16;
  190.     device->_cvt_needed=1;
  191.   case KIT_AUDIO_FMT_I16:
  192.     device->src.buffer_size<<=1;
  193.     device->cvt.buffer_size<<=1;
  194.     audioSpec.dataType=1;
  195.     break;
  196.   default: _kit_audioWaveOutOpenERROR(1,11,_kit_audioFree(device));
  197.   }
  198.  
  199.   //compare simplified spec with device capabilities
  200.   DWORD caps_fmt=device->_waveOutCaps.dwFormats;
  201.   switch(audioSpec.value){
  202.   case 0b0000: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_1M08 ),12,_kit_audioFree(device)); break; //0: 11025Hz,   mono,  8-bit
  203.   case 0b0001: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_1M16 ),13,_kit_audioFree(device)); break; //1: 11025Hz,   mono, 16-bit
  204.   case 0b0010: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_1S08 ),14,_kit_audioFree(device)); break; //2: 11025Hz, stereo,  8-bit
  205.   case 0b0011: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_1S16 ),15,_kit_audioFree(device)); break; //3: 11025Hz, stereo, 16-bit
  206.   case 0b0100: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_2M08 ),16,_kit_audioFree(device)); break; //4: 22050Hz,   mono,  8-bit
  207.   case 0b0101: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_2M16 ),17,_kit_audioFree(device)); break; //5: 22050Hz,   mono, 16-bit
  208.   case 0b0110: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_2S08 ),18,_kit_audioFree(device)); break; //6: 22050Hz, stereo,  8-bit
  209.   case 0b0111: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_2S16 ),19,_kit_audioFree(device)); break; //7: 22050Hz, stereo, 16-bit
  210.   case 0b1000: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_4M08 ),20,_kit_audioFree(device)); break; //8: 44100Hz,   mono,  8-bit
  211.   case 0b1001: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_4M16 ),21,_kit_audioFree(device)); break; //9: 44100Hz,   mono, 16-bit
  212.   case 0b1010: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_4S08 ),22,_kit_audioFree(device)); break; //A: 44100Hz, stereo,  8-bit
  213.   case 0b1011: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_4S16 ),23,_kit_audioFree(device)); break; //B: 44100Hz, stereo, 16-bit
  214.   case 0b1100: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_96M08),24,_kit_audioFree(device)); break; //C: 96000Hz,   mono,  8-bit
  215.   case 0b1101: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_96M16),25,_kit_audioFree(device)); break; //D: 96000Hz,   mono, 16-bit
  216.   case 0b1110: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_96S08),26,_kit_audioFree(device)); break; //E: 96000Hz, stereo,  8-bit
  217.   case 0b1111: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_96S16),27,_kit_audioFree(device)); break; //F: 96000Hz, stereo, 16-bit
  218.   }
  219.  
  220.   //copy spec info more and prepare device struct more
  221.    //set up WAVEFORMATEX
  222.   device->_info.Format.wFormatTag    =WAVE_FORMAT_PCM;
  223.   device->_info.Format.nChannels     =desiredSpec->channels;
  224.   device->_info.Format.nSamplesPerSec=desiredSpec->frequency;
  225.   device->_info.Format.nBlockAlign   =(audioSpec.dataType+1)*desiredSpec->channels;
  226.   device->_info.Format.wBitsPerSample=(audioSpec.dataType+1)*8;
  227.   device->_info.Format.cbSize        =0;
  228.    //allocate buffers
  229.   device->_stream =_kit_audioMalloc(char,device->src.buffer_size);
  230.   _kit_audioWaveOutOpenERROR(device->_stream==NULL,28, //device
  231.                              _kit_audioFree(device));
  232.   device->_buffer[0]=_kit_audioMalloc(char,device->cvt.buffer_size);
  233.   _kit_audioWaveOutOpenERROR(device->_buffer[0]==NULL,29, //_stream, device
  234.                              _kit_audioFree(device->_stream);
  235.                              _kit_audioFree(device));
  236.   device->_buffer[1]=_kit_audioMalloc(char,device->cvt.buffer_size);
  237.   _kit_audioWaveOutOpenERROR(device->_buffer[1]==NULL,30, //_buffer[0], _stream, device
  238.                              _kit_audioFree(device->_buffer[0]);
  239.                              _kit_audioFree(device->_stream);
  240.                              _kit_audioFree(device));
  241.   device->volume=_kit_audioMalloc(float,device->src.channels);
  242.   _kit_audioWaveOutOpenERROR(device->volume==NULL,31, //_buffer[1], _buffer[0], _stream, device
  243.                              _kit_audioFree(device->_buffer[1]);
  244.                              _kit_audioFree(device->_buffer[0]);
  245.                              _kit_audioFree(device->_stream);
  246.                              _kit_audioFree(device));
  247.   #define _kit_audioWaveOutOpenERRORB(_condition,_rcode,_before) \
  248.     _kit_audioWaveOutOpenERROR(_condition,_rcode, \
  249.                                _kit_audioFree(device->volume); \
  250.                                _kit_audioFree(device->_buffer[1]); \
  251.                                _kit_audioFree(device->_buffer[0]); \
  252.                                _kit_audioFree(device->_stream); \
  253.                                _kit_audioFree(device); _before);
  254.  
  255.   //actually open the device
  256.   switch(waveOutOpen(
  257.     &device->_handle_waveOut,
  258.     deviceID,
  259.     &device->_info.Format, //holds the WAVEFORMATEX struct
  260.     (DWORD_PTR)_kit_audioWaveOutProc, //internal callback
  261.     (DWORD_PTR)device, //user data
  262.     CALLBACK_FUNCTION
  263.   )){ //(MMSYSERR_BADDEVICEID was already handled by waveOutGetDevCaps)
  264.   case MMSYSERR_ALLOCATED: _kit_audioWaveOutOpenERRORB(1,32,;); break;
  265.   case MMSYSERR_NODRIVER:  _kit_audioWaveOutOpenERRORB(1,33,;); break;
  266.   case MMSYSERR_NOMEM:     _kit_audioWaveOutOpenERRORB(1,34,;); break;
  267.   case WAVERR_BADFORMAT:   _kit_audioWaveOutOpenERRORB(1,35,;); break;
  268.   case WAVERR_SYNC:        _kit_audioWaveOutOpenERRORB(1,36,;); break;
  269.   case MMSYSERR_NOERROR: waveOutPause(device->_handle_waveOut);
  270.   }
  271.  
  272.   //set relevant WAVEHDR info (rest is handled by waveOutPrepareHeader)
  273.   for(int i=0; i<2; ++i){
  274.     device->_buffer_info[i].lpData=device->_buffer[i];
  275.     device->_buffer_info[i].dwBufferLength=device->cvt.buffer_size;
  276.     waveOutPrepareHeader(device->_handle_waveOut,&device->_buffer_info[i],sizeof(WAVEHDR));
  277.   }
  278.  
  279.   //initialize mutexes
  280.   InitializeCriticalSection(&device->_mutex);
  281.   InitializeCriticalSection(&device->_callback_mutex);
  282.   //default 10-second timeout, which i should probably edit and add parameters for later
  283.   device->callback_timeout=10000;
  284.   //set volumes to 1
  285.   for(int i=0; i<=audioSpec.channels; ++i) device->volume[i]=1.0f;
  286.   waveOutSetVolume(device->_handle_waveOut,0xFFFFFFFF);
  287.  
  288.   //preemptively fill output buffers
  289.   _KIT_AUDIO_LOCKCALLBACKTHREAD(device);
  290.   HANDLE firstThread=CreateThread(NULL,0,_kit_audioWaveOutFillBuffer,(LPVOID)device,0,NULL);
  291.   CloseHandle(firstThread);
  292.   device->_callback_thread=CreateThread(NULL,0,_kit_audioWaveOutFillBuffer,(LPVOID)device,0,NULL);
  293.   _KIT_AUDIO_UNLOCKCALLBACKTHREAD(device);
  294.  
  295.   //wrap things up
  296.   skip:
  297.   if(returnStatus_ptr != NULL) *returnStatus_ptr=returnStatus;
  298.   if(returnStatus==0) return device;
  299.   else return NULL;
  300. }
  301.  
  302. /* can't get waveOutReset to work :(
  303. #define _kit_audioWaveOutCloseERROR(_rcode) \
  304.   { returnStatus=(_rcode); goto skip; }
  305. uint32_t kit_audioWaveOutClose(kit_audioDevice** device_p){
  306.   printf("function start\n");
  307.   Sleep(50);
  308.   //make sure bad things don't happen if attempting to close device twice
  309.   if(device_p == NULL){
  310.     return 1;
  311.   }
  312.   kit_audioDevice* device=*device_p;
  313.   printf("%p\n",device->_handle_waveOut);
  314.   KIT_AUDIO_AUDITANDLOCK(device,KIT_AUDIO_DEVTYPE_WAVEOUT,2);
  315.  
  316.  
  317.   //MMRESULT resetResult=waveOutReset(device->_handle_waveOut);
  318.   //printf("resetResult=%u\n",resetResult);
  319.  
  320.   uint32_t returnStatus=0;
  321.   for(int i=0; i<2; ++i){
  322.     switch(waveOutUnprepareHeader(device->_handle_waveOut,&device->_buffer_info[i],sizeof(WAVEHDR))){
  323.     case MMSYSERR_INVALHANDLE: _kit_audioWaveOutCloseERROR(3);
  324.     case MMSYSERR_NODRIVER:    _kit_audioWaveOutCloseERROR(4);
  325.     case MMSYSERR_NOMEM:       _kit_audioWaveOutCloseERROR(5);
  326.     case WAVERR_STILLPLAYING:  _kit_audioWaveOutCloseERROR(6);
  327.     case MMSYSERR_NOERROR:;
  328.     }
  329.   }
  330.   switch(waveOutClose(device->_handle_waveOut)){
  331.   case MMSYSERR_INVALHANDLE: _kit_audioWaveOutCloseERROR(7);
  332.   case MMSYSERR_NODRIVER:    _kit_audioWaveOutCloseERROR(8);
  333.   case MMSYSERR_NOMEM:       _kit_audioWaveOutCloseERROR(9);
  334.   case WAVERR_STILLPLAYING:  _kit_audioWaveOutCloseERROR(10);
  335.   case MMSYSERR_NOERROR:;
  336.   }
  337.  
  338.   _kit_audioFree(device->volume);
  339.   _kit_audioFree(device->_buffer[1]);
  340.   _kit_audioFree(device->_buffer[0]);
  341.   _kit_audioFree(device->_stream);
  342.  
  343.   skip:
  344.   KIT_AUDIO_UNLOCK(device);
  345.   if(!returnStatus){
  346.     _kit_audioFree(device);
  347.     *device_p=NULL;
  348.   }
  349.   return returnStatus;
  350. }*/
  351.  
  352.  
  353. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement