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.h
- * \brief Header file for KIT Win32's audio module
- */
- //uncomment this if compiling kit_w32_audio.a, and want to use winmm
- #ifndef KIT_AUDIO_USE_WINMM
- # define KIT_AUDIO_USE_WINMM
- #endif
- #ifndef _KIT_W32_AUDIO_H
- #define _KIT_W32_AUDIO_H
- # ifndef _KIT_AUDIO
- # define _KIT_AUDIO
- /* GENERAL */
- #include <stdint.h>
- #include <string.h>
- #include <windef.h>
- //(requires that winmm was linked when kit_w32_audio.a was compiled)
- #ifdef KIT_AUDIO_USE_WINMM
- # include <mmsystem.h>
- #endif
- //WAVEFORMATEXTENSIBLE lives in mmreg.h, but i don't want
- //to also include wingdi.h here just for BITMAPINFOHEADER
- //TBD: check if mmreg.h is deprecated like winmm, as i'm pretty sure they're related
- #ifndef NOBITMAP
- # define NOBITMAP
- # include <mmreg.h>
- # undef NOBITMAP
- #else
- # include <mmreg.h>
- #endif
- //this provides CRITICAL_SECTION, which is a type of mutex object iirc
- #include <synchapi.h>
- //used for creating and managing threads
- #include <processthreadsapi.h>
- #include <combaseapi.h>
- #define _kit_audioMalloc(_type,_len) CoTaskMemAlloc(sizeof(_type)*(_len))
- #define _kit_audioFree(_ptr) CoTaskMemFree(_ptr)
- #define _kit_audioRealloc(_ptr,_type,_len) CoTaskMemRealloc(_ptr,sizeof(_type)*(_len))
- /**
- * \name Audio Format Constants
- */
- /** @{ */
- #define KIT_AUDIO_FMT_I8 (0x8007) ///< \brief signed 8-bit samples
- #define KIT_AUDIO_FMT_U8 (0x0007) ///< \brief unsigned 8-bit samples
- #define KIT_AUDIO_FMT_I16LSB (0x800F) ///< \brief signed 16-bit samples (little endian)
- #define KIT_AUDIO_FMT_U16LSB (0x000F) ///< \brief unsigned 16-bit samples (little endian)
- #define KIT_AUDIO_FMT_I32LSB (0x801F) ///< \brief signed 32-bit samples (little endian)
- #define KIT_AUDIO_FMT_U32LSB (0x001F) ///< \brief unsigned 32-bit samples (little endian)
- #define KIT_AUDIO_FMT_F32LSB (0x811F) ///< \brief 32-bit float samples (little endian)
- #define KIT_AUDIO_FMT_F64LSB (0x813F) ///< \brief 64-bit float samples (little endian)
- #define KIT_AUDIO_FMT_I16MSB (0x900F) ///< \brief signed 16-bit samples (big endian)
- #define KIT_AUDIO_FMT_U16MSB (0x100F) ///< \brief unsigned 16-bit samples (big endian)
- #define KIT_AUDIO_FMT_I32MSB (0x901F) ///< \brief signed 32-bit samples (big endian)
- #define KIT_AUDIO_FMT_U32MSB (0x101F) ///< \brief unsigned 32-bit samples (big endian)
- #define KIT_AUDIO_FMT_F32MSB (0x911F) ///< \brief 32-bit float samples (big endian)
- #define KIT_AUDIO_FMT_F64MSB (0x913F) ///< \brief 64-bit float samples (big endian)
- #define KIT_AUDIO_FMT_I16 KIT_AUDIO_FMT_I16LSB
- #define KIT_AUDIO_FMT_U16 KIT_AUDIO_FMT_U16LSB
- #define KIT_AUDIO_FMT_I32 KIT_AUDIO_FMT_I32LSB
- #define KIT_AUDIO_FMT_U32 KIT_AUDIO_FMT_U32LSB
- #define KIT_AUDIO_FMT_F32 KIT_AUDIO_FMT_F32LSB
- #define KIT_AUDIO_FMT_F64 KIT_AUDIO_FMT_F64LSB
- /** @} */
- /**
- * \name Audio Format Bitmasks & Macros
- */
- /** @{ */ /* (the "M" in FMT_M means (bit)mask) */
- #define KIT_AUDIO_FMT_MBITSIZE (0x00FF)
- #define KIT_AUDIO_FMT_MFLOAT (0x0100)
- #define KIT_AUDIO_FMT_MENDIAN (0X1000)
- #define KIT_AUDIO_FMT_MSIGNED (0x8000)
- #define KIT_AUDIO_FMT_BITSIZE(x) ((x) & KIT_AUDIO_FMT_MBITSIZE)
- #define KIT_AUDIO_FMT_ISFLOAT(x) ((x) & KIT_AUDIO_FMT_MFLOAT)
- #define KIT_AUDIO_FMT_ISBIGENDIAN(x) ((x) & KIT_AUDIO_FMT_MENDIAN)
- #define KIT_AUDIO_FMT_ISSIGNED(x) ((x) & KIT_AUDIO_FMT_MSIGNED)
- #define KIT_AUDIO_FMT_ISINT(x) (!KIT_AUDIO_FMT_ISFLOAT(x))
- #define KIT_AUDIO_FMT_ISLITTLEENDIAN(x) (!KIT_AUDIO_FMT_ISBIGENDIAN(x))
- #define KIT_AUDIO_FMT_ISUNSIGNED(x) (!KIT_AUDIO_FMT_ISSIGNED(x))
- /** @} */
- /**
- * \name Audio Device Type Constants
- */
- /** @{ */
- #define _KIT_AUDIO_DEVTYPE_BASE 0
- #define KIT_AUDIO_DEVTYPE_WASAPIIN (_KIT_AUDIO_DEVTYPE_BASE+1)
- #define KIT_AUDIO_DEVTYPE_WASAPIOUT (_KIT_AUDIO_DEVTYPE_BASE+2)
- #define KIT_AUDIO_DEVTYPE_WAVEIN (_KIT_AUDIO_DEVTYPE_BASE+3)
- #define KIT_AUDIO_DEVTYPE_WAVEOUT (_KIT_AUDIO_DEVTYPE_BASE+4)
- /** @} */
- /**
- * \name Audio Device Type Macros
- */
- /** @{ */
- #define KIT_AUDIO_IFNOTDEVICE(_device)\
- if(_device == NULL || \
- _device->_magic.num != 0x007665446F69647561 \
- )
- #define KIT_AUDIO_IFDEVICEINVALID(_device,_type)\
- if(_device == NULL || \
- _device->_magic.num != 0x007665446F69647561 || \
- _device->_device_type != _type \
- )
- #define KIT_AUDIO_AUDITANDLOCK(_device,_type,_errorvalue)\
- if(!kit_audioLockDevice(_device) || \
- _device->device_type != _type \
- ) return _errorvalue;
- #define KIT_AUDIO_LOCK(_device) \
- EnterCriticalSection(&_device->_mutex);
- //assumes audit already happened
- #define KIT_AUDIO_UNLOCK(_device) \
- LeaveCriticalSection(&_device->_mutex);
- #define _KIT_AUDIO_LOCKCALLBACKTHREAD(_device) \
- EnterCriticalSection(&_device->_callback_mutex);
- #define _KIT_AUDIO_UNLOCKCALLBACKTHREAD(_device) \
- LeaveCriticalSection(&_device->_callback_mutex);
- /** @} */
- /**
- * Audio Format (FMT)
- * \verbatim
- Bit Layout is as follows:
- +----------------------sample is signed if set
- |
- | +----------sample is bigendian if set
- | |
- | | +--sample is float if set
- | | |
- | | | +-sample bit size (-1)+
- | | | | |
- 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
- \endverbatim
- */
- typedef uint16_t kit_audioFormat;
- /**
- * PCM Audio Callback
- * This type of function is called when an opened (and unpaused)
- * audio device's audio buffer needs more PCM data.
- * The given audio buffer must be completely filled before returning
- * \param userdata A user-defined pointer passed to the callback, which
- * is stored in the same kit_audioSpec as the callback itself
- * \param stream A pointer to the audio data buffer
- * \param len The length of that buffer in bytes
- */
- typedef void (*kit_audioCallback) (void* userdata, void* stream, unsigned int len);
- /**
- * \brief This is the struct for an audio specification (something like a config but for a kit_audioDevice)
- */
- typedef struct {
- kit_audioCallback callback; ///< \brief Called when the audio buffer needs to be refilled
- void* userdata; ///< \brief User-defined pointer passed to callback
- uint32_t frequency; ///< \brief Sample rate of audio in Hz
- uint32_t buffer_size; ///< \brief Audio buffer length in bytes (automatically calculated)
- uint16_t buffer_len; ///< \brief Audio buffer length in samples (must a be power of 2)
- uint16_t channels; ///< \brief Number of audio channels (1=mono, 2=stereo, etc.)
- kit_audioFormat format; ///< \brief Audio data format information
- uint16_t _padding; //hopefully this works as intended
- } kit_audioSpec;
- /**
- * \brief This is the struct used for both WASAPI in/out and waveIn/Out devices. \n
- * Something of note is that most members of this struct have the "_" prefix,
- * which states that they are private and most likely should not be interacted
- * with or modified unless through kit_audio's interface.
- *
- * (While this struct uses an ID in the form of _magic, this type of ID
- * is not present in every kind of 'kit_moduleName' struct.)
- */
- typedef struct {
- union {
- char str[8]; ///< \brief String portion of ID ("audioDev\x00")
- uint64_t num; ///< \brief Number portion of ID (0x007665446F69647561)
- } /* -------------- */ _magic; ///< \brief Struct ID number; union of uint64_t and char[8]
- WAVEFORMATEXTENSIBLE _info; ///< \brief Used for some internal Win32 interactions
- #ifdef KIT_AUDIO_USE_WINMM
- WAVEHDR _buffer_info[2]; ///< \brief Information related to output streams
- #endif
- CRITICAL_SECTION _mutex; ///< \brief Used to stop callback from triggering if kit_audioLockDevice is called
- CRITICAL_SECTION _callback_mutex; ///< \brief Used to lock access to _callback_thread specifically
- kit_audioSpec src; ///< \brief Audio format of input stream buffer
- kit_audioSpec cvt; ///< \brief Audio format of ConVerTed (output) stream
- union {
- HANDLE _handle; ///< \brief Pointer handle of the device
- #ifdef KIT_AUDIO_USE_WINMM
- HWAVEIN _handle_waveIn;
- HWAVEOUT _handle_waveOut;
- #endif
- };
- HANDLE _callback_thread; ///< \brief User-defined callback thread, which kit_audioWaveOutReset locks until completion for
- void* _buffer[2]; ///< \brief Output streams (while 0 is playing, 1 is being filled, and vice versa)
- void* _stream; ///< \brief Points to the input stream data that is passed to _src.callback
- float* volume; ///< \brief Volume multiplier for each audio channel (0.0 -> 1.0)
- uint32_t callback_timeout; ///< \brief Timeout for callback thread, in milliseconds (default of 10000)
- uint16_t status; ///< \brief Gives some info of the device's state
- uint8_t _playing; ///< \brief A boolean of whether the device is unpaused or not
- uint8_t _cvt_needed; ///< \brief A boolean of 'is format conversion needed?'
- uint8_t device_type; ///< \brief 1, 2, 3, 4 = WASAPI in, WASAPI out, waveIn, waveOut
- uint8_t _which; ///< \brief Which output stream to fill with more audio data
- uint16_t _padding;
- union {
- #ifdef KIT_AUDIO_USE_WINMM
- WAVEINCAPS _waveInCaps; ///< \brief Capabilities of a waveIn device
- WAVEOUTCAPS _waveOutCaps; ///< \brief Capabilities of a waveOut device
- #endif
- }; /* --------------------- */ ///< \brief Capability specifications of a device
- } kit_audioDevice;
- /**
- * \brief Lock the audio callback of a given device from being called
- * (useful for manipulating the device struct)
- *
- * \param device A pointer to the device
- * \return A boolean of if the given pointer is an actual audio device
- *
- * \remark This activates a CRITICAL_SECTION mutex, so unlock as soon as possible
- */
- static inline int kit_audioLockDevice(kit_audioDevice* device){
- KIT_AUDIO_IFNOTDEVICE(device) return 0;
- else { EnterCriticalSection(&device->_mutex); return 1; }
- }
- /**
- * \brief Unlock the audio callback of a given device
- *
- * \param device A pointer to the device
- * \return A boolean of if the given pointer is an actual audio device
- */
- static inline int kit_audioUnlockDevice(kit_audioDevice* device){
- KIT_AUDIO_IFNOTDEVICE(device) return 0;
- else { LeaveCriticalSection(&device->_mutex); return 1; }
- }
- /**
- * \brief Get the current playing state of a given device
- *
- * \param device A pointer to the device
- * \return A boolean value of whether the device is currently unpaused or not
- */
- static inline int kit_audioIsPlaying(kit_audioDevice* device){
- if(!kit_audioLockDevice(device)) return 0;
- int isPlaying=device->_playing;
- KIT_AUDIO_UNLOCK(device);
- return isPlaying;
- }
- /**
- * \brief Set a device channel's volume multiplier (values should be 0.0 -> 1.0)
- *
- * \param device A pointer to the device
- * \param volume New volume multiplier for selected channel
- * \param channel Channel to assign new multiplier to
- */
- static inline void kit_audioSetVolume(kit_audioDevice* device, float volume,uint32_t channel){
- if(!kit_audioLockDevice(device)) return;
- if(channel>=device->cvt.channels) return;
- device->volume[channel]=volume;
- KIT_AUDIO_UNLOCK(device);
- }
- /**
- * \brief Set Stereo volume multiplier for device (values should be 0.0 -> 1.0)
- *
- * \param device A pointer to the device
- * \param volL New volume multiplier for left channel (or just channel 0 if channels is equal to 1)
- * \param volR New volume multiplier for right channel (ignored if channels is <2)
- */
- static inline void kit_audioSetVolumeLR(kit_audioDevice* device, float volL,float volR){
- if(!kit_audioLockDevice(device)) return;
- device->volume[0]=volL;
- if(device->cvt.channels>1) device->volume[1]=volR;
- KIT_AUDIO_UNLOCK(device);
- }
- /* WASAPI */
- /*//link against kernel32 and ole32
- #include <initguid.h>
- #include <mmdeviceapi.h>
- #include <audioclient.h>
- */
- /* WINMM */
- #ifdef KIT_AUDIO_USE_WINMM
- //thread process that handles filling waveOut audio buffers
- extern DWORD WINAPI _kit_audioWaveOutFillBuffer(LPVOID device_void_ptr);
- //callback associated with a waveOut device
- extern void CALLBACK _kit_audioWaveOutProc(HWAVEOUT waveOutHandle, UINT message, DWORD_PTR instance,
- DWORD_PTR param1, DWORD_PTR param2);
- //(remember to turn on static member extraction in doxygen config!)
- /**
- * \brief Get the current number of waveOut devices
- *
- * \return The number of available waveOut devices, or NULL on error \n
- * A value of 0 either means none are present, or an error occurred
- */
- static inline uint32_t kit_audioWaveOutGetNumDevs(){
- return (uint32_t)waveOutGetNumDevs();
- }
- /**
- * \brief Play/Pause a given waveOut device
- *
- * \param device A pointer to the device
- * \param playState A boolean of whether to resume playing or pause the device
- * \return Result of either waveOutRestart/waveOutPause (depending on if playState == 1 or not) \n
- * Possible return values:
- * \verbatim
- "MMSYSERR_NOERROR": No error occurred; success!
- "MMSYSERR_INVALHANDLE": Specified device handle is invalid
- "MMSYSERR_NODRIVER": No device driver is present
- "MMSYSERR_NOMEM": Unable to allocate or lock memory.
- "MMSYSERR_NOTSUPPORTED": Specified device is synchronous and does not support pausing
- \endverbatim
- * (MMSYSERR_INVALHANDLE can also be returned if "device" is not a waveOut device)
- */
- extern uint32_t kit_audioWaveOutPlay(kit_audioDevice* device, int playState);
- //threading can be a pain, so this is on the backburner for now
- /* *
- * \brief Stop playback of waveOut device, before setting current position to zero. \n
- * (This will immediately call the device's kit_audioCallback to initialize the buffer again!)
- * \remark If the kit_audioCallback is already running, the thread calling kit_audioWaveOutReset
- * will lock until the callback has completed
- *
- * \param device A pointer to the device
- * \return result of waveOutReset, or MMSYSERR_INVALHANDLE if "device" is not a waveOut device \n
- * Possible return values:
- * \verbatim
- "MMSYSERR_NOERROR": No error occurred; success!
- "MMSYSERR_INVALHANDLE": Specified device handle is invalid
- "MMSYSERR_NODRIVER": No device driver is present
- "MMSYSERR_NOMEM": Unable to allocate or lock memory.
- "MMSYSERR_NOTSUPPORTED": Specified device is synchronous and does not support pausing
- \endverbatim
- */
- //extern uint32_t kit_audioWaveOutReset(kit_audioDevice* device);//, uint32_t timeoutMilliseconds);
- /*
- * \param timeoutMilliseconds Maximum wait time for callback thread to end. \n
- * -1 (or "INFINITE") to wait indefinitely, and 0 to use device's timeout (10000 by default)
- */
- /**
- * \brief Open a waveOut device (device will be paused initially)
- *
- * \param desiredSpec The desired kit_audioSpec of the audio stream
- * \param deviceID The ID number of the desired waveOut device (-1 to select default device)
- * \param returnStatus A pointer to an int to be filled with a status code (ignored unless function returns NULL) \n
- * Possible returnStatus codes (all but 0 is considered an error):
- * \verbatim
- 0: Device opened successfully; no error
- 1: CoTaskMemAlloc (equivalent to malloc) of device returned NULL
- 2: Callback in desiredSpec was NULL
- 3: Bad device ID (ID specified was out of range)
- 4: No device driver is present
- 5: Unable to allocate or lock memory while fetching device capabilities
- 6: Format of device capabilities empty for some reason (this shouldn't happen)
- 7: desiredSpec->buffer_len is equal to 0
- 8: desiredSpec->buffer_len is not a power of 2
- 9: desiredSpec->frequency (sample rate) is neither 11025, 22050, 44100, nor 96000
- 10: desiredSpec->channels is neither 1 nor 2
- 11: desiredSpec->format is neither U8 (unsigned 8-bit), I16 (signed 16-bit), nor F32 (32-bit float)
- 12: Device is incapable of 11.025kHz, mono, signed 8-bit
- 13: Device is incapable of 11.025kHz, mono, signed 16-bit
- 14: Device is incapable of 11.025kHz, stereo, signed 8-bit
- 15: Device is incapable of 11.025kHz, stereo, signed 16-bit
- 16: Device is incapable of 22.05kHz, mono, signed 8-bit
- 17: Device is incapable of 22.05kHz, mono, signed 16-bit
- 18: Device is incapable of 22.05kHz, stereo, signed 8-bit
- 19: Device is incapable of 22.05kHz, stereo, signed 16-bit
- 20: Device is incapable of 44.1kHz, mono, signed 8-bit
- 21: Device is incapable of 44.1kHz, mono, signed 16-bit
- 22: Device is incapable of 44.1kHz, stereo, signed 8-bit
- 23: Device is incapable of 44.1kHz, stereo, signed 16-bit
- 24: Device is incapable of 96kHz, mono, signed 8-bit
- 25: Device is incapable of 96kHz, mono, signed 16-bit
- 26: Device is incapable of 96kHz, stereo, signed 8-bit
- 27: Device is incapable of 96kHz, stereo, signed 16-bit
- 28: CoTaskMemAlloc of device->_stream returned NULL
- 29: CoTaskMemAlloc of device->_buffer0 returned NULL
- 30: CoTaskMemAlloc of device->_buffer1 returned NULL
- 31: CoTaskMemAlloc of device->_volume returned NULL
- 32: waveOutOpen returned error 'Specified resource is already allocated'
- 33: waveOutOpen returned error 'No device driver is present'
- 34: waveOutOpen returned error 'Unable to allocate or lock memory'
- 35: waveOutOpen returned error 'Attempted to open with an unsupported waveform-audio format'
- 36: waveOutOpen returned error 'Device is synchronous, but WAVE_ALLOWSYNC flag was not set'
- \endverbatim
- * \return A pointer to a kit_audioDevice struct, otherwise return NULL on failure
- *
- * \remark Audio might begin stuttering if the audio stream buffer is set too small. \n
- * For example, audio at 96kHz might stutter with a buffer size of 4096, but 8192 or 16384 should be safe usually.
- *
- * \sa kit_audioWaveOutGetNumDevs
- * \sa kit_audioWaveOutPlay
- */
- extern kit_audioDevice* kit_audioWaveOutOpen(kit_audioSpec* desiredSpec, uint32_t deviceID, int* returnStatus_ptr);
- /* *
- * \brief Close a waveOut device
- *
- * \param device_p A pointer to the device's pointer
- * \return 0 on success, positive value on failure. \n
- * Possible return codes:
- * \verbatim
- 0: Device closed successfully; no error
- 1: device_p is NULL
- 2: *device_p is invalid (pointer is either NULL, or just not a waveOut audioDevice)
- 3: waveOutUnprepareHeader returned MMSYSERR_INVALHANDLE (Specified handle is invalid)
- 4: waveOutUnprepareHeader returned MMSYSERR_NODRIVER (No device driver is present)
- 5: waveOutUnprepareHeader returned MMSYSERR_NOMEM (Unable to allocate or lock memory)
- 6: waveOutUnprepareHeader returned WAVERR_STILLPLAYING (There are still buffers in the queue)
- 7: waveOutClose returned MMSYSERR_INVALHANDLE
- 8: waveOutClose returned MMSYSERR_NODRIVER
- 9: waveOutClose returned MMSYSERR_NOMEM
- 10: waveOutClose returned WAVERR_STILLPLAYING (There are still buffers in the queue)
- \endverbatim
- */
- //extern uint32_t kit_audioWaveOutClose(kit_audioDevice** device_p);
- #endif
- # endif
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement