Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //(compile with kernel32, ole32, and optionally winmm (define "KIT_AUDIO_USE_WINMM" to use waveIn/Out functionality)
- /**
- * \file kit_w32_audio.c
- * \brief Header file for KIT Win32's audio module
- */
- #ifndef KIT_AUDIO_USE_WINMM
- # define KIT_AUDIO_USE_WINMM
- #endif
- #include <kit_w32_audio.h>
- static inline int _kit_audioCountBits(long long unsigned int bitState){
- int bitCount=0;
- while(bitState){ bitCount+=bitState&1; bitState>>=1; }
- return bitCount;
- }
- /* WASAPI */
- /* WINMM */
- #ifdef KIT_AUDIO_USE_WINMM
- //thread process to trigger user-defined callback, before writing to waveOut
- DWORD WINAPI _kit_audioWaveOutFillBuffer(LPVOID device_void_ptr){
- kit_audioDevice* device=device_void_ptr;
- KIT_AUDIO_AUDITANDLOCK(device,KIT_AUDIO_DEVTYPE_WAVEOUT,0);
- device->src.callback(device->src.userdata,
- device->_stream,
- device->src.buffer_len
- );
- unsigned int buffer_len=device->cvt.buffer_len, which=device->_which;
- uint8_t* dst_u8; int16_t* dst_i16; float* src_flt;
- float vol_l=device->volume[0], vol_r=device->volume[device->src.channels-1];
- switch(device->src.format){
- case KIT_AUDIO_FMT_U8:
- dst_u8=device->_buffer[which];
- memcpy(dst_u8, device->_stream, device->cvt.buffer_size);
- for(unsigned int i=0; i<buffer_len;){
- dst_u8[i]*=vol_l; ++i;
- dst_u8[i]*=vol_r; ++i;
- }
- break;
- case KIT_AUDIO_FMT_I16:
- dst_i16=device->_buffer[which];
- memcpy(dst_i16, device->_stream, device->cvt.buffer_size);
- for(unsigned int i=0; i<buffer_len;){
- dst_i16[i]*=vol_l; ++i;
- dst_i16[i]*=vol_r; ++i;
- }
- break;
- case KIT_AUDIO_FMT_F32: //internally converted to i16
- src_flt=device->_stream;
- dst_i16=device->_buffer[which];
- for(unsigned int i=0; i<buffer_len;){
- dst_i16[i]=(int16_t)(src_flt[i]*32767.0f*vol_l); ++i;
- dst_i16[i]=(int16_t)(src_flt[i]*32767.0f*vol_r); ++i;
- }
- break;
- default: goto skip; //invalid format
- }
- waveOutWrite(device->_handle_waveOut, &device->_buffer_info[which], sizeof(WAVEHDR));
- device->_which^=1; //switch output buffer for next time this function is called
- skip:
- KIT_AUDIO_UNLOCK(device);
- return 0;
- }
- void CALLBACK _kit_audioWaveOutProc(HWAVEOUT waveOutHandle, UINT message, DWORD_PTR instance,
- DWORD_PTR param1, DWORD_PTR param2){
- kit_audioDevice* device=(kit_audioDevice*)instance;
- switch(message){
- case WOM_CLOSE: //closing has its own function, and is handled separately
- case WOM_OPEN: return;
- case WOM_DONE:
- _KIT_AUDIO_LOCKCALLBACKTHREAD(device);
- _kit_audioWaveOutFillBuffer(device);
- _KIT_AUDIO_UNLOCKCALLBACKTHREAD(device);
- }
- }
- //public waveout functions
- uint32_t kit_audioWaveOutPlay(kit_audioDevice* device, int playState){
- playState&=1; //only keep bit 0
- KIT_AUDIO_AUDITANDLOCK(device,KIT_AUDIO_DEVTYPE_WAVEOUT,MMSYSERR_INVALHANDLE);
- if(device->_playing==playState){ KIT_AUDIO_UNLOCK(device); return MMSYSERR_NOERROR; }
- uint32_t result;
- if(playState) result=waveOutRestart(device->_handle_waveOut);
- else result=waveOutPause(device->_handle_waveOut);
- if(result==MMSYSERR_NOERROR){
- device->_playing=playState;
- }
- KIT_AUDIO_UNLOCK(device);
- return result;
- }
- /* bah humbug i'll do this later
- uint32_t kit_audioWaveOutReset(kit_audioDevice* device){//, uint32_t timeoutMilliseconds){
- KIT_AUDIO_IFDEVICEINVALID(device,KIT_AUDIO_DEVTYPE_WAVEOUT) return MMSYSERR_INVALHANDLE;
- _KIT_AUDIO_LOCKCALLBACKTHREAD(device);
- //i'll implement an actual timeout later
- //if(!timeoutMilliseconds) timeoutMilliseconds=device->_callback_timeout;
- uint32_t result=0;
- if(device->_callback_thread != NULL){
- result=WaitForSingleObject(device->_callback_thread,INFINITE);//(DWORD)timeoutMilliseconds);
- CloseHandle(device->_callback_thread);
- }
- device->_callback_thread=NULL;
- _KIT_AUDIO_UNLOCKCALLBACKTHREAD(device);
- if(result) return result;
- KIT_AUDIO_LOCK(device);
- result=(uint32_t)waveOutReset(device->_handle_waveOut);
- if(result == MMSYSERR_NOERROR){
- device->_playing=0;
- KIT_AUDIO_UNLOCK(device);
- //
- _KIT_AUDIO_LOCKCALLBACKTHREAD(device);
- HANDLE thread=CreateThread(NULL,0,_kit_audioWaveOutFillBuffer,(LPVOID)device,0,NULL);
- CloseHandle(thread); //close handle to thread immediately
- device->_callback_thread=CreateThread(NULL,0,_kit_audioWaveOutFillBuffer,(LPVOID)device,0,NULL);
- _KIT_AUDIO_UNLOCKCALLBACKTHREAD(device);
- } else KIT_AUDIO_UNLOCK(device);
- return result;
- }*/
- #define _kit_audioWaveOutOpenERROR(_condition,_rcode,_before) \
- if(_condition){ _before; returnStatus=_rcode; goto skip; }
- kit_audioDevice* kit_audioWaveOutOpen(kit_audioSpec* desiredSpec, uint32_t deviceID, int* returnStatus_ptr){
- int returnStatus=0;
- //allocate space for device struct
- kit_audioDevice* device=_kit_audioMalloc(kit_audioDevice,1);
- _kit_audioWaveOutOpenERROR(!device,1,;);
- _kit_audioWaveOutOpenERROR(desiredSpec->callback==NULL,2,_kit_audioFree(device));
- memset(device,0,sizeof(kit_audioDevice));
- device->_magic.num=0x007665446F69647561; //="audioDev\x00"
- device->device_type=KIT_AUDIO_DEVTYPE_WAVEOUT;
- device->cvt = device->src = *desiredSpec; //copy spec info
- //fetch capabilities of device
- switch(waveOutGetDevCaps(deviceID,&device->_waveOutCaps,sizeof(WAVEOUTCAPS))){
- case MMSYSERR_BADDEVICEID: _kit_audioWaveOutOpenERROR(1,3,_kit_audioFree(device)); break;
- case MMSYSERR_NODRIVER: _kit_audioWaveOutOpenERROR(1,4,_kit_audioFree(device)); break;
- case MMSYSERR_NOMEM: _kit_audioWaveOutOpenERROR(1,5,_kit_audioFree(device)); break;
- case MMSYSERR_NOERROR:; //continue as normal
- }
- _kit_audioWaveOutOpenERROR(!device->_waveOutCaps.dwFormats,6,_kit_audioFree(device));
- //is buffer_len a power of 2 (and not equal to 0)?
- _kit_audioWaveOutOpenERROR(!desiredSpec->buffer_len,7,_kit_audioFree(device));
- _kit_audioWaveOutOpenERROR(_kit_audioCountBits(desiredSpec->buffer_len)!=1,8,_kit_audioFree(device));
- //simplify type of spec
- union { struct {
- uint8_t dataType : 1; //0, 1 = signed 8-bit, signed 16-bit (float handled separately)
- uint8_t channels : 1; //0, 1 = mono, stereo
- uint8_t frequency : 2; //0, 1, 2, 3 = 11025, 22050, 44100, 96000 kHz
- uint8_t _padding : 4;
- }; uint8_t value;
- } audioSpec={.value=0};
- //check sample rate
- switch(desiredSpec->frequency){
- case 11025: audioSpec.frequency=0; break;
- case 22050: audioSpec.frequency=1; break;
- case 44100: audioSpec.frequency=2; break;
- case 96000: audioSpec.frequency=3; break;
- default: _kit_audioWaveOutOpenERROR(1,9,_kit_audioFree(device));
- }
- //check number of channels
- switch(desiredSpec->channels){
- case 1: audioSpec.channels=0; break;
- case 2: audioSpec.channels=1; break;
- default: _kit_audioWaveOutOpenERROR(1,10,_kit_audioFree(device));
- }
- //check data type (and calculate buffer_size, now that the data type is known)
- device->src.buffer_size=device->src.buffer_len;
- device->cvt.buffer_size=device->cvt.buffer_len;
- switch(desiredSpec->format){
- case KIT_AUDIO_FMT_U8: audioSpec.dataType=0; break;
- case KIT_AUDIO_FMT_F32: //internally converted to int16 before passing to waveOutWrite
- device->src.buffer_size<<=1;
- device->cvt.format=KIT_AUDIO_FMT_I16;
- device->_cvt_needed=1;
- case KIT_AUDIO_FMT_I16:
- device->src.buffer_size<<=1;
- device->cvt.buffer_size<<=1;
- audioSpec.dataType=1;
- break;
- default: _kit_audioWaveOutOpenERROR(1,11,_kit_audioFree(device));
- }
- //compare simplified spec with device capabilities
- DWORD caps_fmt=device->_waveOutCaps.dwFormats;
- switch(audioSpec.value){
- case 0b0000: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_1M08 ),12,_kit_audioFree(device)); break; //0: 11025Hz, mono, 8-bit
- case 0b0001: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_1M16 ),13,_kit_audioFree(device)); break; //1: 11025Hz, mono, 16-bit
- case 0b0010: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_1S08 ),14,_kit_audioFree(device)); break; //2: 11025Hz, stereo, 8-bit
- case 0b0011: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_1S16 ),15,_kit_audioFree(device)); break; //3: 11025Hz, stereo, 16-bit
- case 0b0100: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_2M08 ),16,_kit_audioFree(device)); break; //4: 22050Hz, mono, 8-bit
- case 0b0101: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_2M16 ),17,_kit_audioFree(device)); break; //5: 22050Hz, mono, 16-bit
- case 0b0110: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_2S08 ),18,_kit_audioFree(device)); break; //6: 22050Hz, stereo, 8-bit
- case 0b0111: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_2S16 ),19,_kit_audioFree(device)); break; //7: 22050Hz, stereo, 16-bit
- case 0b1000: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_4M08 ),20,_kit_audioFree(device)); break; //8: 44100Hz, mono, 8-bit
- case 0b1001: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_4M16 ),21,_kit_audioFree(device)); break; //9: 44100Hz, mono, 16-bit
- case 0b1010: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_4S08 ),22,_kit_audioFree(device)); break; //A: 44100Hz, stereo, 8-bit
- case 0b1011: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_4S16 ),23,_kit_audioFree(device)); break; //B: 44100Hz, stereo, 16-bit
- case 0b1100: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_96M08),24,_kit_audioFree(device)); break; //C: 96000Hz, mono, 8-bit
- case 0b1101: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_96M16),25,_kit_audioFree(device)); break; //D: 96000Hz, mono, 16-bit
- case 0b1110: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_96S08),26,_kit_audioFree(device)); break; //E: 96000Hz, stereo, 8-bit
- case 0b1111: _kit_audioWaveOutOpenERROR(!(caps_fmt&WAVE_FORMAT_96S16),27,_kit_audioFree(device)); break; //F: 96000Hz, stereo, 16-bit
- }
- //copy spec info more and prepare device struct more
- //set up WAVEFORMATEX
- device->_info.Format.wFormatTag =WAVE_FORMAT_PCM;
- device->_info.Format.nChannels =desiredSpec->channels;
- device->_info.Format.nSamplesPerSec=desiredSpec->frequency;
- device->_info.Format.nBlockAlign =(audioSpec.dataType+1)*desiredSpec->channels;
- device->_info.Format.wBitsPerSample=(audioSpec.dataType+1)*8;
- device->_info.Format.cbSize =0;
- //allocate buffers
- device->_stream =_kit_audioMalloc(char,device->src.buffer_size);
- _kit_audioWaveOutOpenERROR(device->_stream==NULL,28, //device
- _kit_audioFree(device));
- device->_buffer[0]=_kit_audioMalloc(char,device->cvt.buffer_size);
- _kit_audioWaveOutOpenERROR(device->_buffer[0]==NULL,29, //_stream, device
- _kit_audioFree(device->_stream);
- _kit_audioFree(device));
- device->_buffer[1]=_kit_audioMalloc(char,device->cvt.buffer_size);
- _kit_audioWaveOutOpenERROR(device->_buffer[1]==NULL,30, //_buffer[0], _stream, device
- _kit_audioFree(device->_buffer[0]);
- _kit_audioFree(device->_stream);
- _kit_audioFree(device));
- device->volume=_kit_audioMalloc(float,device->src.channels);
- _kit_audioWaveOutOpenERROR(device->volume==NULL,31, //_buffer[1], _buffer[0], _stream, device
- _kit_audioFree(device->_buffer[1]);
- _kit_audioFree(device->_buffer[0]);
- _kit_audioFree(device->_stream);
- _kit_audioFree(device));
- #define _kit_audioWaveOutOpenERRORB(_condition,_rcode,_before) \
- _kit_audioWaveOutOpenERROR(_condition,_rcode, \
- _kit_audioFree(device->volume); \
- _kit_audioFree(device->_buffer[1]); \
- _kit_audioFree(device->_buffer[0]); \
- _kit_audioFree(device->_stream); \
- _kit_audioFree(device); _before);
- //actually open the device
- switch(waveOutOpen(
- &device->_handle_waveOut,
- deviceID,
- &device->_info.Format, //holds the WAVEFORMATEX struct
- (DWORD_PTR)_kit_audioWaveOutProc, //internal callback
- (DWORD_PTR)device, //user data
- CALLBACK_FUNCTION
- )){ //(MMSYSERR_BADDEVICEID was already handled by waveOutGetDevCaps)
- case MMSYSERR_ALLOCATED: _kit_audioWaveOutOpenERRORB(1,32,;); break;
- case MMSYSERR_NODRIVER: _kit_audioWaveOutOpenERRORB(1,33,;); break;
- case MMSYSERR_NOMEM: _kit_audioWaveOutOpenERRORB(1,34,;); break;
- case WAVERR_BADFORMAT: _kit_audioWaveOutOpenERRORB(1,35,;); break;
- case WAVERR_SYNC: _kit_audioWaveOutOpenERRORB(1,36,;); break;
- case MMSYSERR_NOERROR: waveOutPause(device->_handle_waveOut);
- }
- //set relevant WAVEHDR info (rest is handled by waveOutPrepareHeader)
- for(int i=0; i<2; ++i){
- device->_buffer_info[i].lpData=device->_buffer[i];
- device->_buffer_info[i].dwBufferLength=device->cvt.buffer_size;
- waveOutPrepareHeader(device->_handle_waveOut,&device->_buffer_info[i],sizeof(WAVEHDR));
- }
- //initialize mutexes
- InitializeCriticalSection(&device->_mutex);
- InitializeCriticalSection(&device->_callback_mutex);
- //default 10-second timeout, which i should probably edit and add parameters for later
- device->callback_timeout=10000;
- //set volumes to 1
- for(int i=0; i<=audioSpec.channels; ++i) device->volume[i]=1.0f;
- waveOutSetVolume(device->_handle_waveOut,0xFFFFFFFF);
- //preemptively fill output buffers
- _KIT_AUDIO_LOCKCALLBACKTHREAD(device);
- HANDLE firstThread=CreateThread(NULL,0,_kit_audioWaveOutFillBuffer,(LPVOID)device,0,NULL);
- CloseHandle(firstThread);
- device->_callback_thread=CreateThread(NULL,0,_kit_audioWaveOutFillBuffer,(LPVOID)device,0,NULL);
- _KIT_AUDIO_UNLOCKCALLBACKTHREAD(device);
- //wrap things up
- skip:
- if(returnStatus_ptr != NULL) *returnStatus_ptr=returnStatus;
- if(returnStatus==0) return device;
- else return NULL;
- }
- /* can't get waveOutReset to work :(
- #define _kit_audioWaveOutCloseERROR(_rcode) \
- { returnStatus=(_rcode); goto skip; }
- uint32_t kit_audioWaveOutClose(kit_audioDevice** device_p){
- printf("function start\n");
- Sleep(50);
- //make sure bad things don't happen if attempting to close device twice
- if(device_p == NULL){
- return 1;
- }
- kit_audioDevice* device=*device_p;
- printf("%p\n",device->_handle_waveOut);
- KIT_AUDIO_AUDITANDLOCK(device,KIT_AUDIO_DEVTYPE_WAVEOUT,2);
- //MMRESULT resetResult=waveOutReset(device->_handle_waveOut);
- //printf("resetResult=%u\n",resetResult);
- uint32_t returnStatus=0;
- for(int i=0; i<2; ++i){
- switch(waveOutUnprepareHeader(device->_handle_waveOut,&device->_buffer_info[i],sizeof(WAVEHDR))){
- case MMSYSERR_INVALHANDLE: _kit_audioWaveOutCloseERROR(3);
- case MMSYSERR_NODRIVER: _kit_audioWaveOutCloseERROR(4);
- case MMSYSERR_NOMEM: _kit_audioWaveOutCloseERROR(5);
- case WAVERR_STILLPLAYING: _kit_audioWaveOutCloseERROR(6);
- case MMSYSERR_NOERROR:;
- }
- }
- switch(waveOutClose(device->_handle_waveOut)){
- case MMSYSERR_INVALHANDLE: _kit_audioWaveOutCloseERROR(7);
- case MMSYSERR_NODRIVER: _kit_audioWaveOutCloseERROR(8);
- case MMSYSERR_NOMEM: _kit_audioWaveOutCloseERROR(9);
- case WAVERR_STILLPLAYING: _kit_audioWaveOutCloseERROR(10);
- case MMSYSERR_NOERROR:;
- }
- _kit_audioFree(device->volume);
- _kit_audioFree(device->_buffer[1]);
- _kit_audioFree(device->_buffer[0]);
- _kit_audioFree(device->_stream);
- skip:
- KIT_AUDIO_UNLOCK(device);
- if(!returnStatus){
- _kit_audioFree(device);
- *device_p=NULL;
- }
- return returnStatus;
- }*/
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement