Advertisement
Kitomas

work for 2024-11-07

Nov 7th, 2024
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 36.39 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"ksdl2_2024-11-07\kit_SoundEngine.cpp":
  4. #include "_kit_common.hpp"
  5.  
  6. #define SNDENGINE_IS_INVALID (!_valid && !_constructing)
  7.  
  8.  
  9. namespace kit {
  10.  
  11.  
  12.  
  13.  
  14.  
  15. //
  16.  
  17.  
  18.  
  19.  
  20.  
  21. }; /* namespace kit */
  22. /******************************************************************************/
  23. /******************************************************************************/
  24. //"ksdl2_2024-11-07\_audio_AudioData.hpp":
  25. #ifndef _INC__AUDIO_AUDIODATA_HPP
  26. #define _INC__AUDIO_AUDIODATA_HPP
  27.  
  28. #include "commondef.hpp"
  29. #include "_audio_types.hpp"
  30.  
  31.  
  32. namespace kit {
  33.  
  34.  
  35.  
  36.  
  37.  
  38. struct AudioDataHeader;
  39.  
  40. //like Surface, the pointer this returns must have been allocated with
  41.  //memory:alloc specifically (NOT memory::allocSIMD!)
  42. //->samples must not use a separate allocation! samples must be contiguous
  43.  //and on the same memory block as the header itself!
  44.  //(basically, header_ptr->samples = (u8*)header_ptr+header_ptr->headerSize)
  45. typedef AudioDataHeader* (*AudioDataLoaderCallback)(const char* filePath);
  46.  
  47. typedef void (*AudioDataSaverCallback)(const char* filePath, AudioDataHeader& header_in);
  48.  
  49. //(like Surface, when saving OR loading, filePath will never be nullptr by the
  50.  //time the callback is invoked, so you don't need to worry about checking for it)
  51.  
  52.  
  53.  
  54. //(not an actual callback, but rather the lack of one)
  55. #define AudioDataLoadKPM ((AudioDataLoaderCallback)nullptr)
  56. #define AudioDataSaveKPM ((AudioDataSaverCallback)nullptr)
  57.  
  58. AudioDataHeader* AudioDataLoadWAV(const char* filePath);
  59. void             AudioDataSaveWAV(const char* filePath, AudioDataHeader& header_in);
  60.  
  61. AudioDataHeader* AudioDataLoadQOA(const char* filePath);
  62. void             AudioDataSaveQOA(const char* filePath, AudioDataHeader& header_in);
  63.  
  64. AudioDataHeader* AudioDataLoadOGG(const char* filePath);
  65. //(there is no saver callback for ogg currently!)
  66.  
  67.  
  68.  
  69.  
  70.  
  71. #define KIT_MAGIC_KPM (0x4D78506B) // = "kPxM" (no null terminator)
  72.  
  73. struct AudioDataHeader { //72B (0x48B)
  74.   u32        magic; // (0x00) = KIT_MAGIC_KPM = 0x4D78506B = "kPxM"
  75.   u16       format; // (0x04) = one of AudioSampleFormatEnum if fmt_version == 1
  76.   u16   headerSize; // (0x06) = must be >=sizeof(AudioDataHeader)
  77.   u64     dataSize; // (0x08) = size of audio data, in bytes
  78.  
  79.   u64    loopStart; // (0x10) = which sample to loop back to
  80.   u64      loopEnd; // (0x18) = which sample to jump back to loopStart on
  81.  
  82.   u64   numSamples; // (0x20) = # of sample frames in audio data
  83.   u32   sampleRate; // (0x28) = the audio data's sample rate, in Hz
  84.   u32      bitRate; // (0x2C) = the audio's bit rate (per second)
  85.  
  86.   u16    loopCount; // (0x30) = # of times to loop audio (0 = no loop, 0xFFFF = inf loop)
  87.   u16     channels; // (0x32) = # of interlaced channels in the audio data
  88.   u8     _reserved; // (0x34)
  89.   u8   fmt_version; // (0x35) = 0=kit_w32, 1=kit_sdl2
  90.   u8          mode; // (0x36) = 0 for normal PCM or float data types
  91.   u8 metadata_type; // (0x37) = 0 for no metadata
  92.  
  93.   void*    samples; // (0x38) = the audio's sample data (appears as nullptr in file)
  94.   void*   userdata; // (0x40) = user-defined (also appears nullptr in file)
  95.                     // (0x48) = (start of sample data, assuming a .kpm file)
  96.  
  97.   void printHeader(const char* name = nullptr);
  98.  
  99. };
  100.  
  101.  
  102.  
  103.  
  104.  
  105. class AudioData { //24B
  106.   u32          _type;
  107.   bool        _valid = false;
  108.   bool _constructing = true;
  109.   u16     _padding16;
  110.  
  111.  
  112.   //used by both the 'only allocate' constructors
  113.   void _allocate_hdr(u16 headerSize, u64 dataSize,
  114.                      const char* funcName = nullptr);
  115.  
  116.   //used by both of the 'load from file' constructors
  117.   void _construct_file(const char* filePath, AudioDataLoaderCallback callback,
  118.                        const char* funcName = nullptr);
  119.  
  120.  
  121. public:
  122.   //after exiting the constructor, hdr->samples is safe to use with SIMD
  123.    //vector instructions/intriniscs (AudioDataLoaderCallbacks must
  124.    //still use memory::alloc instead of allocSIMD though)!
  125.   AudioDataHeader* hdr;
  126.  
  127.   f32 volumeL = 1.0f;
  128.   f32 volumeR = 1.0f;
  129.  
  130.  
  131.  
  132.   //create with everything zeroed out, except headerSize, dataSize, and samples
  133.   AudioData(u16 headerSize, u64 dataSize)
  134.   { _allocate_hdr(headerSize, dataSize); }
  135.  
  136.   //create with zeroed out sample data
  137.   AudioData(AudioSampleFormatEnum format,
  138.             u64 numSamples, u16 channels, u32 sampleRate);
  139.  
  140.   //create from an audio file of a specific file format
  141.    //(may reduce binary size if you only plan to use 1 file type or something)
  142.   AudioData(const char* filePath, AudioDataLoaderCallback callback)
  143.   { _construct_file(filePath, callback); }
  144.  
  145.   //create from an audio file of any supported format (.kpm, .wav, .qoa, .ogg)
  146.   AudioData(const char* filePath);
  147.  
  148.   ~AudioData();
  149.  
  150.  
  151.  
  152.   inline void printHeader(const char* name = nullptr)
  153.   { if(hdr != nullptr) hdr->printHeader(name); }
  154.  
  155.   //(this will overwrite any file named filePath! make sure to check
  156.    //with fileio::exists() unless you intend to overwrite the previous file)
  157.   void saveAudio(const char* filePath, AudioDataSaverCallback callback);
  158.  
  159.   //the conversion method used is slightly inaccurate for a number of reasons.
  160.    //this function only serves as a convenience, where accuracy isn't
  161.    //needed beyond sounding more or less the same.
  162.   void convertFormat(AudioSampleFormatEnum format);
  163.   //(this will return early if hdr->format == format,
  164.    //since no conversion would be necessary)
  165.  
  166. };
  167.  
  168.  
  169.  
  170.  
  171.  
  172. }; /* namespace kit */
  173.  
  174. #endif /* _INC__AUDIO_AUDIODATA_HPP */
  175. /******************************************************************************/
  176. /******************************************************************************/
  177. //"ksdl2_2024-11-07\_audio_SoundEngine.hpp":
  178. #ifndef _INC__AUDIO_SOUNDENGINE_HPP
  179. #define _INC__AUDIO_SOUNDENGINE_HPP
  180.  
  181. #include "commondef.hpp"
  182. #include "_audio_types.hpp"
  183.  
  184.  
  185. namespace kit {
  186.  
  187.  
  188.  
  189.  
  190.  
  191. class SoundEngine {
  192.   u32          _type;
  193.   bool        _valid = false;
  194.   bool _constructing = true;
  195.   u16     _padding16;
  196.   GenOpqPtr  _tracks = nullptr;
  197.  
  198.  
  199. public:
  200.  
  201.  
  202. };
  203.  
  204.  
  205.  
  206.  
  207.  
  208. }; /* namespace kit */
  209.  
  210. #endif /* _INC__AUDIO_SOUNDENGINE_HPP */
  211. /******************************************************************************/
  212. /******************************************************************************/
  213. //"ksdl2_2024-11-07\kit_AudioData.cpp":
  214. #include "_kit_common.hpp"
  215.  
  216. #define ADATA_IS_INVALID (!_valid && !_constructing)
  217.  
  218.  
  219. namespace kit {
  220.  
  221. //#define DONT_USE_ALLOCSIMD //for debugging
  222.  
  223.  
  224.  
  225.  
  226.  
  227. void AudioDataHeader::printHeader(const char* name){
  228. #ifdef _DEBUG
  229.   //(SDL_Log adds \n automatically, but ignores the last \n if added manually)
  230.   if(name != nullptr) kit_LogInfo("%s = {\n", name);
  231.   else                kit_LogInfo("%p = {\n", this);
  232.  
  233.   kit_LogInfo("  ->magic         = \"%.4s\"; (0x%08X)\n", (char*)&magic, magic);
  234.  
  235.  
  236.   const char* fmt_txt = "?";
  237.   switch(format){
  238.     case SMPFMT_U8    : fmt_txt = "U8";     break;
  239.     case SMPFMT_S8    : fmt_txt = "S8";     break;
  240.  
  241.     case SMPFMT_U16LSB: fmt_txt = "U16LSB"; break;
  242.     case SMPFMT_S16LSB: fmt_txt = "S16LSB"; break;
  243.     case SMPFMT_S24LSB: fmt_txt = "S24LSB"; break;
  244.     case SMPFMT_S32LSB: fmt_txt = "S32LSB"; break;
  245.     case SMPFMT_F32LSB: fmt_txt = "F32LSB"; break;
  246.     case SMPFMT_F64LSB: fmt_txt = "F64LSB"; break;
  247.  
  248.     case SMPFMT_U16MSB: fmt_txt = "U16MSB"; break;
  249.     case SMPFMT_S16MSB: fmt_txt = "S16MSB"; break;
  250.     case SMPFMT_S24MSB: fmt_txt = "S24MSB"; break;
  251.     case SMPFMT_S32MSB: fmt_txt = "S32MSB"; break;
  252.     case SMPFMT_F32MSB: fmt_txt = "F32MSB"; break;
  253.     case SMPFMT_F64MSB: fmt_txt = "F64MSB"; break;
  254.  
  255.     default           : fmt_txt = "UNKNOWN";
  256.   }
  257.  
  258.   kit_LogInfo("  ->format        = SMPFMT_%s; (0x%04X)\n", fmt_txt, format);
  259.  
  260.  
  261.   kit_LogInfo("  ->headerSize    = %u;\n", headerSize);
  262.   kit_LogInfoS("  ->dataSize      = %llu;\n", dataSize);
  263.   kit_LogInfoS("  ->loopStart     = %llu;\n", loopStart);
  264.   kit_LogInfoS("  ->loopEnd       = %llu;\n", loopEnd);
  265.   kit_LogInfoS("  ->numSamples    = %llu;\n", numSamples);
  266.   kit_LogInfo("  ->sampleRate    = %u;\n", sampleRate);
  267.   kit_LogInfo("  ->bitRate       = %u;\n", bitRate);
  268.   kit_LogInfo("  ->loopCount     = %u;\n", loopCount);
  269.   kit_LogInfo("  ->channels      = %u;\n", channels);
  270.   kit_LogInfo("  ->_reserved     = %u;\n", _reserved);
  271.   kit_LogInfo("  ->fmt_version   = %u;\n", fmt_version);
  272.   kit_LogInfo("  ->mode          = %u;\n", mode);
  273.   kit_LogInfo("  ->metadata_type = %u;\n", metadata_type);
  274.   kit_LogInfo("  ->samples       = %p;\n", samples);
  275.   kit_LogInfo("  ->userdata      = %p;\n", userdata);
  276.   kit_LogInfo("};");
  277.  
  278.  
  279. #else
  280.   name = name; //be gone, unused parameter warning
  281.   kit_LogWarn("\"AudioDataHeader::printHeader()\" is only available in the debug build!\n");
  282.  
  283.  
  284. #endif /* _DEBUG */
  285. }
  286.  
  287.  
  288.  
  289.  
  290.  
  291. void AudioData::_allocate_hdr(u16 headerSize, u64 dataSize,
  292.                               const char* funcName)
  293. {
  294.   if(_valid) return;
  295.   _type = KIT_CLASSTYPE_AUDIODATA;
  296.  
  297.   if(funcName == nullptr)
  298.     funcName = "AudioData::AudioData(raw allocation)";
  299.  
  300.   if(headerSize < sizeof(AudioDataHeader))
  301.     THROW_ERRORF("%s: headerSize < sizeof(AudioDataHeader)", funcName);
  302.  
  303.  
  304. #ifndef DONT_USE_ALLOCSIMD
  305.   hdr = (AudioDataHeader*)memory::allocSIMD(headerSize+dataSize);
  306. #else
  307.   hdr = (AudioDataHeader*)memory::alloc(headerSize+dataSize);
  308. #endif /* DONT_USE_ALLOCSIMD */
  309.   if(hdr == nullptr)
  310.     THROW_ERRORF("%s: failed to allocate memory", funcName);
  311.  
  312.   memory::set(hdr, 0, headerSize+dataSize);
  313.  
  314.   hdr->headerSize = headerSize;
  315.   hdr->dataSize   = dataSize;
  316.   hdr->samples    = (u8*)hdr + hdr->headerSize;
  317.  
  318.  
  319.  
  320.   _valid = true;
  321.   _constructing = false;
  322.  
  323. }
  324.  
  325.  
  326.  
  327.  
  328.  
  329. AudioData::AudioData(AudioSampleFormatEnum format,
  330.                      u64 numSamples, u16 channels, u32 sampleRate)
  331. {
  332.   if(_valid) return;
  333.   _type = KIT_CLASSTYPE_AUDIODATA;
  334.  
  335.   const u64 dataSize = KIT_AUDIO_BYTESIZE(format)*numSamples*channels;
  336.  
  337.   _allocate_hdr(sizeof(AudioDataHeader), dataSize,
  338.                 "AudioData::AudioData(formatted allocation)");
  339.  
  340.  
  341.  
  342.   hdr->magic         = KIT_MAGIC_KPM;
  343.   hdr->format        = format;
  344.   hdr->headerSize    = sizeof(AudioDataHeader);
  345.   hdr->dataSize      = dataSize;
  346.  
  347.   hdr->loopStart     = 0;
  348.   hdr->loopEnd       = numSamples;
  349.  
  350.   hdr->numSamples    = numSamples;
  351.   hdr->sampleRate    = sampleRate;
  352.   hdr->bitRate       = KIT_AUDIO_BITSIZE(format)*sampleRate*channels;
  353.  
  354.   hdr->loopCount     = 0;
  355.   hdr->channels      = channels;
  356.   hdr->_reserved     = 0;
  357.   hdr->fmt_version   = 1; //1 indicates the version kit_sdl2 uses
  358.   hdr->mode          = 0; //PCM or float data
  359.   hdr->metadata_type = 0; //no metadata
  360.  
  361.   hdr->samples       = (u8*)hdr + hdr->headerSize;
  362.   hdr->userdata      = nullptr;
  363.  
  364.  
  365.  
  366.   _valid = true;
  367.   _constructing = false;
  368.  
  369. }
  370.  
  371.  
  372.  
  373.  
  374.  
  375. #define KIT_MAGIC_KPCM 0x4D43506B //.kpm's old file signature
  376.  
  377. void AudioData::_construct_file(const char* filePath,
  378.                                 AudioDataLoaderCallback callback,
  379.                                 const char* funcName)
  380. {
  381.   if(_valid) return;
  382.   _type = KIT_CLASSTYPE_AUDIODATA;
  383.  
  384.   if(funcName == nullptr)
  385.     funcName = "AudioData::AudioData(specific file format)";
  386.  
  387.   if(filePath == nullptr)
  388.       THROW_ERRORF("%s: filePath = nullptr", funcName);
  389.  
  390.   if(!fileio::exists(filePath))
  391.     THROW_ERRORF("%s: \"%s\" doesn't exist", funcName, filePath);
  392.  
  393.  
  394.  
  395.   AudioDataHeader* _hdr;
  396.  
  397.   if(callback == nullptr){ //load .kpm file
  398.     size_t fileSize;
  399.     _hdr = (AudioDataHeader*)fileio::readAll(filePath, &fileSize);
  400.     //(assumes that _hdr != nullptr after this point)
  401.  
  402.     //check for the current and old version of .kpm's file signature
  403.      //(but only if the fileSize is enough for a u32)
  404.     if(fileSize >= sizeof(u32)  &&
  405.        (_hdr->magic != KIT_MAGIC_KPM  &&  _hdr->magic != KIT_MAGIC_KPCM))
  406.     {
  407.       memory::free(&_hdr);
  408.       THROW_ERRORF("%s: AudioDataLoadKPM used, but file is not a .kpm", funcName);
  409.     }
  410.  
  411.     if(fileSize < sizeof(AudioDataHeader)){
  412.       memory::free(&_hdr);
  413.       THROW_ERRORF("%s: size of .kpm < sizeof(AudioDataHeader)", funcName);
  414.     }
  415.  
  416. /*
  417.     if(_hdr->magic != KIT_MAGIC_KPM) throw "magic != KIT_MAGIC_KPM";
  418.  
  419.     if(!isFormatValid(_hdr->format)) throw "format is invalid";
  420.  
  421.     if(_hdr->headerSize < sizeof(AudioDataHeader)) throw "headerSize < sizeof(AudioDataHeader)";
  422.  
  423.     if(_hdr->dataSize != (fileSize-_hdr->headerSize)) throw "dataSize is invalid";
  424.  
  425.     //(channels are checked before numSamples to prevent divide-by-zero exceptions)
  426.     if(_hdr->channels!=1 && _hdr->channels!=2) throw "audio is neither mono nor stereo";
  427.  
  428.     //(numSamples is checked before loopStart/loopEnd, as their checks rely upon numSamples)
  429.     if(_hdr->numSamples != (_hdr->dataSize/KIT_ASTREAM_FMT_BYTESIZE(_hdr->format))/_hdr->channels) throw "numSamples is invalid";
  430.  
  431.     if(_hdr->loopStart >= _hdr->numSamples) throw "loopStart >= numSamples";
  432.  
  433.     if(_hdr->loopEnd > _hdr->numSamples) throw "loopEnd > numSamples";
  434.  
  435.     if(_hdr->sampleRate < 1000) throw "sampleRate < 1000";
  436.  
  437.     if(_hdr->bitRate != _hdr->sampleRate*_hdr->channels*KIT_ASTREAM_FMT_BITSIZE(_hdr->format)) throw "bitRate is invalid";
  438.  
  439.     if(_hdr->bitRemainder != 0) throw "bitRemainder != 0";
  440.  
  441.     if(_hdr->mode != 0) throw "only mode 0 kPCM files are currently supported";
  442. */
  443.  
  444.     //the only difference between 0 and 1 is that bitsPerSample is offset by -1
  445.     if(_hdr->fmt_version == 0) ++_hdr->format;
  446.  
  447.     _hdr->magic       = KIT_MAGIC_KPM; //if it was previously kPCM, now it is kPxM
  448.     _hdr->fmt_version = 1;              //
  449.  
  450.  
  451.   } else {
  452.     _hdr = callback(filePath);
  453.     if(_hdr == nullptr)
  454.       THROW_ERRORF("%s: callback returned as nullptr", funcName);
  455.  
  456.  
  457.   }
  458.  
  459.  
  460.  
  461.   size_t totalSize = _hdr->headerSize + _hdr->dataSize;
  462.  
  463. #ifndef DONT_USE_ALLOCSIMD
  464.   hdr = (AudioDataHeader*)memory::allocSIMD(totalSize);
  465. #else
  466.   hdr = (AudioDataHeader*)memory::alloc(totalSize);
  467. #endif /* DONT_USE_ALLOCSIMD */
  468.   if(hdr == nullptr){
  469.     memory::free(&_hdr);
  470.     THROW_ERRORF("%s: failed to allocate memory", funcName);
  471.   }
  472.  
  473.   memory::copy(hdr, _hdr, totalSize);
  474.   memory::free(&_hdr);
  475.  
  476.   hdr->samples = (u8*)hdr + hdr->headerSize;
  477.  
  478.   _valid = true;
  479.   _constructing = false;
  480.  
  481. }
  482.  
  483.  
  484.  
  485.  
  486.  
  487. //(the last constructor can be found in "kit_AudioData_LoadAllTypes.cpp")
  488.  
  489.  
  490.  
  491.  
  492.  
  493. AudioData::~AudioData(){
  494.   if(!_valid) return;
  495.   _valid = false;
  496.  
  497. #ifndef DONT_USE_ALLOCSIMD
  498.   memory::freeSIMD(&hdr);
  499. #else
  500.   memory::free(&hdr);
  501. #endif /* DONT_USE_ALLOCSIMD */
  502.  
  503. }
  504.  
  505.  
  506.  
  507.  
  508.  
  509. void AudioData::saveAudio(const char* filePath,
  510.                           AudioDataSaverCallback callback)
  511. {
  512.   if(ADATA_IS_INVALID)
  513.     THROW_ERROR("AudioData::saveAudio(): invalid AudioData");
  514.  
  515.   if(filePath == nullptr)
  516.     THROW_ERROR("AudioData::saveAudio(): filePath = nullptr");
  517.  
  518.  
  519.  
  520.   if(callback == nullptr){ //save .kpm
  521.     try {
  522.       fileio::writeAll(filePath, hdr, hdr->headerSize+hdr->dataSize);
  523.  
  524.     } catch(const char* errorText){
  525.       freeThreadErrors();
  526.       THROW_ERRORF("AudioData::saveAudio(): \"%s\"", SDL_GetError());
  527.  
  528.     }
  529.  
  530.  
  531.   } else {
  532.     callback(filePath, *hdr);
  533.  
  534.  
  535.   }
  536.  
  537. }
  538.  
  539.  
  540.  
  541.  
  542.  
  543. static bool _fmt_is_valid(u16 fmt){
  544.   switch(fmt){
  545.     case SMPFMT_U8 : SDL_FALLTHROUGH;
  546.     case SMPFMT_S8 : SDL_FALLTHROUGH;
  547.     case SMPFMT_U16: SDL_FALLTHROUGH;
  548.     case SMPFMT_S16: SDL_FALLTHROUGH;
  549.     case SMPFMT_S24: SDL_FALLTHROUGH;
  550.     case SMPFMT_S32: SDL_FALLTHROUGH;
  551.     case SMPFMT_F32: SDL_FALLTHROUGH;
  552.     case SMPFMT_F64: return  true; //lol
  553.     default:         return false;
  554.   }
  555. }
  556.  
  557. // = 2^(bits-1)
  558. #define ABS_S8_MIN         (128) //ABS_Sx_MIN is a horrible name for this,
  559. #define ABS_S16_MIN      (32768)  //but it's the name i chose within 10 seconds
  560. #define ABS_S24_MIN    (8388608)  //(so i may or may not change it, idk)
  561. #define ABS_S32_MIN (2147483648)
  562.  
  563. struct _s24 { u8 a, b, c; } //mostly for memory alignment purposes
  564. __attribute__((packed)); //(explicitly pack just in case; probably unnecessary)
  565.  
  566. union _s24u {
  567.   _s24 v;
  568.    s32 n : 24;
  569.   inline _s24u(_s24 _v) : v(_v) {}
  570.   inline _s24u(s32  _n) : n(_n&KIT_S24_MAX) {}
  571. };
  572.  
  573. static inline f64 frm_s24(_s24 x){ return (f64)_s24u(x).n/ABS_S24_MIN; }
  574.  
  575. static inline _s24 to_s24(f64 x){ return _s24u((s32)(x*KIT_S24_MAX)).v; }
  576.  
  577.  
  578.  
  579. void AudioData::convertFormat(AudioSampleFormatEnum format){
  580.   if(ADATA_IS_INVALID)
  581.     THROW_ERROR("AudioData::convertFormat(): invalid AudioData");
  582.  
  583.   if(hdr->format == format) return; //no need to convert anything; exit early
  584.  
  585.   if(!_fmt_is_valid(hdr->format))
  586.     THROW_ERROR("AudioData::convertFormat(): unrecognized source format");
  587.  
  588.   if(!_fmt_is_valid(format))
  589.     THROW_ERROR("AudioData::convertFormat(): unrecognized destination format");
  590.  
  591.  
  592.  
  593.   u64 totalSamples = hdr->numSamples*hdr->channels;
  594.  
  595.   u64    dataSize = KIT_AUDIO_BYTESIZE(format)*totalSamples;
  596.   u32     bitRate = KIT_AUDIO_BITSIZE(format)*hdr->sampleRate*hdr->channels;
  597.  
  598.  
  599.  
  600.   try {
  601.     memory::Wrapper temp_samples(totalSamples*sizeof(f64));
  602.     f64*  tmp = (f64*)temp_samples.ptr;
  603.     void* smp = hdr->samples;
  604.  
  605.     #define FOR_TS_BRK(x) for(u64 i=0; i<totalSamples; ++i){ x; } break
  606.     #define SMPCAST(_type) (  ((_type*)smp)[i]  )
  607.     #define FRM_CONV(_type, _scaling_factor, _modifier) \
  608.       (  ((f64)SMPCAST(_type) _modifier) _scaling_factor  )
  609.  
  610.     //convert all source samples to 64-bit floats
  611.     switch(hdr->format){
  612.       case SMPFMT_U8 : FOR_TS_BRK(  tmp[i] = FRM_CONV(u8 , /ABS_S8_MIN ,   -128)  );
  613.       case SMPFMT_S8 : FOR_TS_BRK(  tmp[i] = FRM_CONV(s8 , /ABS_S8_MIN ,       )  );
  614.       case SMPFMT_U16: FOR_TS_BRK(  tmp[i] = FRM_CONV(u16, /ABS_S16_MIN, -32768)  );
  615.       case SMPFMT_S16: FOR_TS_BRK(  tmp[i] = FRM_CONV(s16, /ABS_S16_MIN,       )  );
  616.       case SMPFMT_S24: FOR_TS_BRK(  tmp[i] = frm_s24(SMPCAST(_s24))               );
  617.       case SMPFMT_S32: FOR_TS_BRK(  tmp[i] = FRM_CONV(s32, /ABS_S32_MIN,       )  );
  618.       case SMPFMT_F32: FOR_TS_BRK(  tmp[i] = FRM_CONV(f32,             ,       )  );
  619.       case SMPFMT_F64: memory::copy(tmp, smp, hdr->dataSize); break;
  620.     }
  621.  
  622.  
  623.  
  624.     //resize header to match destination format's dataSize
  625. #ifndef DONT_USE_ALLOCSIMD
  626.     if(!memory::reallocSIMD(&hdr, hdr->headerSize+dataSize))
  627. #else
  628.     if(!memory::realloc(&hdr, hdr->headerSize+dataSize))
  629. #endif /* DONT_USE_ALLOCSIMD */
  630.       throw "?"; //what is thrown doesn't matter as long as it's const char*
  631.  
  632.     //update relevant header values
  633.     hdr->format       = format;
  634.     hdr->dataSize     = dataSize;
  635.     hdr->bitRate      = bitRate;
  636.     hdr->samples      = (u8*)hdr + hdr->headerSize;
  637.  
  638.     smp = hdr->samples;
  639.  
  640.  
  641.  
  642.     #define TO_CONV(_type, _scl_fct, _mod) (  (_type)( tmp[i] _scl_fct _mod )  )
  643.  
  644.     //convert the f64 samples to the desired format
  645.     switch(hdr->format){ //(hdr->format = format now)
  646.       case SMPFMT_U8 : FOR_TS_BRK(  SMPCAST( u8 ) = TO_CONV(u8 , *KIT_S8_MAX ,   +128)  );
  647.       case SMPFMT_S8 : FOR_TS_BRK(  SMPCAST( s8 ) = TO_CONV(s8 , *KIT_S8_MAX ,       )  );
  648.       case SMPFMT_U16: FOR_TS_BRK(  SMPCAST( u16) = TO_CONV(u16, *KIT_S16_MAX, +32768)  );
  649.       case SMPFMT_S16: FOR_TS_BRK(  SMPCAST( s16) = TO_CONV(s16, *KIT_S16_MAX,       )  );
  650.       case SMPFMT_S24: FOR_TS_BRK(  SMPCAST(_s24) = to_s24(tmp[i])                      );
  651.       case SMPFMT_S32: FOR_TS_BRK(  SMPCAST( s32) = TO_CONV(s32, *KIT_S32_MAX,       )  );
  652.       case SMPFMT_F32: FOR_TS_BRK(  SMPCAST( f32) = TO_CONV(f32,             ,       )  );
  653.       case SMPFMT_F64: memory::copy(smp, tmp, hdr->dataSize); break;
  654.     }
  655.  
  656.  
  657.  
  658.   } catch(const char* errorText){
  659.     //the only 2 errors that should occur in that try block are failures
  660.      //to allocate heap memory, so i'm just changing the function
  661.      //name to indicate it occurred in this constructor specifically
  662.     freeThreadErrors();
  663.     THROW_ERROR("AudioData::convertFormat(): failed to allocate memory");
  664.  
  665.  
  666.  
  667.   }
  668.  
  669. }
  670.  
  671.  
  672.  
  673.  
  674.  
  675. }; /* namespace kit */
  676. /******************************************************************************/
  677. /******************************************************************************/
  678. //"ksdl2_2024-11-07\kit_AudioData_LoadAllTypes.cpp":
  679. #include "_kit_common.hpp"
  680.  
  681.  
  682. namespace kit {
  683.  
  684.  
  685.  
  686.  
  687.  
  688. //file signatures
  689. //(KIT_MAGIC_KPM already defined in "_audio_AudioData.hpp")
  690. #define MAGIC_WAV 0x46464952 // = "RIFF"
  691. #define MAGIC_QOA 0x66616F71 // = "qoaf"
  692. #define MAGIC_OGG 0x5367674F // = "OggS"
  693.  
  694. //"RIFF" is not a .wav's actual file signature, rather it denotes the type
  695.  //of format used (like a format of formats of sorts), but i'm not going
  696.  //to add extra logic here to also read 4 bytes at offset 8 just to check for
  697.  //"WAVE" (which is its actual signature), because my wav parser already handles
  698.  //everything related to header validation anyway.
  699.  
  700.  
  701.  
  702.  
  703.  
  704. #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
  705.  
  706. AudioData::AudioData(const char* filePath){
  707.   const char* errTxt = "?";
  708.   if(0) _err: THROW_ERRORF("AudioData::AudioData(any file format): %s", errTxt);
  709.  
  710.  
  711.   if(filePath == nullptr)
  712.     GOTO_SET_ERROR("filePath = nullptr");
  713.  
  714.   if(!fileio::exists(filePath))
  715.     GOTO_SET_ERROR("file doesn't exist");
  716.  
  717.  
  718.  
  719.   u32 magic; //file signature, up to a maximum of 4 bytes
  720.  
  721.   if(  File(filePath,"rb").read(&magic, sizeof(magic))  <  sizeof(magic)  )
  722.   {
  723.     GOTO_SET_ERROR("failed to read first 4 bytes of file");
  724.   }
  725.  
  726.  
  727.  
  728.   AudioDataLoaderCallback callback;
  729.  
  730.   if(     magic == KIT_MAGIC_KPM) callback = nullptr;
  731.   else if(magic ==     MAGIC_WAV) callback = AudioDataLoadWAV;
  732.   else if(magic ==     MAGIC_QOA) callback = AudioDataLoadQOA;
  733.   else if(magic ==     MAGIC_OGG) callback = AudioDataLoadOGG;
  734.   else GOTO_SET_ERROR("unsupported file format");
  735.  
  736.  
  737.   _construct_file(filePath, callback, "AudioData::AudioData(any file format)");
  738.  
  739. }
  740.  
  741.  
  742.  
  743.  
  744.  
  745. }; /* namespace kit */
  746. /******************************************************************************/
  747. /******************************************************************************/
  748. //"ksdl2_2024-11-07\kit_AudioData_LoadOGG.cpp":
  749. #include "_kit_common.hpp"
  750.  
  751. #include "../stb_vorbis/stb_vorbis.hpp"
  752.  
  753. namespace kit {
  754.  
  755.  
  756.  
  757.  
  758.  
  759. #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
  760.  
  761. AudioDataHeader* AudioDataLoadOGG(const char* filePath){
  762.   const char* errTxt = "?";
  763.   if(0) _err: THROW_ERRORF("AudioDataLoadOGG(): %s", errTxt);
  764.  
  765.   if(!fileio::exists(filePath))
  766.     GOTO_SET_ERROR("file doesn't exist");
  767.  
  768.   BinaryData fileData(filePath);
  769.  
  770.   size_t fileSize = fileData.getSize();
  771.  
  772.   if(fileSize > KIT_S32_MAX)
  773.     GOTO_SET_ERROR("fileSize > KIT_S32_MAX");
  774.  
  775.  
  776.  
  777.   stb_vorbis* vrb = stb_vorbis_open_memory((u8*)fileData.getData(), fileSize,
  778.                                            nullptr, nullptr);
  779.  
  780.   if(vrb == nullptr)
  781.     GOTO_SET_ERROR("failed to open Ogg Vorbis stream from memory");
  782.  
  783.   stb_vorbis_info vrb_info = stb_vorbis_get_info(vrb);
  784.  
  785.   u32 numSamples = stb_vorbis_stream_length_in_samples(vrb);
  786.   u32 sampleRate = vrb_info.sample_rate;
  787.   s32 channels   = vrb_info.channels;
  788.  
  789.   if(channels > KIT_U16_MAX)
  790.     GOTO_SET_ERROR("channels > KIT_U16_MAX");
  791.  
  792.  
  793.  
  794.   AudioDataHeader hdr;
  795.  
  796.   hdr.magic         = KIT_MAGIC_KPM;
  797.   hdr.format        = SMPFMT_F32;
  798.   hdr.headerSize    = sizeof(AudioDataHeader);
  799.   hdr.dataSize      = sizeof(f32)*channels*numSamples;
  800.  
  801.   hdr.loopStart     = 0;
  802.   hdr.loopEnd       = numSamples;
  803.  
  804.   hdr.numSamples    = numSamples;
  805.   hdr.sampleRate    = sampleRate;
  806.   hdr.bitRate       = KIT_AUDIO_BITSIZE(SMPFMT_F32)*channels*sampleRate;
  807.  
  808.   hdr.loopCount     = 0;
  809.   hdr.channels      = channels;
  810.   hdr._reserved     = 0;
  811.   hdr.fmt_version   = 1;
  812.   hdr.mode          = 0;
  813.   hdr.metadata_type = 0;
  814.  
  815.   hdr.samples       = nullptr;
  816.   hdr.userdata      = nullptr;
  817.  
  818.  
  819.  
  820.   AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
  821.   if(_hdr == nullptr) GOTO_SET_ERROR("failed to allocate memory");
  822.  
  823.   *_hdr = hdr;
  824.   _hdr->samples = (u8*)_hdr + _hdr->headerSize;
  825.  
  826.   int amountDecoded = stb_vorbis_get_samples_float_interleaved(vrb, channels,
  827.                                                                (f32*)_hdr->samples,
  828.                                                                numSamples*channels);
  829.  
  830.   if((u32)amountDecoded < numSamples){
  831.     memory::free(&_hdr);
  832.     stb_vorbis_close(vrb);
  833.     GOTO_SET_ERROR("amountDecoded < numSamples");
  834.   }
  835.  
  836.  
  837.  
  838.   //tbd: add loop points to ogg loader
  839.   //stb_vorbis_comment comments = stb_vorbis_get_comment(vrb);
  840.   //error if loopStart >= numSamples, error if loopEnd > numSamples
  841.  
  842.  
  843.  
  844.   stb_vorbis_close(vrb);
  845.  
  846.   return _hdr;
  847.  
  848. }
  849.  
  850.  
  851.  
  852.  
  853.  
  854. }; /* namespace kit */
  855. /******************************************************************************/
  856. /******************************************************************************/
  857. //"ksdl2_2024-11-07\kit_AudioData_LoadSaveQOA.cpp":
  858. #include "_kit_common.hpp"
  859.  
  860. #define QOA_NO_STDIO
  861. #define QOA_MALLOC(sz) kit::memory::alloc(sz)
  862. #define QOA_FREE(p)    kit::memory::free(&p)
  863.  
  864.  
  865. namespace kit {
  866.  
  867.  
  868. namespace qoa {
  869.  
  870. #define QOA_IMPLEMENTATION
  871. //idk why this is defined, but it's in qoaconv.c so i'll keep it in to be safe
  872. #define QOA_RECORD_TOTAL_ERROR
  873. #include "../qoa/qoa.h"
  874.  
  875. }; /* namespace qoa */
  876.  
  877. //hopefully putting it in its own namespace will prevent any user naming conflicts
  878.  //(maybe it wouldn't have been a problem anyway, idk)
  879. using namespace qoa;
  880.  
  881.  
  882.  
  883.  
  884.  
  885. /*
  886.  
  887. struct {
  888.   u32 channels;
  889.   u32 samplerate;
  890.   u32 samples;
  891.   qoa_lms_t lms[QOA_MAX_CHANNELS];
  892.   #ifdef QOA_RECORD_TOTAL_ERROR
  893.     f64 error;
  894.   #endif
  895. } qoa_desc;
  896.  
  897. s16* qoa_decode(const u8* bytes, s32 size, qoa_desc* file);
  898.  
  899. void* qoa_encode(const s16* sample_data, qoa_desc* qoa, u32* out_len);
  900.  
  901. */
  902.  
  903.  
  904.  
  905.  
  906.  
  907. #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
  908.  
  909.  
  910.  
  911.  
  912.  
  913. #define MAGIC_QOA 0x66616F71 // = "qoaf"
  914.  
  915. AudioDataHeader* AudioDataLoadQOA(const char* filePath){
  916.   const char* errTxt = "?";
  917.   if(0) _err: THROW_ERRORF("AudioDataLoadQOA(): %s", errTxt);
  918.  
  919.   if(!fileio::exists(filePath))
  920.     GOTO_SET_ERROR("file doesn't exist");
  921.  
  922.   BinaryData _fileData(filePath);
  923.  
  924.  
  925.  
  926.   s32   fileSize = ( s32 )_fileData.getSize();
  927.   void* fileData = (void*)_fileData.getData(); //the ACTUAL file data
  928.  
  929.   if(_fileData.getSize() > KIT_S32_MAX)
  930.     GOTO_SET_ERROR("file is too large for a QOA (>2GiB)");
  931.  
  932.   //if(fileSize < ??)
  933.   //  GOTO_SET_ERROR("file is too small for a QOA (<??B)");
  934.  
  935.   if((*(u32*)fileData) != MAGIC_QOA)
  936.     GOTO_SET_ERROR("file is not a QOA audio file");
  937.  
  938.  
  939.  
  940.   qoa_desc smp_info;
  941.   memory::Wrapper _smp(qoa_decode((u8*)fileData, fileSize, &smp_info));
  942.   s16* smp = (s16*)_smp.ptr;
  943.  
  944.   if(smp == nullptr) GOTO_SET_ERROR("failed to decode QOA file data");
  945.  
  946.   if(smp_info.channels > KIT_U16_MAX)
  947.     GOTO_SET_ERROR("channels > KIT_U16_MAX");
  948.  
  949.   AudioDataHeader hdr;
  950.  
  951.   hdr.magic         = KIT_MAGIC_KPM;
  952.   hdr.format        = SMPFMT_S16;
  953.   hdr.headerSize    = sizeof(AudioDataHeader);
  954.   hdr.dataSize      = sizeof(s16)*smp_info.samples*smp_info.channels;
  955.  
  956.   hdr.loopStart     = 0;
  957.   hdr.loopEnd       = smp_info.samples;
  958.  
  959.   hdr.numSamples    = smp_info.samples;
  960.   hdr.sampleRate    = smp_info.samplerate;
  961.   hdr.bitRate       = KIT_AUDIO_BITSIZE(hdr.format)*smp_info.channels*smp_info.samplerate;
  962.  
  963.   hdr.loopCount     = 0;
  964.   hdr.channels      = smp_info.channels;
  965.   hdr._reserved     = 0;
  966.   hdr.fmt_version   = 1;
  967.   hdr.mode          = 0;
  968.   hdr.metadata_type = 0;
  969.  
  970.   hdr.samples       = nullptr;
  971.   hdr.userdata      = nullptr;
  972.  
  973.  
  974.  
  975.   AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
  976.   if(_hdr == nullptr) GOTO_SET_ERROR("failed to allocate memory");
  977.  
  978.   *_hdr = hdr;
  979.   _hdr->samples = (u8*)_hdr + _hdr->headerSize;
  980.   memory::copy(_hdr->samples, smp, _hdr->dataSize);
  981.  
  982.   return _hdr;
  983.  
  984. }
  985.  
  986.  
  987.  
  988.  
  989.  
  990. void AudioDataSaveQOA(const char* filePath,
  991.                       AudioDataHeader& header_in)
  992. {
  993.   const char* errTxt = "?";
  994.   if(0) _err: THROW_ERRORF("AudioDataSaveQOA(): %s", errTxt);
  995.  
  996.   if(header_in.format != SMPFMT_S16)
  997.     GOTO_SET_ERROR("format != SMPFMT_S16");
  998.  
  999.   if(header_in.numSamples > KIT_U32_MAX)
  1000.     GOTO_SET_ERROR("numSamples > KIT_U32_MAX");
  1001.  
  1002.  
  1003.  
  1004.   qoa_desc smp_info;
  1005.  
  1006.   smp_info.channels   = header_in.channels;
  1007.   smp_info.samplerate = header_in.sampleRate;
  1008.   smp_info.samples    = header_in.numSamples;
  1009.  
  1010.   u32 fileSize;
  1011.   memory::Wrapper fileData(qoa_encode((s16*)header_in.samples,
  1012.                                        &smp_info, &fileSize));
  1013.  
  1014.   if(fileData.ptr == nullptr) GOTO_SET_ERROR("failed to encode QOA data");
  1015.  
  1016.  
  1017.  
  1018.   try {
  1019.     File file(filePath, "wb");
  1020.     file.write(fileData.ptr, fileSize);
  1021.  
  1022.   } catch(const char* errorText){
  1023.     freeThreadErrors();
  1024.     GOTO_SET_ERROR("failed to write to file");
  1025.  
  1026.   }
  1027.  
  1028. }
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034. }; /* namespace kit */
  1035. /******************************************************************************/
  1036. /******************************************************************************/
  1037. //"ksdl2_2024-11-07\kit_AudioData_LoadSaveWAV.cpp":
  1038. #include "_kit_common.hpp"
  1039.  
  1040. namespace kit {
  1041.  
  1042. #define KIT_LOAD_WAV_MALLOC(_ptr) kit::memory::alloc(_ptr)
  1043. #define KIT_LOAD_WAV_FREE(_ptr)   kit::memory::free(&_ptr)
  1044.  
  1045. #define KIT_LOAD_WAV_MEMSET(_ptr_or_arr, _value, _size) \
  1046.   kit::memory::set((_ptr_or_arr), (_value), (_size))
  1047.  
  1048. #define KIT_LOAD_WAV_MEMCPY(_dst_ptr, _src_ptr, _size) \
  1049.   kit::memory::copy((_dst_ptr), (_src_ptr), (_size))
  1050.  
  1051. #define KIT_LOAD_WAV_IMPLEMENTATION
  1052. #define KIT_LOAD_WAV_CUSTOM_READ
  1053.  
  1054. #include "kit_load_wav.h"
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060. void* kit_read_wav(const char* filePath, int32_t* fileSize_out){
  1061.   if(!filePath) return NULL;
  1062.  
  1063.   size_t fileSize;
  1064.   void* fileData = SDL_LoadFile(filePath, &fileSize);
  1065.   if(!fileData) return NULL;
  1066.  
  1067.   if(fileSize > KIT_S32_MAX){
  1068.     SDL_free(fileData);
  1069.     return NULL;
  1070.  
  1071.   }
  1072.  
  1073.   //SDL_LoadFile calls SDL_malloc internally; increment # of allocations
  1074.   ++numAllocations;
  1075.  
  1076.   if(fileSize_out) *fileSize_out = (int32_t)fileSize;
  1077.  
  1078.   return fileData;
  1079.  
  1080. }
  1081.  
  1082.  
  1083.  
  1084.  
  1085.  
  1086. #define GOTO_SET_ERROR(_text) { errTxt = _text; goto _err; }
  1087.  
  1088. //(channels may be inaccurate if they use a different layout than SDL's channel mappings!)
  1089. AudioDataHeader* AudioDataLoadWAV(const char* filePath){
  1090.   const char* errTxt = "?";
  1091.   if(0) _err: THROW_ERRORF("AudioDataLoadWAV(): %s", errTxt);
  1092.  
  1093.   if(!fileio::exists(filePath))
  1094.     GOTO_SET_ERROR("file doesn't exist");
  1095.  
  1096.   int32_t _wavErr;
  1097.   memory::Wrapper _wavData(kit_load_wav(filePath, &_wavErr));
  1098.   kit_WavData* wavData = (kit_WavData*)_wavData.ptr;
  1099.  
  1100.   if(_wavErr != WAVEERROR_SUCCESS){
  1101.     switch(_wavErr){
  1102.       case WAVEERROR_NULLPTR   : errTxt = "non-optional argument pointer was nullptr";         break;
  1103.       case WAVEERROR_FILE_READ : errTxt = "failed to read file";                               break;
  1104.       case WAVEERROR_FILE_SIZE : errTxt = "fileSize was < 44 (minimum needed for header)";     break;
  1105.       case WAVEERROR_NOT_RIFF  : errTxt = "first 4 bytes of file != \"RIFF\"";                 break;
  1106.       case WAVEERROR_MALFORMED : errTxt = "wav has malformed data";                            break;
  1107.       case WAVEERROR_NOT_WAVE  : errTxt = "4 bytes from offset 8 != \"WAVE\"";                 break;
  1108.       case WAVEERROR_MALLOC    : _alloc_err: errTxt = "failed to allocate memory";             break;
  1109.       case WAVEERROR_NO_FMT    : errTxt = "wav doesn't contain a f[or]m[a]t subchunk";         break;
  1110.       case WAVEERROR_NO_DATA   : errTxt = "wav doesn't contain a data subchunk";               break;
  1111.       case WAVEERROR_FORMAT    : _fmt_tag_err: errTxt = "wav uses an unsupported format tag";  break;
  1112.       case WAVEERROR_CHANNELS  : errTxt = "channels = 0";                                      break;
  1113.       case WAVEERROR_SAMPLERATE: errTxt = "sampleRate = 0";                                    break;
  1114.       case WAVEERROR_BYTERATE  : errTxt = "byteRate !=  blockAlign*sampleRate";                break;
  1115.       case WAVEERROR_BLOCKALIGN: errTxt = "blockAlign != (.channels*.bitsPerSample)/8";        break;
  1116.       case WAVEERROR_BITSPERSMP: errTxt = "bitsPerSample%8 != 0  OR  = 0  OR  > 64";           break;
  1117.       case WAVEERROR_EXTSIZE   : errTxt = "extensionSize < 22 (format tag is EXTENSIBLE)";     break;
  1118.       case WAVEERROR_VALIDBITS : errTxt = "validBits > bitsPerSample  OR  validBits = 0";      break;
  1119.       default                  : _unknown_err: errTxt = "unknown error";                       break;
  1120.     }
  1121.  
  1122.     goto _err;
  1123.  
  1124.   }
  1125.  
  1126.   if(wavData == nullptr) goto _unknown_err; //this one should be impossible, but just in case
  1127.   if(!wavData->samples_type) goto _unknown_err;
  1128.  
  1129.  
  1130.  
  1131.   //convert kit_WavData_type to that of AudioSampleFormatEnum (AKA SDL_AudioFormat)
  1132.   kit_WavData_type wavType;
  1133.   wavType.value = wavData->samples_type;
  1134.  
  1135.   if(wavType.totalBits != wavType.validBits)
  1136.     GOTO_SET_ERROR("bitsPerSample != validBits");
  1137.  
  1138.   if(wavType.format != WAVEDATA_FORMAT_PCM  &&  wavType.format != WAVEDATA_FORMAT_FLOAT)
  1139.     goto _fmt_tag_err; //(WAVEDATA_FORMAT_<ALAW/ULAW> aren't allowed currently)
  1140.  
  1141.   u16 format = (wavType.value&0x803F) + 1;
  1142.   if(wavType.format == WAVEDATA_FORMAT_FLOAT) format |= 0x8100;
  1143.  
  1144.  
  1145.  
  1146.   AudioDataHeader hdr;
  1147.   hdr.magic         = KIT_MAGIC_KPM;
  1148.   hdr.format        = format;
  1149.   hdr.headerSize    = sizeof(AudioDataHeader);
  1150.   hdr.dataSize      = wavData->samples_size;
  1151.  
  1152.   hdr.loopStart     = 0;
  1153.   hdr.loopEnd       = wavData->samples_len;
  1154.  
  1155.   hdr.numSamples    = wavData->samples_len;
  1156.   hdr.sampleRate    = wavData->sampleRate;
  1157.   hdr.bitRate       = KIT_AUDIO_BITSIZE(format)*wavData->sampleRate*wavData->channels;
  1158.  
  1159.   hdr.loopCount     = 0;
  1160.   hdr.channels      = wavData->channels;
  1161.   hdr._reserved     = 0;
  1162.   hdr.fmt_version   = 1; //1 indicates the version kit_sdl2 uses
  1163.   hdr.mode          = 0; //PCM or float data
  1164.   hdr.metadata_type = 0; //no metadata
  1165.  
  1166.   hdr.samples       = nullptr;
  1167.   hdr.userdata      = nullptr;
  1168.  
  1169.  
  1170.  
  1171.   AudioDataHeader* _hdr = (AudioDataHeader*)memory::alloc(hdr.headerSize + hdr.dataSize);
  1172.   if(_hdr == nullptr) goto _alloc_err;
  1173.  
  1174.   *_hdr = hdr;
  1175.   _hdr->samples = (u8*)_hdr + _hdr->headerSize;
  1176.   memory::copy(_hdr->samples, wavData->samples, _hdr->dataSize);
  1177.  
  1178.   return _hdr;
  1179.  
  1180. }
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186. struct _WavHeader { //the whole thing (for convenience)
  1187.   u32 file_id;           // = 0x46464952 = "RIFF"
  1188.   u32 file_size;         // = file's total size - 8
  1189.   u32 file_id2;          // = 0x45564157 = "WAVE"
  1190.  
  1191.   u32 fmt_id;            // = 0x20746D66 = "fmt "
  1192.   u32 fmt_size;          // = 16
  1193.   u16 fmt_format;        // = 3 if float, 1 if PCM
  1194.   u16 fmt_channels;      // = # of interleaved channels; L&R for stereo (2)
  1195.   u32 fmt_sampleRate;    // = # of sample frames per second
  1196.   u32 fmt_byteRate;      // = blockAlign*sampleRate
  1197.   u16 fmt_blockAlign;    // = size of sample frame (channels*bitsPerSample)/8
  1198.   u16 fmt_bitsPerSample; // (Assumed to be unsigned if 8 and .format is PCM)
  1199.  
  1200.   u32 data_id;           // = 0x61746164 = "data"
  1201.   u32 data_size;         // = size of sample data, in bytes
  1202.  
  1203.   //(sample data starts here)
  1204.  
  1205. };
  1206.  
  1207.  
  1208.  
  1209. #define SV_ASSERT(_success, _error_text) \
  1210.   if(!(_success)){ errTxt = _error_text; goto _err; }
  1211.  
  1212.  
  1213.  
  1214. void AudioDataSaveWAV(const char* filePath,
  1215.                       AudioDataHeader& header_in)
  1216. {
  1217.   const char* errTxt = "?";
  1218.   if(0) _err: THROW_ERRORF("AudioDataSaveWAV(): %s", errTxt);
  1219.  
  1220.   //stack copy, so i can't accidentally change values of the original header
  1221.   AudioDataHeader hdri = header_in;
  1222.  
  1223.   SV_ASSERT(hdri.fmt_version == 1, "fmt_version != 1");
  1224.   SV_ASSERT(!( KIT_AUDIO_ISSIGNED(hdri.format) && KIT_BITSPERPIXEL(hdri.format)<=8 ),
  1225.             "samples 8-bits and below must be unsigned");
  1226.  
  1227.  
  1228.  
  1229.   //round bits UP to the nearest byte (as in a multiple of 8 bits)
  1230.   #define BYTE_CEIL(_num) (((_num)+7)&(~7))
  1231.  
  1232.   _WavHeader hdro;
  1233.  
  1234.   hdro.file_id           = wid_RIFF;
  1235.   hdro.file_size         = sizeof(_WavHeader) + hdri.dataSize - 8;
  1236.   hdro.file_id2          = wid_WAVE;
  1237.  
  1238.   hdro.fmt_id            = wid_fmt_;
  1239.   hdro.fmt_size          = 16;
  1240.   hdro.fmt_format        = KIT_AUDIO_ISFLOAT(hdri.format) ? 3 : 1;
  1241.   hdro.fmt_channels      = hdri.channels;
  1242.   hdro.fmt_sampleRate    = hdri.sampleRate;
  1243.   hdro.fmt_byteRate      = BYTE_CEIL(hdri.bitRate)/8;
  1244.   hdro.fmt_blockAlign    = BYTE_CEIL(hdri.channels*KIT_AUDIO_BITSIZE(hdri.format))/8;
  1245.   hdro.fmt_bitsPerSample = KIT_AUDIO_BITSIZE(hdri.format);
  1246.  
  1247.   hdro.data_id           = wid_data;
  1248.   hdro.data_size         = hdri.dataSize;
  1249.  
  1250.  
  1251.  
  1252.   try {
  1253.     File file(filePath, "wb");
  1254.  
  1255.     file.write(&hdro, sizeof(hdro));
  1256.     file.write(hdri.samples, hdri.dataSize);
  1257.  
  1258.   } catch(const char* errorText){
  1259.     freeThreadErrors();
  1260.     GOTO_SET_ERROR("failed to write to file");
  1261.  
  1262.   }
  1263.  
  1264. }
  1265.  
  1266.  
  1267.  
  1268.  
  1269.  
  1270. }; /* namespace kit */
  1271.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement