Advertisement
Kitomas

work for 2024-11-21 (1/10)

Nov 22nd, 2024
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 30.63 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"2024-11-21\src\kit_sdl2\kit_AudioData_LoadAllTypes.cpp":
  4. #include "_kit_common.hpp"
  5.  
  6.  
  7. namespace kit {
  8.  
  9.  
  10.  
  11.  
  12.  
  13. //file signatures
  14. //(KIT_MAGIC_KPM already defined in "_audio_AudioData.hpp")
  15. #define MAGIC_WAV 0x46464952 // = "RIFF"
  16. #define MAGIC_QOA 0x66616F71 // = "qoaf"
  17. #define MAGIC_OGG 0x5367674F // = "OggS"
  18.  
  19. //"RIFF" is not a .wav's actual file signature, rather it denotes the type
  20.  //of format used (like a format of formats of sorts), but i'm not going
  21.  //to add extra logic here to also read 4 bytes at offset 8 just to check for
  22.  //"WAVE" (which is its actual signature), because my wav parser already handles
  23.  //everything related to header validation anyway.
  24.  
  25.  
  26.  
  27.  
  28.  
  29. #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
  30.  
  31. AudioData::AudioData(const char* filePath){
  32.   const char* errTxt = "?";
  33.   if(0) _err: THROW_ERRORF("AudioData::AudioData(any file format): %s", errTxt);
  34.  
  35.  
  36.   if(filePath == nullptr)
  37.     GOTO_SET_ERROR("filePath = nullptr");
  38.  
  39.   if(!fileio::exists(filePath))
  40.     GOTO_SET_ERROR("file doesn't exist");
  41.  
  42.  
  43.  
  44.   u32 magic; //file signature, up to a maximum of 4 bytes
  45.  
  46.   if(  File(filePath,"rb").read(&magic, sizeof(magic))  <  sizeof(magic)  )
  47.   {
  48.     GOTO_SET_ERROR("failed to read first 4 bytes of file");
  49.   }
  50.  
  51.  
  52.  
  53.   AudioDataLoaderCallback callback;
  54.  
  55.   if(     magic == KIT_MAGIC_KPM) callback = nullptr;
  56.   else if(magic ==     MAGIC_WAV) callback = AudioDataLoadWAV;
  57.   else if(magic ==     MAGIC_QOA) callback = AudioDataLoadQOA;
  58.   else if(magic ==     MAGIC_OGG) callback = AudioDataLoadOGG;
  59.   else GOTO_SET_ERROR("unsupported file format");
  60.  
  61.  
  62.   _construct_file(filePath, callback, "AudioData::AudioData(any file format)");
  63.  
  64. }
  65.  
  66.  
  67.  
  68.  
  69.  
  70. }; /* namespace kit */
  71. /******************************************************************************/
  72. /******************************************************************************/
  73. //"2024-11-21\src\kit_sdl2\kit_AudioData_LoadOGG.cpp":
  74. #include "_kit_common.hpp"
  75.  
  76. #include "../stb_vorbis/stb_vorbis.hpp"
  77.  
  78. namespace kit {
  79.  
  80.  
  81.  
  82.  
  83.  
  84. #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
  85.  
  86. AudioDataHeader* AudioDataLoadOGG(const char* filePath){
  87.   const char* errTxt = "?";
  88.   if(0) _err: THROW_ERRORF("AudioDataLoadOGG(): %s", errTxt);
  89.  
  90.   if(!fileio::exists(filePath))
  91.     GOTO_SET_ERROR("file doesn't exist");
  92.  
  93.   BinaryData fileData(filePath);
  94.  
  95.   size_t fileSize = fileData.getSize();
  96.  
  97.   if(fileSize > KIT_S32_MAX)
  98.     GOTO_SET_ERROR("fileSize > KIT_S32_MAX");
  99.  
  100.  
  101.  
  102.   stb_vorbis* vrb = stb_vorbis_open_memory((u8*)fileData.getData(), fileSize,
  103.                                            nullptr, nullptr);
  104.  
  105.   if(vrb == nullptr)
  106.     GOTO_SET_ERROR("failed to open Ogg Vorbis stream from memory");
  107.  
  108.   stb_vorbis_info vrb_info = stb_vorbis_get_info(vrb);
  109.  
  110.   u32 numSamples = stb_vorbis_stream_length_in_samples(vrb);
  111.   u32 sampleRate = vrb_info.sample_rate;
  112.   s32 channels   = vrb_info.channels;
  113.  
  114.   if(channels > KIT_U16_MAX)
  115.     GOTO_SET_ERROR("channels > KIT_U16_MAX");
  116.  
  117.  
  118.  
  119.   AudioDataHeader hdr;
  120.  
  121.   hdr.magic         = KIT_MAGIC_KPM;
  122.   hdr.format        = SMPFMT_F32;
  123.   hdr.headerSize    = sizeof(AudioDataHeader);
  124.   hdr.dataSize      = sizeof(f32)*channels*numSamples;
  125.  
  126.   hdr.loopStart     = 0;
  127.   hdr.loopEnd       = numSamples;
  128.  
  129.   hdr.numSamples    = numSamples;
  130.   hdr.sampleRate    = sampleRate;
  131.   hdr.bitRate       = KIT_AUDIO_BITSIZE(SMPFMT_F32)*channels*sampleRate;
  132.  
  133.   hdr.loopCount     = 0;
  134.   hdr.channels      = channels;
  135.   hdr._reserved     = 0;
  136.   hdr.fmt_version   = 1;
  137.   hdr.mode          = 0;
  138.   hdr.metadata_type = 0;
  139.  
  140.   hdr.samples       = nullptr;
  141.   hdr.userdata      = nullptr;
  142.  
  143.  
  144.  
  145.   AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
  146.   if(_hdr == nullptr) GOTO_SET_ERROR("failed to allocate memory");
  147.  
  148.   *_hdr = hdr;
  149.   _hdr->samples = (u8*)_hdr + _hdr->headerSize;
  150.  
  151.   int amountDecoded = stb_vorbis_get_samples_float_interleaved(vrb, channels,
  152.                                                                (f32*)_hdr->samples,
  153.                                                                numSamples*channels);
  154.  
  155.   if((u32)amountDecoded < numSamples){
  156.     memory::free(&_hdr);
  157.     stb_vorbis_close(vrb);
  158.     GOTO_SET_ERROR("amountDecoded < numSamples");
  159.   }
  160.  
  161.  
  162.  
  163.   //tbd: add loop points to ogg loader
  164.   //stb_vorbis_comment comments = stb_vorbis_get_comment(vrb);
  165.   //error if loopStart >= numSamples, error if loopEnd > numSamples
  166.  
  167.  
  168.  
  169.   stb_vorbis_close(vrb);
  170.  
  171.   return _hdr;
  172.  
  173. }
  174.  
  175.  
  176.  
  177.  
  178.  
  179. }; /* namespace kit */
  180. /******************************************************************************/
  181. /******************************************************************************/
  182. //"2024-11-21\src\kit_sdl2\kit_AudioData_LoadSaveQOA.cpp":
  183. #include "_kit_common.hpp"
  184.  
  185. #define QOA_NO_STDIO
  186. #define QOA_MALLOC(sz) kit::memory::alloc(sz)
  187. #define QOA_FREE(p)    kit::memory::free(&p)
  188.  
  189.  
  190. namespace kit {
  191.  
  192.  
  193. namespace qoa {
  194.  
  195. #define QOA_IMPLEMENTATION
  196. //idk why this is defined, but it's in qoaconv.c so i'll keep it in to be safe
  197. #define QOA_RECORD_TOTAL_ERROR
  198. #include "../qoa/qoa.h"
  199.  
  200. }; /* namespace qoa */
  201.  
  202. //hopefully putting it in its own namespace will prevent any user naming conflicts
  203.  //(maybe it wouldn't have been a problem anyway, idk)
  204. using namespace qoa;
  205.  
  206.  
  207.  
  208.  
  209.  
  210. /*
  211.  
  212. struct {
  213.   u32 channels;
  214.   u32 samplerate;
  215.   u32 samples;
  216.   qoa_lms_t lms[QOA_MAX_CHANNELS];
  217.   #ifdef QOA_RECORD_TOTAL_ERROR
  218.     f64 error;
  219.   #endif
  220. } qoa_desc;
  221.  
  222. s16* qoa_decode(const u8* bytes, s32 size, qoa_desc* file);
  223.  
  224. void* qoa_encode(const s16* sample_data, qoa_desc* qoa, u32* out_len);
  225.  
  226. */
  227.  
  228.  
  229.  
  230.  
  231.  
  232. #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
  233.  
  234.  
  235.  
  236.  
  237.  
  238. #define MAGIC_QOA 0x66616F71 // = "qoaf"
  239.  
  240. AudioDataHeader* AudioDataLoadQOA(const char* filePath){
  241.   const char* errTxt = "?";
  242.   if(0) _err: THROW_ERRORF("AudioDataLoadQOA(): %s", errTxt);
  243.  
  244.   if(!fileio::exists(filePath))
  245.     GOTO_SET_ERROR("file doesn't exist");
  246.  
  247.   BinaryData _fileData(filePath);
  248.  
  249.  
  250.  
  251.   s32   fileSize = ( s32 )_fileData.getSize();
  252.   void* fileData = (void*)_fileData.getData(); //the ACTUAL file data
  253.  
  254.   if(_fileData.getSize() > KIT_S32_MAX)
  255.     GOTO_SET_ERROR("file is too large for a QOA (>2GiB)");
  256.  
  257.   //if(fileSize < ??)
  258.   //  GOTO_SET_ERROR("file is too small for a QOA (<??B)");
  259.  
  260.   if((*(u32*)fileData) != MAGIC_QOA)
  261.     GOTO_SET_ERROR("file is not a QOA audio file");
  262.  
  263.  
  264.  
  265.   qoa_desc smp_info;
  266.   memory::Wrapper _smp(qoa_decode((u8*)fileData, fileSize, &smp_info));
  267.   s16* smp = (s16*)_smp.ptr;
  268.  
  269.   if(smp == nullptr) GOTO_SET_ERROR("failed to decode QOA file data");
  270.  
  271.   if(smp_info.channels > KIT_U16_MAX)
  272.     GOTO_SET_ERROR("channels > KIT_U16_MAX");
  273.  
  274.   AudioDataHeader hdr;
  275.  
  276.   hdr.magic         = KIT_MAGIC_KPM;
  277.   hdr.format        = SMPFMT_S16;
  278.   hdr.headerSize    = sizeof(AudioDataHeader);
  279.   hdr.dataSize      = sizeof(s16)*smp_info.samples*smp_info.channels;
  280.  
  281.   hdr.loopStart     = 0;
  282.   hdr.loopEnd       = smp_info.samples;
  283.  
  284.   hdr.numSamples    = smp_info.samples;
  285.   hdr.sampleRate    = smp_info.samplerate;
  286.   hdr.bitRate       = KIT_AUDIO_BITSIZE(hdr.format)*smp_info.channels*smp_info.samplerate;
  287.  
  288.   hdr.loopCount     = 0;
  289.   hdr.channels      = smp_info.channels;
  290.   hdr._reserved     = 0;
  291.   hdr.fmt_version   = 1;
  292.   hdr.mode          = 0;
  293.   hdr.metadata_type = 0;
  294.  
  295.   hdr.samples       = nullptr;
  296.   hdr.userdata      = nullptr;
  297.  
  298.  
  299.  
  300.   AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
  301.   if(_hdr == nullptr) GOTO_SET_ERROR("failed to allocate memory");
  302.  
  303.   *_hdr = hdr;
  304.   _hdr->samples = (u8*)_hdr + _hdr->headerSize;
  305.   memory::copy(_hdr->samples, smp, _hdr->dataSize);
  306.  
  307.   return _hdr;
  308.  
  309. }
  310.  
  311.  
  312.  
  313.  
  314.  
  315. void AudioDataSaveQOA(const char* filePath,
  316.                       AudioDataHeader& header_in)
  317. {
  318.   const char* errTxt = "?";
  319.   if(0) _err: THROW_ERRORF("AudioDataSaveQOA(): %s", errTxt);
  320.  
  321.   if(header_in.format != SMPFMT_S16)
  322.     GOTO_SET_ERROR("format != SMPFMT_S16");
  323.  
  324.   if(header_in.numSamples > KIT_U32_MAX)
  325.     GOTO_SET_ERROR("numSamples > KIT_U32_MAX");
  326.  
  327.  
  328.  
  329.   qoa_desc smp_info;
  330.  
  331.   smp_info.channels   = header_in.channels;
  332.   smp_info.samplerate = header_in.sampleRate;
  333.   smp_info.samples    = header_in.numSamples;
  334.  
  335.   u32 fileSize;
  336.   memory::Wrapper fileData(qoa_encode((s16*)header_in.samples,
  337.                                        &smp_info, &fileSize));
  338.  
  339.   if(fileData.ptr == nullptr) GOTO_SET_ERROR("failed to encode QOA data");
  340.  
  341.  
  342.  
  343.   try {
  344.     File file(filePath, "wb");
  345.     file.write(fileData.ptr, fileSize);
  346.  
  347.   } catch(const char* errorText){
  348.     freeThreadErrors();
  349.     GOTO_SET_ERROR("failed to write to file");
  350.  
  351.   }
  352.  
  353. }
  354.  
  355.  
  356.  
  357.  
  358.  
  359. }; /* namespace kit */
  360. /******************************************************************************/
  361. /******************************************************************************/
  362. //"2024-11-21\src\kit_sdl2\kit_AudioData_LoadSaveWAV.cpp":
  363. #include "_kit_common.hpp"
  364.  
  365. namespace kit {
  366.  
  367. #define KIT_LOAD_WAV_MALLOC(_ptr) kit::memory::alloc(_ptr)
  368. #define KIT_LOAD_WAV_FREE(_ptr)   kit::memory::free(&_ptr)
  369.  
  370. #define KIT_LOAD_WAV_MEMSET(_ptr_or_arr, _value, _size) \
  371.   kit::memory::set((_ptr_or_arr), (_value), (_size))
  372.  
  373. #define KIT_LOAD_WAV_MEMCPY(_dst_ptr, _src_ptr, _size) \
  374.   kit::memory::copy((_dst_ptr), (_src_ptr), (_size))
  375.  
  376. #define KIT_LOAD_WAV_IMPLEMENTATION
  377. #define KIT_LOAD_WAV_CUSTOM_READ
  378.  
  379. #include "kit_load_wav.h"
  380.  
  381.  
  382.  
  383.  
  384.  
  385. void* kit_read_wav(const char* filePath, int32_t* fileSize_out){
  386.   if(!filePath) return NULL;
  387.  
  388.   size_t fileSize;
  389.   void* fileData = SDL_LoadFile(filePath, &fileSize);
  390.   if(!fileData) return NULL;
  391.  
  392.   if(fileSize > KIT_S32_MAX){
  393.     SDL_free(fileData);
  394.     return NULL;
  395.  
  396.   }
  397.  
  398.   //SDL_LoadFile calls SDL_malloc internally; increment # of allocations
  399.   ++numAllocations;
  400.  
  401.   if(fileSize_out) *fileSize_out = (int32_t)fileSize;
  402.  
  403.   return fileData;
  404.  
  405. }
  406.  
  407.  
  408.  
  409.  
  410.  
  411. #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
  412.  
  413. //(channels may be inaccurate if they use a different layout than SDL's channel mappings!)
  414. AudioDataHeader* AudioDataLoadWAV(const char* filePath){
  415.   const char* errTxt = "?";
  416.   if(0) _err: THROW_ERRORF("AudioDataLoadWAV(): %s", errTxt);
  417.  
  418.   if(!fileio::exists(filePath))
  419.     GOTO_SET_ERROR("file doesn't exist");
  420.  
  421.   int32_t _wavErr;
  422.   memory::Wrapper _wavData(kit_load_wav(filePath, &_wavErr));
  423.   kit_WavData* wavData = (kit_WavData*)_wavData.ptr;
  424.  
  425.   if(_wavErr != WAVEERROR_SUCCESS){
  426.     switch(_wavErr){
  427.       case WAVEERROR_NULLPTR   : errTxt = "non-optional argument pointer was nullptr";         break;
  428.       case WAVEERROR_FILE_READ : errTxt = "failed to read file";                               break;
  429.       case WAVEERROR_FILE_SIZE : errTxt = "fileSize was < 44 (minimum needed for header)";     break;
  430.       case WAVEERROR_NOT_RIFF  : errTxt = "first 4 bytes of file != \"RIFF\"";                 break;
  431.       case WAVEERROR_MALFORMED : errTxt = "wav has malformed data";                            break;
  432.       case WAVEERROR_NOT_WAVE  : errTxt = "4 bytes from offset 8 != \"WAVE\"";                 break;
  433.       case WAVEERROR_MALLOC    : _alloc_err: errTxt = "failed to allocate memory";             break;
  434.       case WAVEERROR_NO_FMT    : errTxt = "wav doesn't contain a f[or]m[a]t subchunk";         break;
  435.       case WAVEERROR_NO_DATA   : errTxt = "wav doesn't contain a data subchunk";               break;
  436.       case WAVEERROR_FORMAT    : _fmt_tag_err: errTxt = "wav uses an unsupported format tag";  break;
  437.       case WAVEERROR_CHANNELS  : errTxt = "channels = 0";                                      break;
  438.       case WAVEERROR_SAMPLERATE: errTxt = "sampleRate = 0";                                    break;
  439.       case WAVEERROR_BYTERATE  : errTxt = "byteRate !=  blockAlign*sampleRate";                break;
  440.       case WAVEERROR_BLOCKALIGN: errTxt = "blockAlign != (.channels*.bitsPerSample)/8";        break;
  441.       case WAVEERROR_BITSPERSMP: errTxt = "bitsPerSample%8 != 0  OR  = 0  OR  > 64";           break;
  442.       case WAVEERROR_EXTSIZE   : errTxt = "extensionSize < 22 (format tag is EXTENSIBLE)";     break;
  443.       case WAVEERROR_VALIDBITS : errTxt = "validBits > bitsPerSample  OR  validBits = 0";      break;
  444.       default                  : _unknown_err: errTxt = "unknown error";                       break;
  445.     }
  446.  
  447.     goto _err;
  448.  
  449.   }
  450.  
  451.   if(wavData == nullptr) goto _unknown_err; //this one should be impossible, but just in case
  452.   if(!wavData->samples_type) goto _unknown_err;
  453.  
  454.  
  455.  
  456.   //convert kit_WavData_type to that of AudioSampleFormatEnum (AKA SDL_AudioFormat)
  457.   kit_WavData_type wavType;
  458.   wavType.value = wavData->samples_type;
  459.  
  460.   if(wavType.totalBits != wavType.validBits)
  461.     GOTO_SET_ERROR("bitsPerSample != validBits");
  462.  
  463.   if(wavType.format != WAVEDATA_FORMAT_PCM  &&  wavType.format != WAVEDATA_FORMAT_FLOAT)
  464.     goto _fmt_tag_err; //(WAVEDATA_FORMAT_<ALAW/ULAW> aren't allowed currently)
  465.  
  466.   u16 format = (wavType.value&0x803F) + 1;
  467.   if(wavType.format == WAVEDATA_FORMAT_FLOAT) format |= 0x8100;
  468.  
  469.  
  470.  
  471.   AudioDataHeader hdr;
  472.   hdr.magic         = KIT_MAGIC_KPM;
  473.   hdr.format        = format;
  474.   hdr.headerSize    = sizeof(AudioDataHeader);
  475.   hdr.dataSize      = wavData->samples_size;
  476.  
  477.   hdr.loopStart     = 0;
  478.   hdr.loopEnd       = wavData->samples_len;
  479.  
  480.   hdr.numSamples    = wavData->samples_len;
  481.   hdr.sampleRate    = wavData->sampleRate;
  482.   hdr.bitRate       = KIT_AUDIO_BITSIZE(format)*wavData->sampleRate*wavData->channels;
  483.  
  484.   hdr.loopCount     = 0;
  485.   hdr.channels      = wavData->channels;
  486.   hdr._reserved     = 0;
  487.   hdr.fmt_version   = 1; //1 indicates the version kit_sdl2 uses
  488.   hdr.mode          = 0; //PCM or float data
  489.   hdr.metadata_type = 0; //no metadata
  490.  
  491.   hdr.samples       = nullptr;
  492.   hdr.userdata      = nullptr;
  493.  
  494.  
  495.  
  496.   AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
  497.   if(_hdr == nullptr) goto _alloc_err;
  498.  
  499.   *_hdr = hdr;
  500.   _hdr->samples = (u8*)_hdr + _hdr->headerSize;
  501.   memory::copy(_hdr->samples, wavData->samples, _hdr->dataSize);
  502.  
  503.   return _hdr;
  504.  
  505. }
  506.  
  507.  
  508.  
  509.  
  510.  
  511. struct _WavHeader { //the whole thing (for convenience)
  512.   u32 file_id;           // = 0x46464952 = "RIFF"
  513.   u32 file_size;         // = file's total size - 8
  514.   u32 file_id2;          // = 0x45564157 = "WAVE"
  515.  
  516.   u32 fmt_id;            // = 0x20746D66 = "fmt "
  517.   u32 fmt_size;          // = 16
  518.   u16 fmt_format;        // = 3 if float, 1 if PCM
  519.   u16 fmt_channels;      // = # of interleaved channels; L&R for stereo (2)
  520.   u32 fmt_sampleRate;    // = # of sample frames per second
  521.   u32 fmt_byteRate;      // = blockAlign*sampleRate
  522.   u16 fmt_blockAlign;    // = size of sample frame (channels*bitsPerSample)/8
  523.   u16 fmt_bitsPerSample; // (Assumed to be unsigned if 8 and .format is PCM)
  524.  
  525.   u32 data_id;           // = 0x61746164 = "data"
  526.   u32 data_size;         // = size of sample data, in bytes
  527.  
  528.   //(sample data starts here)
  529.  
  530. };
  531.  
  532.  
  533.  
  534. #define SV_ASSERT(_success, _error_text) \
  535.   if(!(_success)){ errTxt = _error_text; goto _err; }
  536.  
  537.  
  538.  
  539. void AudioDataSaveWAV(const char* filePath,
  540.                       AudioDataHeader& header_in)
  541. {
  542.   const char* errTxt = "?";
  543.   if(0) _err: THROW_ERRORF("AudioDataSaveWAV(): %s", errTxt);
  544.  
  545.   //stack copy, so i can't accidentally change values of the original header
  546.   AudioDataHeader hdri = header_in;
  547.  
  548.   SV_ASSERT(hdri.fmt_version == 1, "fmt_version != 1");
  549.   SV_ASSERT(!( KIT_AUDIO_ISSIGNED(hdri.format) && KIT_BITSPERPIXEL(hdri.format)<=8 ),
  550.             "samples 8-bits and below must be unsigned");
  551.  
  552.  
  553.  
  554.   //round bits UP to the nearest byte (as in a multiple of 8 bits)
  555.   #define BYTE_CEIL(_num) (((_num)+7)&(~7))
  556.  
  557.   _WavHeader hdro;
  558.  
  559.   hdro.file_id           = wid_RIFF;
  560.   hdro.file_size         = sizeof(_WavHeader) + hdri.dataSize - 8;
  561.   hdro.file_id2          = wid_WAVE;
  562.  
  563.   hdro.fmt_id            = wid_fmt_;
  564.   hdro.fmt_size          = 16;
  565.   hdro.fmt_format        = KIT_AUDIO_ISFLOAT(hdri.format) ? 3 : 1;
  566.   hdro.fmt_channels      = hdri.channels;
  567.   hdro.fmt_sampleRate    = hdri.sampleRate;
  568.   hdro.fmt_byteRate      = BYTE_CEIL(hdri.bitRate)/8;
  569.   hdro.fmt_blockAlign    = BYTE_CEIL(hdri.channels*KIT_AUDIO_BITSIZE(hdri.format))/8;
  570.   hdro.fmt_bitsPerSample = KIT_AUDIO_BITSIZE(hdri.format);
  571.  
  572.   hdro.data_id           = wid_data;
  573.   hdro.data_size         = hdri.dataSize;
  574.  
  575.  
  576.  
  577.   try {
  578.     File file(filePath, "wb");
  579.  
  580.     file.write(&hdro, sizeof(hdro));
  581.     file.write(hdri.samples, hdri.dataSize);
  582.  
  583.   } catch(const char* errorText){
  584.     freeThreadErrors();
  585.     GOTO_SET_ERROR("failed to write to file");
  586.  
  587.   }
  588.  
  589. }
  590.  
  591.  
  592.  
  593.  
  594.  
  595. }; /* namespace kit */
  596. /******************************************************************************/
  597. /******************************************************************************/
  598. //"2024-11-21\src\kit_sdl2\kit_AudioDevice.cpp":
  599. #include "_kit_common.hpp"
  600.  
  601. #define INDEX_FUNC "AudioDevice::AudioDevice(index)"
  602. #define NAME_FUNC  "AudioDevice::AudioDevice(name)"
  603.  
  604. #define DEVICE_IS_INVALID (!_valid)
  605.  
  606. //i don't think i ended up using these lol
  607. #define CONSTRUCTOR_ERR(_txt) PUSH_ERRORF("%s: " _txt , funcname)
  608. #define CONSTRUCTOR_ERRSDL    PUSH_ERRORF("%s: %s", funcname, SDL_GetError())
  609.  
  610. #define DEV_PTR ((_AudioDeviceOpaque*)_opq)
  611.  
  612.  
  613. namespace kit {
  614.  
  615.  
  616.  
  617.  
  618.  
  619. //in "kit_AudioCallbackWrapper.cpp"
  620. void _AudioCallbackWrapper(void* userdata, u8* _stream, int len);
  621.  
  622.  
  623.  
  624.  
  625.  
  626. static inline u32 _count_bits(u32 num){
  627.   u32 count = 0;
  628.  
  629.   while(num > 0){
  630.     if(num&1) ++count;
  631.     num >>= 1;
  632.   }
  633.  
  634.   return count;
  635.  
  636. }
  637.  
  638.  
  639. //not inlined
  640. bool _validate_smpfmt(u16 sampleFormat, bool allow0 = false){
  641.   switch(sampleFormat){
  642.     case SMPFMT_U8    :
  643.     case SMPFMT_S8    :
  644.     case SMPFMT_U16LSB:
  645.     case SMPFMT_S16LSB:
  646.   //case SMPFMT_U16MSB:
  647.   //case SMPFMT_S16MSB:
  648.     case SMPFMT_S32LSB:
  649.   //case SMPFMT_S32MSB:
  650.     case SMPFMT_F32LSB:
  651.   //case SMPFMT_F32MSB:
  652.     break;
  653.  
  654.     case 0:
  655.       if(allow0) break;
  656.       else SDL_FALLTHROUGH;
  657.  
  658.     default:
  659.       return false;
  660.  
  661.   }
  662.  
  663.   return true;
  664.  
  665. }
  666.  
  667.  
  668. static inline void validate_desired(const AudioDeviceInfo& desired,
  669.                                     const char* funcname)
  670. {
  671.   if(desired.sampleRate > KIT_S32_MAX)
  672.     THROW_ERRORF("%s: desired.sampleRate > KIT_S32_MAX", funcname);
  673.  
  674.   //this isn't strictly necessary, as my machine (windows, currently) seems to
  675.    //accept frame counts that aren't powers of 2. however it might be best
  676.    //practice to use powers of 2 in case the target system doesn't support it.
  677. /*if(_count_bits(desired.sampleFrames) > 1)
  678.     THROW_ERRORF("%s: desired.sampleFrames is not a power of 2", funcname);*/
  679.  
  680.   if(!_validate_smpfmt(desired.sampleFormat, true)){
  681.     THROW_ERRORF("%s: desired.sampleFormat of 0x%04X is invalid",
  682.                       funcname, desired.sampleFormat);
  683.   }
  684.  
  685.   if(desired.numChannels > 8)
  686.     THROW_ERRORF("%s: desired.numChannels > 8", funcname);
  687.  
  688.   if(desired.callback == nullptr)
  689.     THROW_ERRORF("%s: desired.callback = nullptr", funcname);
  690.  
  691. }
  692.  
  693.  
  694. static inline s32 get_dev_params(SDL_AudioSpec& want,
  695.                                  const AudioDeviceInfo& desired,
  696.                                  AudioDevice* device)
  697. {
  698.   want.freq     = (s32)((desired.sampleRate) ? desired.sampleRate : 48000);
  699.   want.format   = AUDIO_F32LSB;
  700.   want.channels = (desired.numChannels) ? desired.numChannels : 2;
  701.   want.samples  = (desired.sampleFrames) ? desired.sampleFrames : 4096;
  702.   want.callback = _AudioCallbackWrapper;
  703.   want.userdata = device;
  704.  
  705.   s32 allowed_changes = 0;
  706.   if(!desired.sampleRate  ) allowed_changes |= SDL_AUDIO_ALLOW_FREQUENCY_CHANGE;
  707.   //underlying stream must be f32, so this one should never be set
  708. //if(!desired.sampleFormat) allowed_changes |= SDL_AUDIO_ALLOW_FORMAT_CHANGE;
  709.   if(!desired.numChannels ) allowed_changes |= SDL_AUDIO_ALLOW_CHANNELS_CHANGE;
  710.   if(!desired.sampleFrames) allowed_changes |= SDL_AUDIO_ALLOW_SAMPLES_CHANGE;
  711.  
  712.   return allowed_changes;
  713.  
  714. }
  715.  
  716.  
  717. static inline AudioDeviceInfo set_dev_info(SDL_AudioDeviceID      deviceID,
  718.                                            SDL_AudioSpec          have,
  719.                                            const AudioDeviceInfo& desired)
  720. {
  721.   AudioDeviceInfo info;
  722. //info.timeStartTicks  = 0;
  723. //info.timeStartMS     = 0;
  724.   info.deviceID        = deviceID;
  725.   info.sampleRate      = have.freq;
  726.   info.sampleFrames    = have.samples;
  727.   info.sampleFormat    = have.format;
  728.   info.sampleFrameSize = KIT_AUDIO_BYTESIZE(have.format)*have.channels;
  729.   info.numChannels     = have.channels;
  730.   info.isInput         = desired.isInput;
  731.   info.zeroBuffer      = desired.zeroBuffer;
  732.   info.callback        = desired.callback;
  733.   info.userdata        = desired.userdata;
  734.  
  735.   return info;
  736.  
  737. }
  738.  
  739.  
  740.  
  741.  
  742.  
  743. AudioDevice::AudioDevice(s32 index, //-1 to use default device
  744.                          const AudioDeviceInfo& desired,
  745.                          bool disableFadeDelay)
  746. {
  747.   const char* name = nullptr;
  748.  
  749.   if(index >= 0){
  750.     name = SDL_GetAudioDeviceName(index, desired.isInput);
  751.  
  752.     if(name == nullptr)
  753.       THROW_ERRORF(INDEX_FUNC ": \"%s\"", SDL_GetError());
  754.  
  755.   }
  756.  
  757.   _construct(name, desired, disableFadeDelay);
  758.  
  759. }
  760.  
  761.  
  762.  
  763.  
  764.  
  765. void AudioDevice::_construct(const char* name,
  766.                              const AudioDeviceInfo& desired,
  767.                              bool disableFadeDelay,
  768.                              bool indexed)
  769. {
  770.   if(_valid) return;
  771.   _type = KIT_CLASSTYPE_AUDIODEVICE;
  772.  
  773.   const char* funcname = (indexed) ? INDEX_FUNC : NAME_FUNC;
  774.  
  775.   AudioDeviceInfo* info_p = (AudioDeviceInfo*)&info; //info is normally const
  776.  
  777.  
  778.  
  779.   //a few domain checks
  780.   validate_desired(desired, funcname);
  781.  
  782.   SDL_AudioSpec want, have;
  783.   s32 allowed_changes = get_dev_params(want, desired, this);
  784.  
  785.  
  786.  
  787.   //actually create the device
  788.   SDL_AudioDeviceID deviceID = SDL_OpenAudioDevice(name, desired.isInput,
  789.                                                    &want, &have, allowed_changes);
  790.  
  791.   if(!deviceID) THROW_ERRORF("%s: %s", funcname, SDL_GetError());
  792.  
  793.   if(desired.sampleFormat) have.format = desired.sampleFormat;
  794.  
  795.   *info_p = set_dev_info(deviceID, have, desired);
  796.  
  797.  
  798.  
  799.   _opq = memory::alloc(sizeof(_AudioDeviceOpaque));
  800.  
  801.   if(_opq == nullptr){
  802.     SDL_CloseAudioDevice(info.deviceID);
  803.     THROW_ERRORF("%s: failed to allocate memory for opaque struct", funcname);
  804.  
  805.   }
  806.  
  807.   memory::set(_opq, 0, sizeof(_AudioDeviceOpaque));
  808.  
  809.  
  810.  
  811.   DEV_PTR->info_p      = info_p;
  812.   DEV_PTR->buffer_size = info.sampleFrames * info.sampleFrameSize;
  813.   DEV_PTR->buffer      = memory::allocSIMD(DEV_PTR->buffer_size);
  814.   DEV_PTR->fadeDelta   = 1.0f / ((f32)info.sampleRate*FADEDELTA_SEC);
  815. //DEV_PTR->fadeVolume  = 0.0f; //(the prior memset makes setting to 0 redundant)
  816. //DEV_PTR->fadeDelay   = 0;
  817. //DEV_PTR->fadeOut     = false;
  818.   DEV_PTR->noFadeDelay = disableFadeDelay;
  819. //DEV_PTR->playing     = false;
  820.  
  821.   if(DEV_PTR->buffer == nullptr){
  822.     memory::free(&_opq);
  823.     SDL_CloseAudioDevice(info.deviceID);
  824.     THROW_ERRORF("%s: failed to allocate memory for audio buffer", funcname);
  825.  
  826.   }
  827.  
  828.   memory::set(DEV_PTR->buffer, 0, DEV_PTR->buffer_size);
  829.  
  830.  
  831.  
  832.   _valid = true;
  833.   _constructing = false;
  834.  
  835. }
  836.  
  837.  
  838.  
  839.  
  840.  
  841. AudioDevice::~AudioDevice(){
  842.   if(!_valid) return;
  843.   _valid = false;
  844.  
  845.   if(info.deviceID != 0) SDL_CloseAudioDevice(info.deviceID);
  846.   if(_opq != nullptr){
  847.     memory::freeSIMD(&DEV_PTR->buffer);
  848.     memory::free(&_opq);
  849.   }
  850.  
  851. }
  852.  
  853.  
  854.  
  855.  
  856.  
  857. bool AudioDevice::isPlaying(){
  858.   if(DEVICE_IS_INVALID)
  859.     THROW_ERROR("AudioDevice::isPlaying(): invalid AudioDevice");
  860.  
  861.   //return SDL_GetAudioDeviceStatus(info.deviceID) == SDL_AUDIO_PLAYING;
  862.   return DEV_PTR->playing;
  863.  
  864. }
  865.  
  866.  
  867.  
  868.  
  869.  
  870. bool AudioDevice::isActive(){
  871.   if(DEVICE_IS_INVALID)
  872.     THROW_ERROR("AudioDevice::isActive(): invalid AudioDevice");
  873.  
  874.   return SDL_GetAudioDeviceStatus(info.deviceID) == SDL_AUDIO_PLAYING;
  875.   //return DEV_PTR->playing;
  876.  
  877. }
  878.  
  879.  
  880.  
  881.  
  882.  
  883. void AudioDevice::setCallback(AudioCallback callback){
  884.   if(DEVICE_IS_INVALID)
  885.     THROW_ERROR("AudioDevice::setCallback(): invalid AudioDevice");
  886.  
  887.   if(callback == nullptr)
  888.     THROW_ERROR("AudioDevice::setCallback(): callback = nullptr");
  889.  
  890.   SDL_LockAudioDevice(info.deviceID);
  891.  
  892.   ((AudioDeviceInfo*)&info)->callback = callback;
  893.  
  894.   SDL_UnlockAudioDevice(info.deviceID);
  895.  
  896. }
  897.  
  898.  
  899.  
  900.  
  901. void AudioDevice::setUserdata(void* userdata){
  902.   if(DEVICE_IS_INVALID)
  903.     THROW_ERROR("AudioDevice::setUserdata(): invalid AudioDevice");
  904.  
  905.   SDL_LockAudioDevice(info.deviceID);
  906.  
  907.   ((AudioDeviceInfo*)&info)->userdata = userdata;
  908.  
  909.   SDL_UnlockAudioDevice(info.deviceID);
  910.  
  911. }
  912.  
  913.  
  914.  
  915.  
  916. void AudioDevice::setPlayback(bool playing){
  917.   if(DEVICE_IS_INVALID)
  918.     THROW_ERROR("AudioDevice::setPlayback(): invalid AudioDevice");
  919.  
  920.  
  921.   //this should occur when _AudioCallbackWrapper
  922.    //fails to trigger the pause thread
  923.   if(DEV_PTR->fadeDelay == KIT_U32_MAX){
  924.     SDL_LockAudioDevice(info.deviceID);
  925.  
  926.     SDL_PauseAudioDevice(info.deviceID, true);
  927.  
  928.     DEV_PTR->fadeVolume = 0.0f;
  929.     DEV_PTR->fadeDelay  = 0;
  930.     DEV_PTR->fadeOut    = false;
  931.     DEV_PTR->playing    = false;
  932.  
  933.     SDL_UnlockAudioDevice(info.deviceID);
  934.  
  935.   }
  936.  
  937.  
  938.   DEV_PTR->fadeOut = !playing;
  939.   if(playing && !DEV_PTR->playing){
  940.     //the purpose of fadeDelay is to mute for some samples
  941.      //to give the sdl audio device some time to warm up,
  942.      //otherwise artifacts start to occur (for me, anyway)
  943.     if(!DEV_PTR->noFadeDelay) DEV_PTR->fadeDelay = (u32)(info.sampleRate * FADEDELAY_SEC);
  944.     else                      DEV_PTR->fadeDelay = 0;
  945.  
  946.     DEV_PTR->fadeVolume = 0.0f;
  947.     DEV_PTR->playing    = true;
  948.  
  949.     SDL_PauseAudioDevice(info.deviceID, false);
  950.  
  951.   }
  952.  
  953. }
  954.  
  955.  
  956.  
  957.  
  958. void AudioDevice::setPlaybackAndWait(bool playing){
  959.   if(DEVICE_IS_INVALID)
  960.     THROW_ERROR("AudioDevice::setPlaybackAndWait(): invalid AudioDevice");
  961.  
  962.  
  963.   bool wasPlaying = DEV_PTR->playing;
  964.  
  965.   setPlayback(playing);
  966.  
  967.  
  968.   if(playing && !wasPlaying && !DEV_PTR->noFadeDelay){
  969.     time::sleep((u32)( FADETOTAL_SEC*1000 ));
  970.  
  971.   } else {
  972.     time::sleep((u32)( FADEDELTA_SEC*1000 ));
  973.  
  974.   }
  975.  
  976. }
  977.  
  978.  
  979.  
  980.  
  981.  
  982. void AudioDevice::lock(bool locked){
  983.   if(DEVICE_IS_INVALID)
  984.     THROW_ERROR("AudioDevice::lock(): invalid AudioDevice");
  985.  
  986.   if(locked) SDL_LockAudioDevice(info.deviceID);
  987.   else       SDL_UnlockAudioDevice(info.deviceID);
  988.  
  989. }
  990.  
  991.  
  992.  
  993.  
  994.  
  995. }; /* namespace kit */
  996. /******************************************************************************/
  997. /******************************************************************************/
  998. //"2024-11-21\src\kit_sdl2\kit_AudioStream.cpp":
  999. #include "_kit_common.hpp"
  1000.  
  1001. #define STREAM_IS_INVALID (!_valid)
  1002.  
  1003. #define STRM_PTR ((SDL_AudioStream*)_opq)
  1004.  
  1005.  
  1006. namespace kit {
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012. bool _validate_smpfmt(u16 sampleFormat, bool allow0 = false);
  1013.  
  1014.  
  1015.  
  1016.  
  1017.  
  1018. AudioStream::AudioStream(const AudioDeviceInfo* src_p,
  1019.                          const AudioDeviceInfo* dst_p)
  1020. {
  1021.   if(_valid) return;
  1022.   _type = KIT_CLASSTYPE_AUDIOSTREAM;
  1023.  
  1024.  
  1025.   if(src_p == nullptr) THROW_ERROR("AudioStream::AudioStream(): src_p = nullptr");
  1026.   if(dst_p == nullptr) THROW_ERROR("AudioStream::AudioStream(): dst_p = nullptr");
  1027.  
  1028.  
  1029.   if(src_p->sampleRate > KIT_S32_MAX)
  1030.     THROW_ERROR("AudioStream::AudioStream(): src_p->sampleRate > KIT_S32_MAX");
  1031.  
  1032.   if(dst_p->sampleRate > KIT_S32_MAX)
  1033.     THROW_ERROR("AudioStream::AudioStream(): dst_p->sampleRate > KIT_S32_MAX");
  1034.  
  1035.  
  1036.   if(!_validate_smpfmt(src_p->sampleFormat))
  1037.     THROW_ERROR("AudioStream::AudioStream(): src_p->sampleFormat is invalid");
  1038.  
  1039.   if(!_validate_smpfmt(dst_p->sampleFormat))
  1040.     THROW_ERROR("AudioStream::AudioStream(): dst_p->sampleFormat is invalid");
  1041.  
  1042.  
  1043.   if(src_p->numChannels == 0  ||  src_p->numChannels > 8)
  1044.     THROW_ERROR("AudioStream::AudioStream(): src_p->numChannels must be 1 -> 8");
  1045.  
  1046.   if(dst_p->numChannels == 0  ||  dst_p->numChannels > 8)
  1047.     THROW_ERROR("AudioStream::AudioStream(): dst_p->numChannels must be 1 -> 8");
  1048.  
  1049.  
  1050.  
  1051.   //since src and dst are normally const,
  1052.    //they're punned so that they can be set
  1053.   AudioDeviceInfo* _src_p = (AudioDeviceInfo*)&src;
  1054.   AudioDeviceInfo* _dst_p = (AudioDeviceInfo*)&dst;
  1055.  
  1056.   *_src_p = *src_p;
  1057.   *_dst_p = *dst_p;
  1058.  
  1059.   _src_p->sampleFrameSize = src.numChannels * KIT_AUDIO_BYTESIZE(src.sampleFormat);
  1060.   _dst_p->sampleFrameSize = dst.numChannels * KIT_AUDIO_BYTESIZE(dst.sampleFormat);
  1061.  
  1062.  
  1063.   _opq = SDL_NewAudioStream(src.sampleFormat, src.numChannels, (s32)src.sampleRate,
  1064.                             dst.sampleFormat, dst.numChannels, (s32)dst.sampleRate);
  1065.  
  1066.   if(_opq == nullptr)
  1067.     THROW_ERRORF("AudioStream::AudioStream(): \"%s\"", SDL_GetError());
  1068.  
  1069.   ++numAllocations;
  1070.  
  1071.  
  1072.   _valid = true;
  1073.   _constructing = false;
  1074.  
  1075. }
  1076.  
  1077.  
  1078.  
  1079.  
  1080. AudioStream::~AudioStream(){
  1081.   if(!_valid) return;
  1082.   _valid = false;
  1083.  
  1084.   if(_opq != nullptr){
  1085.     SDL_FreeAudioStream(STRM_PTR);
  1086.     _opq = nullptr;
  1087.     --numAllocations;
  1088.  
  1089.   }
  1090.  
  1091. }
  1092.  
  1093.  
  1094.  
  1095.  
  1096.  
  1097. u32 AudioStream::getAvailableBytes(){
  1098.   if(STREAM_IS_INVALID)
  1099.     THROW_ERROR("AudioStream::getNumAvailable(): invalid AudioStream");
  1100.  
  1101.   s32 result = SDL_AudioStreamAvailable(STRM_PTR);
  1102.  
  1103.   if(result < 0)
  1104.     THROW_ERRORF("AudioStream::getNumAvailable(): \"%s\"", SDL_GetError());
  1105.  
  1106.   return (u32)result;
  1107.  
  1108. }
  1109.  
  1110.  
  1111.  
  1112.  
  1113.  
  1114. void AudioStream::flush(){
  1115.   if(STREAM_IS_INVALID)
  1116.     THROW_ERROR("AudioStream::flush(): invalid AudioStream");
  1117.  
  1118.   //as of 2024-08-03, the SDL2 wiki does not even tell you what this returns,
  1119.    //but most SDL calls with int returns of this type use 0 and -1 for
  1120.    //success and failure respectively. so, hopefully my hunch is right :D
  1121.   if(SDL_AudioStreamFlush(STRM_PTR) != 0)
  1122.     THROW_ERRORF("AudioStream::flush(): \"%s\"", SDL_GetError());
  1123.  
  1124. }
  1125.  
  1126.  
  1127.  
  1128.  
  1129.  
  1130. void AudioStream::clear(){
  1131.   if(STREAM_IS_INVALID)
  1132.     THROW_ERROR("AudioStream::clear(): invalid AudioStream");
  1133.  
  1134.   SDL_AudioStreamClear(STRM_PTR);
  1135.  
  1136. }
  1137.  
  1138.  
  1139.  
  1140.  
  1141.  
  1142. u32 AudioStream::get(void* buffer_dst, u32 buffer_size){
  1143.   if(STREAM_IS_INVALID)
  1144.     THROW_ERROR("AudioStream::get(): invalid AudioStream");
  1145.  
  1146.   if(buffer_dst == nullptr)
  1147.     THROW_ERROR("AudioStream::get(): buffer_dst = nullptr");
  1148.  
  1149.   if(buffer_size > KIT_S32_MAX)
  1150.     THROW_ERROR("AudioStream::get(): buffer_size > KIT_S32_MAX");
  1151.  
  1152.  
  1153.   s32 result = SDL_AudioStreamGet(STRM_PTR, buffer_dst, buffer_size);
  1154.  
  1155.   if(result < 0)
  1156.     THROW_ERRORF("AudioStream::get(): \"%s\"", SDL_GetError());
  1157.  
  1158.   return (u32)result;
  1159.  
  1160. }
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166. void AudioStream::put(void* buffer_src, u32 buffer_size){
  1167.   if(STREAM_IS_INVALID)
  1168.     THROW_ERROR("AudioStream::put(): invalid AudioStream");
  1169.  
  1170.   if(buffer_src == nullptr)
  1171.     THROW_ERROR("AudioStream::put(): buffer_src = nullptr");
  1172.  
  1173.   if(buffer_size > KIT_S32_MAX)
  1174.     THROW_ERROR("AudioStream::put(): buffer_size > KIT_S32_MAX");
  1175.  
  1176.  
  1177.   if(SDL_AudioStreamPut(STRM_PTR, buffer_src, buffer_size) < 0)
  1178.     THROW_ERRORF("AudioStream::put(): \"%s\"", SDL_GetError());
  1179.  
  1180. }
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186. }; /* namespace kit */
  1187.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement