Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\kit_sdl2\kit_AudioData_LoadAllTypes.cpp":
- #include "_kit_common.hpp"
- namespace kit {
- //file signatures
- //(KIT_MAGIC_KPM already defined in "_audio_AudioData.hpp")
- #define MAGIC_WAV 0x46464952 // = "RIFF"
- #define MAGIC_QOA 0x66616F71 // = "qoaf"
- #define MAGIC_OGG 0x5367674F // = "OggS"
- //"RIFF" is not a .wav's actual file signature, rather it denotes the type
- //of format used (like a format of formats of sorts), but i'm not going
- //to add extra logic here to also read 4 bytes at offset 8 just to check for
- //"WAVE" (which is its actual signature), because my wav parser already handles
- //everything related to header validation anyway.
- #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
- AudioData::AudioData(const char* filePath){
- const char* errTxt = "?";
- if(0) _err: THROW_ERRORF("AudioData::AudioData(any file format): %s", errTxt);
- if(filePath == nullptr)
- GOTO_SET_ERROR("filePath = nullptr");
- if(!fileio::exists(filePath))
- GOTO_SET_ERROR("file doesn't exist");
- u32 magic; //file signature, up to a maximum of 4 bytes
- if( File(filePath,"rb").read(&magic, sizeof(magic)) < sizeof(magic) )
- {
- GOTO_SET_ERROR("failed to read first 4 bytes of file");
- }
- AudioDataLoaderCallback callback;
- if( magic == KIT_MAGIC_KPM) callback = nullptr;
- else if(magic == MAGIC_WAV) callback = AudioDataLoadWAV;
- else if(magic == MAGIC_QOA) callback = AudioDataLoadQOA;
- else if(magic == MAGIC_OGG) callback = AudioDataLoadOGG;
- else GOTO_SET_ERROR("unsupported file format");
- _construct_file(filePath, callback, "AudioData::AudioData(any file format)");
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\kit_sdl2\kit_AudioData_LoadOGG.cpp":
- #include "_kit_common.hpp"
- #include "../stb_vorbis/stb_vorbis.hpp"
- namespace kit {
- #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
- AudioDataHeader* AudioDataLoadOGG(const char* filePath){
- const char* errTxt = "?";
- if(0) _err: THROW_ERRORF("AudioDataLoadOGG(): %s", errTxt);
- if(!fileio::exists(filePath))
- GOTO_SET_ERROR("file doesn't exist");
- BinaryData fileData(filePath);
- size_t fileSize = fileData.getSize();
- if(fileSize > KIT_S32_MAX)
- GOTO_SET_ERROR("fileSize > KIT_S32_MAX");
- stb_vorbis* vrb = stb_vorbis_open_memory((u8*)fileData.getData(), fileSize,
- nullptr, nullptr);
- if(vrb == nullptr)
- GOTO_SET_ERROR("failed to open Ogg Vorbis stream from memory");
- stb_vorbis_info vrb_info = stb_vorbis_get_info(vrb);
- u32 numSamples = stb_vorbis_stream_length_in_samples(vrb);
- u32 sampleRate = vrb_info.sample_rate;
- s32 channels = vrb_info.channels;
- if(channels > KIT_U16_MAX)
- GOTO_SET_ERROR("channels > KIT_U16_MAX");
- AudioDataHeader hdr;
- hdr.magic = KIT_MAGIC_KPM;
- hdr.format = SMPFMT_F32;
- hdr.headerSize = sizeof(AudioDataHeader);
- hdr.dataSize = sizeof(f32)*channels*numSamples;
- hdr.loopStart = 0;
- hdr.loopEnd = numSamples;
- hdr.numSamples = numSamples;
- hdr.sampleRate = sampleRate;
- hdr.bitRate = KIT_AUDIO_BITSIZE(SMPFMT_F32)*channels*sampleRate;
- hdr.loopCount = 0;
- hdr.channels = channels;
- hdr._reserved = 0;
- hdr.fmt_version = 1;
- hdr.mode = 0;
- hdr.metadata_type = 0;
- hdr.samples = nullptr;
- hdr.userdata = nullptr;
- AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
- if(_hdr == nullptr) GOTO_SET_ERROR("failed to allocate memory");
- *_hdr = hdr;
- _hdr->samples = (u8*)_hdr + _hdr->headerSize;
- int amountDecoded = stb_vorbis_get_samples_float_interleaved(vrb, channels,
- (f32*)_hdr->samples,
- numSamples*channels);
- if((u32)amountDecoded < numSamples){
- memory::free(&_hdr);
- stb_vorbis_close(vrb);
- GOTO_SET_ERROR("amountDecoded < numSamples");
- }
- //tbd: add loop points to ogg loader
- //stb_vorbis_comment comments = stb_vorbis_get_comment(vrb);
- //error if loopStart >= numSamples, error if loopEnd > numSamples
- stb_vorbis_close(vrb);
- return _hdr;
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\kit_sdl2\kit_AudioData_LoadSaveQOA.cpp":
- #include "_kit_common.hpp"
- #define QOA_NO_STDIO
- #define QOA_MALLOC(sz) kit::memory::alloc(sz)
- #define QOA_FREE(p) kit::memory::free(&p)
- namespace kit {
- namespace qoa {
- #define QOA_IMPLEMENTATION
- //idk why this is defined, but it's in qoaconv.c so i'll keep it in to be safe
- #define QOA_RECORD_TOTAL_ERROR
- #include "../qoa/qoa.h"
- }; /* namespace qoa */
- //hopefully putting it in its own namespace will prevent any user naming conflicts
- //(maybe it wouldn't have been a problem anyway, idk)
- using namespace qoa;
- /*
- struct {
- u32 channels;
- u32 samplerate;
- u32 samples;
- qoa_lms_t lms[QOA_MAX_CHANNELS];
- #ifdef QOA_RECORD_TOTAL_ERROR
- f64 error;
- #endif
- } qoa_desc;
- s16* qoa_decode(const u8* bytes, s32 size, qoa_desc* file);
- void* qoa_encode(const s16* sample_data, qoa_desc* qoa, u32* out_len);
- */
- #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
- #define MAGIC_QOA 0x66616F71 // = "qoaf"
- AudioDataHeader* AudioDataLoadQOA(const char* filePath){
- const char* errTxt = "?";
- if(0) _err: THROW_ERRORF("AudioDataLoadQOA(): %s", errTxt);
- if(!fileio::exists(filePath))
- GOTO_SET_ERROR("file doesn't exist");
- BinaryData _fileData(filePath);
- s32 fileSize = ( s32 )_fileData.getSize();
- void* fileData = (void*)_fileData.getData(); //the ACTUAL file data
- if(_fileData.getSize() > KIT_S32_MAX)
- GOTO_SET_ERROR("file is too large for a QOA (>2GiB)");
- //if(fileSize < ??)
- // GOTO_SET_ERROR("file is too small for a QOA (<??B)");
- if((*(u32*)fileData) != MAGIC_QOA)
- GOTO_SET_ERROR("file is not a QOA audio file");
- qoa_desc smp_info;
- memory::Wrapper _smp(qoa_decode((u8*)fileData, fileSize, &smp_info));
- s16* smp = (s16*)_smp.ptr;
- if(smp == nullptr) GOTO_SET_ERROR("failed to decode QOA file data");
- if(smp_info.channels > KIT_U16_MAX)
- GOTO_SET_ERROR("channels > KIT_U16_MAX");
- AudioDataHeader hdr;
- hdr.magic = KIT_MAGIC_KPM;
- hdr.format = SMPFMT_S16;
- hdr.headerSize = sizeof(AudioDataHeader);
- hdr.dataSize = sizeof(s16)*smp_info.samples*smp_info.channels;
- hdr.loopStart = 0;
- hdr.loopEnd = smp_info.samples;
- hdr.numSamples = smp_info.samples;
- hdr.sampleRate = smp_info.samplerate;
- hdr.bitRate = KIT_AUDIO_BITSIZE(hdr.format)*smp_info.channels*smp_info.samplerate;
- hdr.loopCount = 0;
- hdr.channels = smp_info.channels;
- hdr._reserved = 0;
- hdr.fmt_version = 1;
- hdr.mode = 0;
- hdr.metadata_type = 0;
- hdr.samples = nullptr;
- hdr.userdata = nullptr;
- AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
- if(_hdr == nullptr) GOTO_SET_ERROR("failed to allocate memory");
- *_hdr = hdr;
- _hdr->samples = (u8*)_hdr + _hdr->headerSize;
- memory::copy(_hdr->samples, smp, _hdr->dataSize);
- return _hdr;
- }
- void AudioDataSaveQOA(const char* filePath,
- AudioDataHeader& header_in)
- {
- const char* errTxt = "?";
- if(0) _err: THROW_ERRORF("AudioDataSaveQOA(): %s", errTxt);
- if(header_in.format != SMPFMT_S16)
- GOTO_SET_ERROR("format != SMPFMT_S16");
- if(header_in.numSamples > KIT_U32_MAX)
- GOTO_SET_ERROR("numSamples > KIT_U32_MAX");
- qoa_desc smp_info;
- smp_info.channels = header_in.channels;
- smp_info.samplerate = header_in.sampleRate;
- smp_info.samples = header_in.numSamples;
- u32 fileSize;
- memory::Wrapper fileData(qoa_encode((s16*)header_in.samples,
- &smp_info, &fileSize));
- if(fileData.ptr == nullptr) GOTO_SET_ERROR("failed to encode QOA data");
- try {
- File file(filePath, "wb");
- file.write(fileData.ptr, fileSize);
- } catch(const char* errorText){
- freeThreadErrors();
- GOTO_SET_ERROR("failed to write to file");
- }
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\kit_sdl2\kit_AudioData_LoadSaveWAV.cpp":
- #include "_kit_common.hpp"
- namespace kit {
- #define KIT_LOAD_WAV_MALLOC(_ptr) kit::memory::alloc(_ptr)
- #define KIT_LOAD_WAV_FREE(_ptr) kit::memory::free(&_ptr)
- #define KIT_LOAD_WAV_MEMSET(_ptr_or_arr, _value, _size) \
- kit::memory::set((_ptr_or_arr), (_value), (_size))
- #define KIT_LOAD_WAV_MEMCPY(_dst_ptr, _src_ptr, _size) \
- kit::memory::copy((_dst_ptr), (_src_ptr), (_size))
- #define KIT_LOAD_WAV_IMPLEMENTATION
- #define KIT_LOAD_WAV_CUSTOM_READ
- #include "kit_load_wav.h"
- void* kit_read_wav(const char* filePath, int32_t* fileSize_out){
- if(!filePath) return NULL;
- size_t fileSize;
- void* fileData = SDL_LoadFile(filePath, &fileSize);
- if(!fileData) return NULL;
- if(fileSize > KIT_S32_MAX){
- SDL_free(fileData);
- return NULL;
- }
- //SDL_LoadFile calls SDL_malloc internally; increment # of allocations
- ++numAllocations;
- if(fileSize_out) *fileSize_out = (int32_t)fileSize;
- return fileData;
- }
- #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
- //(channels may be inaccurate if they use a different layout than SDL's channel mappings!)
- AudioDataHeader* AudioDataLoadWAV(const char* filePath){
- const char* errTxt = "?";
- if(0) _err: THROW_ERRORF("AudioDataLoadWAV(): %s", errTxt);
- if(!fileio::exists(filePath))
- GOTO_SET_ERROR("file doesn't exist");
- int32_t _wavErr;
- memory::Wrapper _wavData(kit_load_wav(filePath, &_wavErr));
- kit_WavData* wavData = (kit_WavData*)_wavData.ptr;
- if(_wavErr != WAVEERROR_SUCCESS){
- switch(_wavErr){
- case WAVEERROR_NULLPTR : errTxt = "non-optional argument pointer was nullptr"; break;
- case WAVEERROR_FILE_READ : errTxt = "failed to read file"; break;
- case WAVEERROR_FILE_SIZE : errTxt = "fileSize was < 44 (minimum needed for header)"; break;
- case WAVEERROR_NOT_RIFF : errTxt = "first 4 bytes of file != \"RIFF\""; break;
- case WAVEERROR_MALFORMED : errTxt = "wav has malformed data"; break;
- case WAVEERROR_NOT_WAVE : errTxt = "4 bytes from offset 8 != \"WAVE\""; break;
- case WAVEERROR_MALLOC : _alloc_err: errTxt = "failed to allocate memory"; break;
- case WAVEERROR_NO_FMT : errTxt = "wav doesn't contain a f[or]m[a]t subchunk"; break;
- case WAVEERROR_NO_DATA : errTxt = "wav doesn't contain a data subchunk"; break;
- case WAVEERROR_FORMAT : _fmt_tag_err: errTxt = "wav uses an unsupported format tag"; break;
- case WAVEERROR_CHANNELS : errTxt = "channels = 0"; break;
- case WAVEERROR_SAMPLERATE: errTxt = "sampleRate = 0"; break;
- case WAVEERROR_BYTERATE : errTxt = "byteRate != blockAlign*sampleRate"; break;
- case WAVEERROR_BLOCKALIGN: errTxt = "blockAlign != (.channels*.bitsPerSample)/8"; break;
- case WAVEERROR_BITSPERSMP: errTxt = "bitsPerSample%8 != 0 OR = 0 OR > 64"; break;
- case WAVEERROR_EXTSIZE : errTxt = "extensionSize < 22 (format tag is EXTENSIBLE)"; break;
- case WAVEERROR_VALIDBITS : errTxt = "validBits > bitsPerSample OR validBits = 0"; break;
- default : _unknown_err: errTxt = "unknown error"; break;
- }
- goto _err;
- }
- if(wavData == nullptr) goto _unknown_err; //this one should be impossible, but just in case
- if(!wavData->samples_type) goto _unknown_err;
- //convert kit_WavData_type to that of AudioSampleFormatEnum (AKA SDL_AudioFormat)
- kit_WavData_type wavType;
- wavType.value = wavData->samples_type;
- if(wavType.totalBits != wavType.validBits)
- GOTO_SET_ERROR("bitsPerSample != validBits");
- if(wavType.format != WAVEDATA_FORMAT_PCM && wavType.format != WAVEDATA_FORMAT_FLOAT)
- goto _fmt_tag_err; //(WAVEDATA_FORMAT_<ALAW/ULAW> aren't allowed currently)
- u16 format = (wavType.value&0x803F) + 1;
- if(wavType.format == WAVEDATA_FORMAT_FLOAT) format |= 0x8100;
- AudioDataHeader hdr;
- hdr.magic = KIT_MAGIC_KPM;
- hdr.format = format;
- hdr.headerSize = sizeof(AudioDataHeader);
- hdr.dataSize = wavData->samples_size;
- hdr.loopStart = 0;
- hdr.loopEnd = wavData->samples_len;
- hdr.numSamples = wavData->samples_len;
- hdr.sampleRate = wavData->sampleRate;
- hdr.bitRate = KIT_AUDIO_BITSIZE(format)*wavData->sampleRate*wavData->channels;
- hdr.loopCount = 0;
- hdr.channels = wavData->channels;
- hdr._reserved = 0;
- hdr.fmt_version = 1; //1 indicates the version kit_sdl2 uses
- hdr.mode = 0; //PCM or float data
- hdr.metadata_type = 0; //no metadata
- hdr.samples = nullptr;
- hdr.userdata = nullptr;
- AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
- if(_hdr == nullptr) goto _alloc_err;
- *_hdr = hdr;
- _hdr->samples = (u8*)_hdr + _hdr->headerSize;
- memory::copy(_hdr->samples, wavData->samples, _hdr->dataSize);
- return _hdr;
- }
- struct _WavHeader { //the whole thing (for convenience)
- u32 file_id; // = 0x46464952 = "RIFF"
- u32 file_size; // = file's total size - 8
- u32 file_id2; // = 0x45564157 = "WAVE"
- u32 fmt_id; // = 0x20746D66 = "fmt "
- u32 fmt_size; // = 16
- u16 fmt_format; // = 3 if float, 1 if PCM
- u16 fmt_channels; // = # of interleaved channels; L&R for stereo (2)
- u32 fmt_sampleRate; // = # of sample frames per second
- u32 fmt_byteRate; // = blockAlign*sampleRate
- u16 fmt_blockAlign; // = size of sample frame (channels*bitsPerSample)/8
- u16 fmt_bitsPerSample; // (Assumed to be unsigned if 8 and .format is PCM)
- u32 data_id; // = 0x61746164 = "data"
- u32 data_size; // = size of sample data, in bytes
- //(sample data starts here)
- };
- #define SV_ASSERT(_success, _error_text) \
- if(!(_success)){ errTxt = _error_text; goto _err; }
- void AudioDataSaveWAV(const char* filePath,
- AudioDataHeader& header_in)
- {
- const char* errTxt = "?";
- if(0) _err: THROW_ERRORF("AudioDataSaveWAV(): %s", errTxt);
- //stack copy, so i can't accidentally change values of the original header
- AudioDataHeader hdri = header_in;
- SV_ASSERT(hdri.fmt_version == 1, "fmt_version != 1");
- SV_ASSERT(!( KIT_AUDIO_ISSIGNED(hdri.format) && KIT_BITSPERPIXEL(hdri.format)<=8 ),
- "samples 8-bits and below must be unsigned");
- //round bits UP to the nearest byte (as in a multiple of 8 bits)
- #define BYTE_CEIL(_num) (((_num)+7)&(~7))
- _WavHeader hdro;
- hdro.file_id = wid_RIFF;
- hdro.file_size = sizeof(_WavHeader) + hdri.dataSize - 8;
- hdro.file_id2 = wid_WAVE;
- hdro.fmt_id = wid_fmt_;
- hdro.fmt_size = 16;
- hdro.fmt_format = KIT_AUDIO_ISFLOAT(hdri.format) ? 3 : 1;
- hdro.fmt_channels = hdri.channels;
- hdro.fmt_sampleRate = hdri.sampleRate;
- hdro.fmt_byteRate = BYTE_CEIL(hdri.bitRate)/8;
- hdro.fmt_blockAlign = BYTE_CEIL(hdri.channels*KIT_AUDIO_BITSIZE(hdri.format))/8;
- hdro.fmt_bitsPerSample = KIT_AUDIO_BITSIZE(hdri.format);
- hdro.data_id = wid_data;
- hdro.data_size = hdri.dataSize;
- try {
- File file(filePath, "wb");
- file.write(&hdro, sizeof(hdro));
- file.write(hdri.samples, hdri.dataSize);
- } catch(const char* errorText){
- freeThreadErrors();
- GOTO_SET_ERROR("failed to write to file");
- }
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\kit_sdl2\kit_AudioDevice.cpp":
- #include "_kit_common.hpp"
- #define INDEX_FUNC "AudioDevice::AudioDevice(index)"
- #define NAME_FUNC "AudioDevice::AudioDevice(name)"
- #define DEVICE_IS_INVALID (!_valid)
- //i don't think i ended up using these lol
- #define CONSTRUCTOR_ERR(_txt) PUSH_ERRORF("%s: " _txt , funcname)
- #define CONSTRUCTOR_ERRSDL PUSH_ERRORF("%s: %s", funcname, SDL_GetError())
- #define DEV_PTR ((_AudioDeviceOpaque*)_opq)
- namespace kit {
- //in "kit_AudioCallbackWrapper.cpp"
- void _AudioCallbackWrapper(void* userdata, u8* _stream, int len);
- static inline u32 _count_bits(u32 num){
- u32 count = 0;
- while(num > 0){
- if(num&1) ++count;
- num >>= 1;
- }
- return count;
- }
- //not inlined
- bool _validate_smpfmt(u16 sampleFormat, bool allow0 = false){
- switch(sampleFormat){
- case SMPFMT_U8 :
- case SMPFMT_S8 :
- case SMPFMT_U16LSB:
- case SMPFMT_S16LSB:
- //case SMPFMT_U16MSB:
- //case SMPFMT_S16MSB:
- case SMPFMT_S32LSB:
- //case SMPFMT_S32MSB:
- case SMPFMT_F32LSB:
- //case SMPFMT_F32MSB:
- break;
- case 0:
- if(allow0) break;
- else SDL_FALLTHROUGH;
- default:
- return false;
- }
- return true;
- }
- static inline void validate_desired(const AudioDeviceInfo& desired,
- const char* funcname)
- {
- if(desired.sampleRate > KIT_S32_MAX)
- THROW_ERRORF("%s: desired.sampleRate > KIT_S32_MAX", funcname);
- //this isn't strictly necessary, as my machine (windows, currently) seems to
- //accept frame counts that aren't powers of 2. however it might be best
- //practice to use powers of 2 in case the target system doesn't support it.
- /*if(_count_bits(desired.sampleFrames) > 1)
- THROW_ERRORF("%s: desired.sampleFrames is not a power of 2", funcname);*/
- if(!_validate_smpfmt(desired.sampleFormat, true)){
- THROW_ERRORF("%s: desired.sampleFormat of 0x%04X is invalid",
- funcname, desired.sampleFormat);
- }
- if(desired.numChannels > 8)
- THROW_ERRORF("%s: desired.numChannels > 8", funcname);
- if(desired.callback == nullptr)
- THROW_ERRORF("%s: desired.callback = nullptr", funcname);
- }
- static inline s32 get_dev_params(SDL_AudioSpec& want,
- const AudioDeviceInfo& desired,
- AudioDevice* device)
- {
- want.freq = (s32)((desired.sampleRate) ? desired.sampleRate : 48000);
- want.format = AUDIO_F32LSB;
- want.channels = (desired.numChannels) ? desired.numChannels : 2;
- want.samples = (desired.sampleFrames) ? desired.sampleFrames : 4096;
- want.callback = _AudioCallbackWrapper;
- want.userdata = device;
- s32 allowed_changes = 0;
- if(!desired.sampleRate ) allowed_changes |= SDL_AUDIO_ALLOW_FREQUENCY_CHANGE;
- //underlying stream must be f32, so this one should never be set
- //if(!desired.sampleFormat) allowed_changes |= SDL_AUDIO_ALLOW_FORMAT_CHANGE;
- if(!desired.numChannels ) allowed_changes |= SDL_AUDIO_ALLOW_CHANNELS_CHANGE;
- if(!desired.sampleFrames) allowed_changes |= SDL_AUDIO_ALLOW_SAMPLES_CHANGE;
- return allowed_changes;
- }
- static inline AudioDeviceInfo set_dev_info(SDL_AudioDeviceID deviceID,
- SDL_AudioSpec have,
- const AudioDeviceInfo& desired)
- {
- AudioDeviceInfo info;
- //info.timeStartTicks = 0;
- //info.timeStartMS = 0;
- info.deviceID = deviceID;
- info.sampleRate = have.freq;
- info.sampleFrames = have.samples;
- info.sampleFormat = have.format;
- info.sampleFrameSize = KIT_AUDIO_BYTESIZE(have.format)*have.channels;
- info.numChannels = have.channels;
- info.isInput = desired.isInput;
- info.zeroBuffer = desired.zeroBuffer;
- info.callback = desired.callback;
- info.userdata = desired.userdata;
- return info;
- }
- AudioDevice::AudioDevice(s32 index, //-1 to use default device
- const AudioDeviceInfo& desired,
- bool disableFadeDelay)
- {
- const char* name = nullptr;
- if(index >= 0){
- name = SDL_GetAudioDeviceName(index, desired.isInput);
- if(name == nullptr)
- THROW_ERRORF(INDEX_FUNC ": \"%s\"", SDL_GetError());
- }
- _construct(name, desired, disableFadeDelay);
- }
- void AudioDevice::_construct(const char* name,
- const AudioDeviceInfo& desired,
- bool disableFadeDelay,
- bool indexed)
- {
- if(_valid) return;
- _type = KIT_CLASSTYPE_AUDIODEVICE;
- const char* funcname = (indexed) ? INDEX_FUNC : NAME_FUNC;
- AudioDeviceInfo* info_p = (AudioDeviceInfo*)&info; //info is normally const
- //a few domain checks
- validate_desired(desired, funcname);
- SDL_AudioSpec want, have;
- s32 allowed_changes = get_dev_params(want, desired, this);
- //actually create the device
- SDL_AudioDeviceID deviceID = SDL_OpenAudioDevice(name, desired.isInput,
- &want, &have, allowed_changes);
- if(!deviceID) THROW_ERRORF("%s: %s", funcname, SDL_GetError());
- if(desired.sampleFormat) have.format = desired.sampleFormat;
- *info_p = set_dev_info(deviceID, have, desired);
- _opq = memory::alloc(sizeof(_AudioDeviceOpaque));
- if(_opq == nullptr){
- SDL_CloseAudioDevice(info.deviceID);
- THROW_ERRORF("%s: failed to allocate memory for opaque struct", funcname);
- }
- memory::set(_opq, 0, sizeof(_AudioDeviceOpaque));
- DEV_PTR->info_p = info_p;
- DEV_PTR->buffer_size = info.sampleFrames * info.sampleFrameSize;
- DEV_PTR->buffer = memory::allocSIMD(DEV_PTR->buffer_size);
- DEV_PTR->fadeDelta = 1.0f / ((f32)info.sampleRate*FADEDELTA_SEC);
- //DEV_PTR->fadeVolume = 0.0f; //(the prior memset makes setting to 0 redundant)
- //DEV_PTR->fadeDelay = 0;
- //DEV_PTR->fadeOut = false;
- DEV_PTR->noFadeDelay = disableFadeDelay;
- //DEV_PTR->playing = false;
- if(DEV_PTR->buffer == nullptr){
- memory::free(&_opq);
- SDL_CloseAudioDevice(info.deviceID);
- THROW_ERRORF("%s: failed to allocate memory for audio buffer", funcname);
- }
- memory::set(DEV_PTR->buffer, 0, DEV_PTR->buffer_size);
- _valid = true;
- _constructing = false;
- }
- AudioDevice::~AudioDevice(){
- if(!_valid) return;
- _valid = false;
- if(info.deviceID != 0) SDL_CloseAudioDevice(info.deviceID);
- if(_opq != nullptr){
- memory::freeSIMD(&DEV_PTR->buffer);
- memory::free(&_opq);
- }
- }
- bool AudioDevice::isPlaying(){
- if(DEVICE_IS_INVALID)
- THROW_ERROR("AudioDevice::isPlaying(): invalid AudioDevice");
- //return SDL_GetAudioDeviceStatus(info.deviceID) == SDL_AUDIO_PLAYING;
- return DEV_PTR->playing;
- }
- bool AudioDevice::isActive(){
- if(DEVICE_IS_INVALID)
- THROW_ERROR("AudioDevice::isActive(): invalid AudioDevice");
- return SDL_GetAudioDeviceStatus(info.deviceID) == SDL_AUDIO_PLAYING;
- //return DEV_PTR->playing;
- }
- void AudioDevice::setCallback(AudioCallback callback){
- if(DEVICE_IS_INVALID)
- THROW_ERROR("AudioDevice::setCallback(): invalid AudioDevice");
- if(callback == nullptr)
- THROW_ERROR("AudioDevice::setCallback(): callback = nullptr");
- SDL_LockAudioDevice(info.deviceID);
- ((AudioDeviceInfo*)&info)->callback = callback;
- SDL_UnlockAudioDevice(info.deviceID);
- }
- void AudioDevice::setUserdata(void* userdata){
- if(DEVICE_IS_INVALID)
- THROW_ERROR("AudioDevice::setUserdata(): invalid AudioDevice");
- SDL_LockAudioDevice(info.deviceID);
- ((AudioDeviceInfo*)&info)->userdata = userdata;
- SDL_UnlockAudioDevice(info.deviceID);
- }
- void AudioDevice::setPlayback(bool playing){
- if(DEVICE_IS_INVALID)
- THROW_ERROR("AudioDevice::setPlayback(): invalid AudioDevice");
- //this should occur when _AudioCallbackWrapper
- //fails to trigger the pause thread
- if(DEV_PTR->fadeDelay == KIT_U32_MAX){
- SDL_LockAudioDevice(info.deviceID);
- SDL_PauseAudioDevice(info.deviceID, true);
- DEV_PTR->fadeVolume = 0.0f;
- DEV_PTR->fadeDelay = 0;
- DEV_PTR->fadeOut = false;
- DEV_PTR->playing = false;
- SDL_UnlockAudioDevice(info.deviceID);
- }
- DEV_PTR->fadeOut = !playing;
- if(playing && !DEV_PTR->playing){
- //the purpose of fadeDelay is to mute for some samples
- //to give the sdl audio device some time to warm up,
- //otherwise artifacts start to occur (for me, anyway)
- if(!DEV_PTR->noFadeDelay) DEV_PTR->fadeDelay = (u32)(info.sampleRate * FADEDELAY_SEC);
- else DEV_PTR->fadeDelay = 0;
- DEV_PTR->fadeVolume = 0.0f;
- DEV_PTR->playing = true;
- SDL_PauseAudioDevice(info.deviceID, false);
- }
- }
- void AudioDevice::setPlaybackAndWait(bool playing){
- if(DEVICE_IS_INVALID)
- THROW_ERROR("AudioDevice::setPlaybackAndWait(): invalid AudioDevice");
- bool wasPlaying = DEV_PTR->playing;
- setPlayback(playing);
- if(playing && !wasPlaying && !DEV_PTR->noFadeDelay){
- time::sleep((u32)( FADETOTAL_SEC*1000 ));
- } else {
- time::sleep((u32)( FADEDELTA_SEC*1000 ));
- }
- }
- void AudioDevice::lock(bool locked){
- if(DEVICE_IS_INVALID)
- THROW_ERROR("AudioDevice::lock(): invalid AudioDevice");
- if(locked) SDL_LockAudioDevice(info.deviceID);
- else SDL_UnlockAudioDevice(info.deviceID);
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\kit_sdl2\kit_AudioStream.cpp":
- #include "_kit_common.hpp"
- #define STREAM_IS_INVALID (!_valid)
- #define STRM_PTR ((SDL_AudioStream*)_opq)
- namespace kit {
- bool _validate_smpfmt(u16 sampleFormat, bool allow0 = false);
- AudioStream::AudioStream(const AudioDeviceInfo* src_p,
- const AudioDeviceInfo* dst_p)
- {
- if(_valid) return;
- _type = KIT_CLASSTYPE_AUDIOSTREAM;
- if(src_p == nullptr) THROW_ERROR("AudioStream::AudioStream(): src_p = nullptr");
- if(dst_p == nullptr) THROW_ERROR("AudioStream::AudioStream(): dst_p = nullptr");
- if(src_p->sampleRate > KIT_S32_MAX)
- THROW_ERROR("AudioStream::AudioStream(): src_p->sampleRate > KIT_S32_MAX");
- if(dst_p->sampleRate > KIT_S32_MAX)
- THROW_ERROR("AudioStream::AudioStream(): dst_p->sampleRate > KIT_S32_MAX");
- if(!_validate_smpfmt(src_p->sampleFormat))
- THROW_ERROR("AudioStream::AudioStream(): src_p->sampleFormat is invalid");
- if(!_validate_smpfmt(dst_p->sampleFormat))
- THROW_ERROR("AudioStream::AudioStream(): dst_p->sampleFormat is invalid");
- if(src_p->numChannels == 0 || src_p->numChannels > 8)
- THROW_ERROR("AudioStream::AudioStream(): src_p->numChannels must be 1 -> 8");
- if(dst_p->numChannels == 0 || dst_p->numChannels > 8)
- THROW_ERROR("AudioStream::AudioStream(): dst_p->numChannels must be 1 -> 8");
- //since src and dst are normally const,
- //they're punned so that they can be set
- AudioDeviceInfo* _src_p = (AudioDeviceInfo*)&src;
- AudioDeviceInfo* _dst_p = (AudioDeviceInfo*)&dst;
- *_src_p = *src_p;
- *_dst_p = *dst_p;
- _src_p->sampleFrameSize = src.numChannels * KIT_AUDIO_BYTESIZE(src.sampleFormat);
- _dst_p->sampleFrameSize = dst.numChannels * KIT_AUDIO_BYTESIZE(dst.sampleFormat);
- _opq = SDL_NewAudioStream(src.sampleFormat, src.numChannels, (s32)src.sampleRate,
- dst.sampleFormat, dst.numChannels, (s32)dst.sampleRate);
- if(_opq == nullptr)
- THROW_ERRORF("AudioStream::AudioStream(): \"%s\"", SDL_GetError());
- ++numAllocations;
- _valid = true;
- _constructing = false;
- }
- AudioStream::~AudioStream(){
- if(!_valid) return;
- _valid = false;
- if(_opq != nullptr){
- SDL_FreeAudioStream(STRM_PTR);
- _opq = nullptr;
- --numAllocations;
- }
- }
- u32 AudioStream::getAvailableBytes(){
- if(STREAM_IS_INVALID)
- THROW_ERROR("AudioStream::getNumAvailable(): invalid AudioStream");
- s32 result = SDL_AudioStreamAvailable(STRM_PTR);
- if(result < 0)
- THROW_ERRORF("AudioStream::getNumAvailable(): \"%s\"", SDL_GetError());
- return (u32)result;
- }
- void AudioStream::flush(){
- if(STREAM_IS_INVALID)
- THROW_ERROR("AudioStream::flush(): invalid AudioStream");
- //as of 2024-08-03, the SDL2 wiki does not even tell you what this returns,
- //but most SDL calls with int returns of this type use 0 and -1 for
- //success and failure respectively. so, hopefully my hunch is right :D
- if(SDL_AudioStreamFlush(STRM_PTR) != 0)
- THROW_ERRORF("AudioStream::flush(): \"%s\"", SDL_GetError());
- }
- void AudioStream::clear(){
- if(STREAM_IS_INVALID)
- THROW_ERROR("AudioStream::clear(): invalid AudioStream");
- SDL_AudioStreamClear(STRM_PTR);
- }
- u32 AudioStream::get(void* buffer_dst, u32 buffer_size){
- if(STREAM_IS_INVALID)
- THROW_ERROR("AudioStream::get(): invalid AudioStream");
- if(buffer_dst == nullptr)
- THROW_ERROR("AudioStream::get(): buffer_dst = nullptr");
- if(buffer_size > KIT_S32_MAX)
- THROW_ERROR("AudioStream::get(): buffer_size > KIT_S32_MAX");
- s32 result = SDL_AudioStreamGet(STRM_PTR, buffer_dst, buffer_size);
- if(result < 0)
- THROW_ERRORF("AudioStream::get(): \"%s\"", SDL_GetError());
- return (u32)result;
- }
- void AudioStream::put(void* buffer_src, u32 buffer_size){
- if(STREAM_IS_INVALID)
- THROW_ERROR("AudioStream::put(): invalid AudioStream");
- if(buffer_src == nullptr)
- THROW_ERROR("AudioStream::put(): buffer_src = nullptr");
- if(buffer_size > KIT_S32_MAX)
- THROW_ERROR("AudioStream::put(): buffer_size > KIT_S32_MAX");
- if(SDL_AudioStreamPut(STRM_PTR, buffer_src, buffer_size) < 0)
- THROW_ERRORF("AudioStream::put(): \"%s\"", SDL_GetError());
- }
- }; /* namespace kit */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement