Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"ksdl2_2024-11-07\kit_SoundEngine.cpp":
- #include "_kit_common.hpp"
- #define SNDENGINE_IS_INVALID (!_valid && !_constructing)
- namespace kit {
- //
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"ksdl2_2024-11-07\_audio_AudioData.hpp":
- #ifndef _INC__AUDIO_AUDIODATA_HPP
- #define _INC__AUDIO_AUDIODATA_HPP
- #include "commondef.hpp"
- #include "_audio_types.hpp"
- namespace kit {
- struct AudioDataHeader;
- //like Surface, the pointer this returns must have been allocated with
- //memory:alloc specifically (NOT memory::allocSIMD!)
- //->samples must not use a separate allocation! samples must be contiguous
- //and on the same memory block as the header itself!
- //(basically, header_ptr->samples = (u8*)header_ptr+header_ptr->headerSize)
- typedef AudioDataHeader* (*AudioDataLoaderCallback)(const char* filePath);
- typedef void (*AudioDataSaverCallback)(const char* filePath, AudioDataHeader& header_in);
- //(like Surface, when saving OR loading, filePath will never be nullptr by the
- //time the callback is invoked, so you don't need to worry about checking for it)
- //(not an actual callback, but rather the lack of one)
- #define AudioDataLoadKPM ((AudioDataLoaderCallback)nullptr)
- #define AudioDataSaveKPM ((AudioDataSaverCallback)nullptr)
- AudioDataHeader* AudioDataLoadWAV(const char* filePath);
- void AudioDataSaveWAV(const char* filePath, AudioDataHeader& header_in);
- AudioDataHeader* AudioDataLoadQOA(const char* filePath);
- void AudioDataSaveQOA(const char* filePath, AudioDataHeader& header_in);
- AudioDataHeader* AudioDataLoadOGG(const char* filePath);
- //(there is no saver callback for ogg currently!)
- #define KIT_MAGIC_KPM (0x4D78506B) // = "kPxM" (no null terminator)
- struct AudioDataHeader { //72B (0x48B)
- u32 magic; // (0x00) = KIT_MAGIC_KPM = 0x4D78506B = "kPxM"
- u16 format; // (0x04) = one of AudioSampleFormatEnum if fmt_version == 1
- u16 headerSize; // (0x06) = must be >=sizeof(AudioDataHeader)
- u64 dataSize; // (0x08) = size of audio data, in bytes
- u64 loopStart; // (0x10) = which sample to loop back to
- u64 loopEnd; // (0x18) = which sample to jump back to loopStart on
- u64 numSamples; // (0x20) = # of sample frames in audio data
- u32 sampleRate; // (0x28) = the audio data's sample rate, in Hz
- u32 bitRate; // (0x2C) = the audio's bit rate (per second)
- u16 loopCount; // (0x30) = # of times to loop audio (0 = no loop, 0xFFFF = inf loop)
- u16 channels; // (0x32) = # of interlaced channels in the audio data
- u8 _reserved; // (0x34)
- u8 fmt_version; // (0x35) = 0=kit_w32, 1=kit_sdl2
- u8 mode; // (0x36) = 0 for normal PCM or float data types
- u8 metadata_type; // (0x37) = 0 for no metadata
- void* samples; // (0x38) = the audio's sample data (appears as nullptr in file)
- void* userdata; // (0x40) = user-defined (also appears nullptr in file)
- // (0x48) = (start of sample data, assuming a .kpm file)
- void printHeader(const char* name = nullptr);
- };
- class AudioData { //24B
- u32 _type;
- bool _valid = false;
- bool _constructing = true;
- u16 _padding16;
- //used by both the 'only allocate' constructors
- void _allocate_hdr(u16 headerSize, u64 dataSize,
- const char* funcName = nullptr);
- //used by both of the 'load from file' constructors
- void _construct_file(const char* filePath, AudioDataLoaderCallback callback,
- const char* funcName = nullptr);
- public:
- //after exiting the constructor, hdr->samples is safe to use with SIMD
- //vector instructions/intriniscs (AudioDataLoaderCallbacks must
- //still use memory::alloc instead of allocSIMD though)!
- AudioDataHeader* hdr;
- f32 volumeL = 1.0f;
- f32 volumeR = 1.0f;
- //create with everything zeroed out, except headerSize, dataSize, and samples
- AudioData(u16 headerSize, u64 dataSize)
- { _allocate_hdr(headerSize, dataSize); }
- //create with zeroed out sample data
- AudioData(AudioSampleFormatEnum format,
- u64 numSamples, u16 channels, u32 sampleRate);
- //create from an audio file of a specific file format
- //(may reduce binary size if you only plan to use 1 file type or something)
- AudioData(const char* filePath, AudioDataLoaderCallback callback)
- { _construct_file(filePath, callback); }
- //create from an audio file of any supported format (.kpm, .wav, .qoa, .ogg)
- AudioData(const char* filePath);
- ~AudioData();
- inline void printHeader(const char* name = nullptr)
- { if(hdr != nullptr) hdr->printHeader(name); }
- //(this will overwrite any file named filePath! make sure to check
- //with fileio::exists() unless you intend to overwrite the previous file)
- void saveAudio(const char* filePath, AudioDataSaverCallback callback);
- //the conversion method used is slightly inaccurate for a number of reasons.
- //this function only serves as a convenience, where accuracy isn't
- //needed beyond sounding more or less the same.
- void convertFormat(AudioSampleFormatEnum format);
- //(this will return early if hdr->format == format,
- //since no conversion would be necessary)
- };
- }; /* namespace kit */
- #endif /* _INC__AUDIO_AUDIODATA_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"ksdl2_2024-11-07\_audio_SoundEngine.hpp":
- #ifndef _INC__AUDIO_SOUNDENGINE_HPP
- #define _INC__AUDIO_SOUNDENGINE_HPP
- #include "commondef.hpp"
- #include "_audio_types.hpp"
- namespace kit {
- class SoundEngine {
- u32 _type;
- bool _valid = false;
- bool _constructing = true;
- u16 _padding16;
- GenOpqPtr _tracks = nullptr;
- public:
- };
- }; /* namespace kit */
- #endif /* _INC__AUDIO_SOUNDENGINE_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"ksdl2_2024-11-07\kit_AudioData.cpp":
- #include "_kit_common.hpp"
- #define ADATA_IS_INVALID (!_valid && !_constructing)
- namespace kit {
- //#define DONT_USE_ALLOCSIMD //for debugging
- void AudioDataHeader::printHeader(const char* name){
- #ifdef _DEBUG
- //(SDL_Log adds \n automatically, but ignores the last \n if added manually)
- if(name != nullptr) kit_LogInfo("%s = {\n", name);
- else kit_LogInfo("%p = {\n", this);
- kit_LogInfo(" ->magic = \"%.4s\"; (0x%08X)\n", (char*)&magic, magic);
- const char* fmt_txt = "?";
- switch(format){
- case SMPFMT_U8 : fmt_txt = "U8"; break;
- case SMPFMT_S8 : fmt_txt = "S8"; break;
- case SMPFMT_U16LSB: fmt_txt = "U16LSB"; break;
- case SMPFMT_S16LSB: fmt_txt = "S16LSB"; break;
- case SMPFMT_S24LSB: fmt_txt = "S24LSB"; break;
- case SMPFMT_S32LSB: fmt_txt = "S32LSB"; break;
- case SMPFMT_F32LSB: fmt_txt = "F32LSB"; break;
- case SMPFMT_F64LSB: fmt_txt = "F64LSB"; break;
- case SMPFMT_U16MSB: fmt_txt = "U16MSB"; break;
- case SMPFMT_S16MSB: fmt_txt = "S16MSB"; break;
- case SMPFMT_S24MSB: fmt_txt = "S24MSB"; break;
- case SMPFMT_S32MSB: fmt_txt = "S32MSB"; break;
- case SMPFMT_F32MSB: fmt_txt = "F32MSB"; break;
- case SMPFMT_F64MSB: fmt_txt = "F64MSB"; break;
- default : fmt_txt = "UNKNOWN";
- }
- kit_LogInfo(" ->format = SMPFMT_%s; (0x%04X)\n", fmt_txt, format);
- kit_LogInfo(" ->headerSize = %u;\n", headerSize);
- kit_LogInfoS(" ->dataSize = %llu;\n", dataSize);
- kit_LogInfoS(" ->loopStart = %llu;\n", loopStart);
- kit_LogInfoS(" ->loopEnd = %llu;\n", loopEnd);
- kit_LogInfoS(" ->numSamples = %llu;\n", numSamples);
- kit_LogInfo(" ->sampleRate = %u;\n", sampleRate);
- kit_LogInfo(" ->bitRate = %u;\n", bitRate);
- kit_LogInfo(" ->loopCount = %u;\n", loopCount);
- kit_LogInfo(" ->channels = %u;\n", channels);
- kit_LogInfo(" ->_reserved = %u;\n", _reserved);
- kit_LogInfo(" ->fmt_version = %u;\n", fmt_version);
- kit_LogInfo(" ->mode = %u;\n", mode);
- kit_LogInfo(" ->metadata_type = %u;\n", metadata_type);
- kit_LogInfo(" ->samples = %p;\n", samples);
- kit_LogInfo(" ->userdata = %p;\n", userdata);
- kit_LogInfo("};");
- #else
- name = name; //be gone, unused parameter warning
- kit_LogWarn("\"AudioDataHeader::printHeader()\" is only available in the debug build!\n");
- #endif /* _DEBUG */
- }
- void AudioData::_allocate_hdr(u16 headerSize, u64 dataSize,
- const char* funcName)
- {
- if(_valid) return;
- _type = KIT_CLASSTYPE_AUDIODATA;
- if(funcName == nullptr)
- funcName = "AudioData::AudioData(raw allocation)";
- if(headerSize < sizeof(AudioDataHeader))
- THROW_ERRORF("%s: headerSize < sizeof(AudioDataHeader)", funcName);
- #ifndef DONT_USE_ALLOCSIMD
- hdr = (AudioDataHeader*)memory::allocSIMD(headerSize+dataSize);
- #else
- hdr = (AudioDataHeader*)memory::alloc(headerSize+dataSize);
- #endif /* DONT_USE_ALLOCSIMD */
- if(hdr == nullptr)
- THROW_ERRORF("%s: failed to allocate memory", funcName);
- memory::set(hdr, 0, headerSize+dataSize);
- hdr->headerSize = headerSize;
- hdr->dataSize = dataSize;
- hdr->samples = (u8*)hdr + hdr->headerSize;
- _valid = true;
- _constructing = false;
- }
- AudioData::AudioData(AudioSampleFormatEnum format,
- u64 numSamples, u16 channels, u32 sampleRate)
- {
- if(_valid) return;
- _type = KIT_CLASSTYPE_AUDIODATA;
- const u64 dataSize = KIT_AUDIO_BYTESIZE(format)*numSamples*channels;
- _allocate_hdr(sizeof(AudioDataHeader), dataSize,
- "AudioData::AudioData(formatted allocation)");
- hdr->magic = KIT_MAGIC_KPM;
- hdr->format = format;
- hdr->headerSize = sizeof(AudioDataHeader);
- hdr->dataSize = dataSize;
- hdr->loopStart = 0;
- hdr->loopEnd = numSamples;
- hdr->numSamples = numSamples;
- hdr->sampleRate = sampleRate;
- hdr->bitRate = KIT_AUDIO_BITSIZE(format)*sampleRate*channels;
- hdr->loopCount = 0;
- hdr->channels = 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 = (u8*)hdr + hdr->headerSize;
- hdr->userdata = nullptr;
- _valid = true;
- _constructing = false;
- }
- #define KIT_MAGIC_KPCM 0x4D43506B //.kpm's old file signature
- void AudioData::_construct_file(const char* filePath,
- AudioDataLoaderCallback callback,
- const char* funcName)
- {
- if(_valid) return;
- _type = KIT_CLASSTYPE_AUDIODATA;
- if(funcName == nullptr)
- funcName = "AudioData::AudioData(specific file format)";
- if(filePath == nullptr)
- THROW_ERRORF("%s: filePath = nullptr", funcName);
- if(!fileio::exists(filePath))
- THROW_ERRORF("%s: \"%s\" doesn't exist", funcName, filePath);
- AudioDataHeader* _hdr;
- if(callback == nullptr){ //load .kpm file
- size_t fileSize;
- _hdr = (AudioDataHeader*)fileio::readAll(filePath, &fileSize);
- //(assumes that _hdr != nullptr after this point)
- //check for the current and old version of .kpm's file signature
- //(but only if the fileSize is enough for a u32)
- if(fileSize >= sizeof(u32) &&
- (_hdr->magic != KIT_MAGIC_KPM && _hdr->magic != KIT_MAGIC_KPCM))
- {
- memory::free(&_hdr);
- THROW_ERRORF("%s: AudioDataLoadKPM used, but file is not a .kpm", funcName);
- }
- if(fileSize < sizeof(AudioDataHeader)){
- memory::free(&_hdr);
- THROW_ERRORF("%s: size of .kpm < sizeof(AudioDataHeader)", funcName);
- }
- /*
- if(_hdr->magic != KIT_MAGIC_KPM) throw "magic != KIT_MAGIC_KPM";
- if(!isFormatValid(_hdr->format)) throw "format is invalid";
- if(_hdr->headerSize < sizeof(AudioDataHeader)) throw "headerSize < sizeof(AudioDataHeader)";
- if(_hdr->dataSize != (fileSize-_hdr->headerSize)) throw "dataSize is invalid";
- //(channels are checked before numSamples to prevent divide-by-zero exceptions)
- if(_hdr->channels!=1 && _hdr->channels!=2) throw "audio is neither mono nor stereo";
- //(numSamples is checked before loopStart/loopEnd, as their checks rely upon numSamples)
- if(_hdr->numSamples != (_hdr->dataSize/KIT_ASTREAM_FMT_BYTESIZE(_hdr->format))/_hdr->channels) throw "numSamples is invalid";
- if(_hdr->loopStart >= _hdr->numSamples) throw "loopStart >= numSamples";
- if(_hdr->loopEnd > _hdr->numSamples) throw "loopEnd > numSamples";
- if(_hdr->sampleRate < 1000) throw "sampleRate < 1000";
- if(_hdr->bitRate != _hdr->sampleRate*_hdr->channels*KIT_ASTREAM_FMT_BITSIZE(_hdr->format)) throw "bitRate is invalid";
- if(_hdr->bitRemainder != 0) throw "bitRemainder != 0";
- if(_hdr->mode != 0) throw "only mode 0 kPCM files are currently supported";
- */
- //the only difference between 0 and 1 is that bitsPerSample is offset by -1
- if(_hdr->fmt_version == 0) ++_hdr->format;
- _hdr->magic = KIT_MAGIC_KPM; //if it was previously kPCM, now it is kPxM
- _hdr->fmt_version = 1; //
- } else {
- _hdr = callback(filePath);
- if(_hdr == nullptr)
- THROW_ERRORF("%s: callback returned as nullptr", funcName);
- }
- size_t totalSize = _hdr->headerSize + _hdr->dataSize;
- #ifndef DONT_USE_ALLOCSIMD
- hdr = (AudioDataHeader*)memory::allocSIMD(totalSize);
- #else
- hdr = (AudioDataHeader*)memory::alloc(totalSize);
- #endif /* DONT_USE_ALLOCSIMD */
- if(hdr == nullptr){
- memory::free(&_hdr);
- THROW_ERRORF("%s: failed to allocate memory", funcName);
- }
- memory::copy(hdr, _hdr, totalSize);
- memory::free(&_hdr);
- hdr->samples = (u8*)hdr + hdr->headerSize;
- _valid = true;
- _constructing = false;
- }
- //(the last constructor can be found in "kit_AudioData_LoadAllTypes.cpp")
- AudioData::~AudioData(){
- if(!_valid) return;
- _valid = false;
- #ifndef DONT_USE_ALLOCSIMD
- memory::freeSIMD(&hdr);
- #else
- memory::free(&hdr);
- #endif /* DONT_USE_ALLOCSIMD */
- }
- void AudioData::saveAudio(const char* filePath,
- AudioDataSaverCallback callback)
- {
- if(ADATA_IS_INVALID)
- THROW_ERROR("AudioData::saveAudio(): invalid AudioData");
- if(filePath == nullptr)
- THROW_ERROR("AudioData::saveAudio(): filePath = nullptr");
- if(callback == nullptr){ //save .kpm
- try {
- fileio::writeAll(filePath, hdr, hdr->headerSize+hdr->dataSize);
- } catch(const char* errorText){
- freeThreadErrors();
- THROW_ERRORF("AudioData::saveAudio(): \"%s\"", SDL_GetError());
- }
- } else {
- callback(filePath, *hdr);
- }
- }
- static bool _fmt_is_valid(u16 fmt){
- switch(fmt){
- case SMPFMT_U8 : SDL_FALLTHROUGH;
- case SMPFMT_S8 : SDL_FALLTHROUGH;
- case SMPFMT_U16: SDL_FALLTHROUGH;
- case SMPFMT_S16: SDL_FALLTHROUGH;
- case SMPFMT_S24: SDL_FALLTHROUGH;
- case SMPFMT_S32: SDL_FALLTHROUGH;
- case SMPFMT_F32: SDL_FALLTHROUGH;
- case SMPFMT_F64: return true; //lol
- default: return false;
- }
- }
- // = 2^(bits-1)
- #define ABS_S8_MIN (128) //ABS_Sx_MIN is a horrible name for this,
- #define ABS_S16_MIN (32768) //but it's the name i chose within 10 seconds
- #define ABS_S24_MIN (8388608) //(so i may or may not change it, idk)
- #define ABS_S32_MIN (2147483648)
- struct _s24 { u8 a, b, c; } //mostly for memory alignment purposes
- __attribute__((packed)); //(explicitly pack just in case; probably unnecessary)
- union _s24u {
- _s24 v;
- s32 n : 24;
- inline _s24u(_s24 _v) : v(_v) {}
- inline _s24u(s32 _n) : n(_n&KIT_S24_MAX) {}
- };
- static inline f64 frm_s24(_s24 x){ return (f64)_s24u(x).n/ABS_S24_MIN; }
- static inline _s24 to_s24(f64 x){ return _s24u((s32)(x*KIT_S24_MAX)).v; }
- void AudioData::convertFormat(AudioSampleFormatEnum format){
- if(ADATA_IS_INVALID)
- THROW_ERROR("AudioData::convertFormat(): invalid AudioData");
- if(hdr->format == format) return; //no need to convert anything; exit early
- if(!_fmt_is_valid(hdr->format))
- THROW_ERROR("AudioData::convertFormat(): unrecognized source format");
- if(!_fmt_is_valid(format))
- THROW_ERROR("AudioData::convertFormat(): unrecognized destination format");
- u64 totalSamples = hdr->numSamples*hdr->channels;
- u64 dataSize = KIT_AUDIO_BYTESIZE(format)*totalSamples;
- u32 bitRate = KIT_AUDIO_BITSIZE(format)*hdr->sampleRate*hdr->channels;
- try {
- memory::Wrapper temp_samples(totalSamples*sizeof(f64));
- f64* tmp = (f64*)temp_samples.ptr;
- void* smp = hdr->samples;
- #define FOR_TS_BRK(x) for(u64 i=0; i<totalSamples; ++i){ x; } break
- #define SMPCAST(_type) ( ((_type*)smp)[i] )
- #define FRM_CONV(_type, _scaling_factor, _modifier) \
- ( ((f64)SMPCAST(_type) _modifier) _scaling_factor )
- //convert all source samples to 64-bit floats
- switch(hdr->format){
- case SMPFMT_U8 : FOR_TS_BRK( tmp[i] = FRM_CONV(u8 , /ABS_S8_MIN , -128) );
- case SMPFMT_S8 : FOR_TS_BRK( tmp[i] = FRM_CONV(s8 , /ABS_S8_MIN , ) );
- case SMPFMT_U16: FOR_TS_BRK( tmp[i] = FRM_CONV(u16, /ABS_S16_MIN, -32768) );
- case SMPFMT_S16: FOR_TS_BRK( tmp[i] = FRM_CONV(s16, /ABS_S16_MIN, ) );
- case SMPFMT_S24: FOR_TS_BRK( tmp[i] = frm_s24(SMPCAST(_s24)) );
- case SMPFMT_S32: FOR_TS_BRK( tmp[i] = FRM_CONV(s32, /ABS_S32_MIN, ) );
- case SMPFMT_F32: FOR_TS_BRK( tmp[i] = FRM_CONV(f32, , ) );
- case SMPFMT_F64: memory::copy(tmp, smp, hdr->dataSize); break;
- }
- //resize header to match destination format's dataSize
- #ifndef DONT_USE_ALLOCSIMD
- if(!memory::reallocSIMD(&hdr, hdr->headerSize+dataSize))
- #else
- if(!memory::realloc(&hdr, hdr->headerSize+dataSize))
- #endif /* DONT_USE_ALLOCSIMD */
- throw "?"; //what is thrown doesn't matter as long as it's const char*
- //update relevant header values
- hdr->format = format;
- hdr->dataSize = dataSize;
- hdr->bitRate = bitRate;
- hdr->samples = (u8*)hdr + hdr->headerSize;
- smp = hdr->samples;
- #define TO_CONV(_type, _scl_fct, _mod) ( (_type)( tmp[i] _scl_fct _mod ) )
- //convert the f64 samples to the desired format
- switch(hdr->format){ //(hdr->format = format now)
- case SMPFMT_U8 : FOR_TS_BRK( SMPCAST( u8 ) = TO_CONV(u8 , *KIT_S8_MAX , +128) );
- case SMPFMT_S8 : FOR_TS_BRK( SMPCAST( s8 ) = TO_CONV(s8 , *KIT_S8_MAX , ) );
- case SMPFMT_U16: FOR_TS_BRK( SMPCAST( u16) = TO_CONV(u16, *KIT_S16_MAX, +32768) );
- case SMPFMT_S16: FOR_TS_BRK( SMPCAST( s16) = TO_CONV(s16, *KIT_S16_MAX, ) );
- case SMPFMT_S24: FOR_TS_BRK( SMPCAST(_s24) = to_s24(tmp[i]) );
- case SMPFMT_S32: FOR_TS_BRK( SMPCAST( s32) = TO_CONV(s32, *KIT_S32_MAX, ) );
- case SMPFMT_F32: FOR_TS_BRK( SMPCAST( f32) = TO_CONV(f32, , ) );
- case SMPFMT_F64: memory::copy(smp, tmp, hdr->dataSize); break;
- }
- } catch(const char* errorText){
- //the only 2 errors that should occur in that try block are failures
- //to allocate heap memory, so i'm just changing the function
- //name to indicate it occurred in this constructor specifically
- freeThreadErrors();
- THROW_ERROR("AudioData::convertFormat(): failed to allocate memory");
- }
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"ksdl2_2024-11-07\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 */
- /******************************************************************************/
- /******************************************************************************/
- //"ksdl2_2024-11-07\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 */
- /******************************************************************************/
- /******************************************************************************/
- //"ksdl2_2024-11-07\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 */
- /******************************************************************************/
- /******************************************************************************/
- //"ksdl2_2024-11-07\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 */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement