Advertisement
Kitomas

ksdl2 work for 2024-08-02 (1/5)

Aug 2nd, 2024 (edited)
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 25.37 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"ksdl2\src\main.cpp":
  4. #include <kit/all.hpp>
  5.  
  6. using namespace kit;
  7.  
  8. #define SDL_MAIN_HANDLED
  9. #include <SDL2/SDL.h>
  10. #include "../lodepng/lodepng.h"
  11. #include "./kit_sdl2/_kit_common.hpp"
  12.  
  13.  
  14. Mutex mutex;
  15.  
  16. s32 threadfunc(void* userdata){
  17.   userdata = userdata;
  18.  
  19.   for(int i=0; i<30; ++i){
  20.     mutex.lock();
  21.     SDL_Log("  before thread wait %i",i);
  22.     //SDL_Delay(200);
  23.     SDL_Delay(100);
  24.     SDL_Log("  after thread wait %i",i);
  25.     mutex.unlock();
  26.     SDL_Delay((rand()>16384) ? 4 : 1);
  27.  
  28.   }
  29.  
  30.   SDL_Log("exiting thread...");
  31.   return 0;
  32.  
  33. }
  34.  
  35.  
  36. #define _PI 3.1415926535897932384626433
  37. #define _2PI (_PI+_PI)
  38.  
  39. bool audiocallback(void* _stream, const AudioDeviceInfo* info){
  40.  
  41.   static u64 smp = 0;
  42.  
  43.   f32* stream     = (f32*)_stream;
  44.   u32  stream_len = info->sampleFrames;
  45.   u32  sampleRate = info->sampleRate;
  46.  
  47.   for(u32 i=0; i<stream_len; ++i, ++smp){
  48.     f64 value = ((f64)smp/sampleRate) * _2PI * 440;
  49.     stream[i] = (f32)SDL_sin(value)*0.1f;
  50.   }
  51.  
  52.   return smp < sampleRate*2;
  53.  
  54. }
  55.  
  56.  
  57.  
  58. int main(/*int argc, char** argv*/){ try { {
  59.   initSubsystems(KINIT_EVENTS|KINIT_AUDIO);
  60.   srand(SDL_GetTicks());
  61.  
  62. /*
  63.   Window win(nullptr, 640, 480, WINFLAG_RESIZABLE);
  64.  
  65.   win.setMouseGrab(true);
  66.  
  67.   bool fullscreen = false;
  68.  
  69.   bool run = true;
  70.   while(run){
  71.  
  72.     Event evt;
  73.     while(run && pollEvent(&evt))
  74.     switch(evt.type){
  75.       case KEVENT_QUIT: run = false; break;
  76.       case KEVENT_KEY_DOWN: {
  77.         switch(evt.key.vkey){
  78.           case VKEY_F11: win.setFullscreen(1*(fullscreen^=1)); break;
  79.           default:;
  80.         }
  81.       } break;
  82.       default:;
  83.     }
  84.  
  85.   }
  86. */
  87.  
  88.  
  89.   {
  90.     AudioDeviceInfo info;
  91.     info.sampleRate   = 8000;
  92.     info.sampleFrames = 512;
  93.     info.sampleFormat = SMPFMT_F32;
  94.     info.numChannels  = 1;
  95.     info.zeroBuffer   = true;
  96.     info.callback     = audiocallback;
  97.  
  98.     AudioDevice adev(-1, &info, false);
  99.  
  100.     SDL_Log("waiting to start...");
  101.     u32 timeStart = time::getMS_32();
  102.     adev.playAndWait();
  103.     SDL_Log("time taken to start: %u", time::getMS_32()-timeStart);
  104.  
  105.     timeStart = time::getMS_32();
  106.     while(adev.isPlaying()) time::sleep(50);
  107.     SDL_Log("time taken rendering audio: %u", time::getMS_32()-timeStart);
  108.  
  109.     timeStart = time::getMS_32();
  110.     adev.pauseAndWait();
  111.     SDL_Log("time taken to fade out: %u", time::getMS_32()-timeStart);
  112.  
  113.   }
  114.  
  115.  
  116. }
  117.   quitSubsystems(KINIT_EVERYTHING);
  118.   return 0;
  119.  
  120. } catch(const char* errorText){
  121. #ifdef _DEBUG
  122.   SDL_Log("FATAL EXCEPTION OCCURRED: \"%s\"\n", errorText);
  123. #else
  124.   showMsgBox(fstr("Error: %-14s", errorText),
  125.              "FATAL EXCEPTION OCCURRED!", MSGBOX_ERROR);
  126. #endif /* _DEBUG */
  127.  
  128.   //redundant, since quitSubsystems(KINIT_EVERYTHING)
  129.    //frees all thread errors automatically anyway
  130.   //freeThreadError();
  131.  
  132.   _getnumallocs
  133.   quitSubsystems(KINIT_EVERYTHING);
  134.   _getnumallocs
  135.  
  136.   return -1;
  137. }}
  138. /******************************************************************************/
  139. /******************************************************************************/
  140. //"ksdl2\src\kit_sdl2\kit_AudioCallbackWrapper.cpp":
  141. #include "_kit_common.hpp"
  142.  
  143.  
  144. namespace kit {
  145.  
  146.  
  147.  
  148.  
  149.  
  150. //workaround for having _AudioCallbackWrapper pause the device,
  151.  //without having to call SDL_PauseAudioDevice inside the callback itself
  152. static int _AudioPauseThread(void* data){
  153.   _AudioDeviceOpaque* opq = (_AudioDeviceOpaque*)data;
  154.   SDL_AudioDeviceID devID = opq->info_p->deviceID;
  155.  
  156.   //wait for the callback to exit before actually pausing
  157.   SDL_LockAudioDevice(devID);
  158.  
  159.   SDL_PauseAudioDevice(devID, 1);
  160.  
  161.   SDL_UnlockAudioDevice(devID);
  162.  
  163.   return 0;
  164.  
  165. }
  166.  
  167. static inline bool startPauseThread(_AudioDeviceOpaque* opq){
  168.   SDL_Thread* pauseThread = SDL_CreateThread(_AudioPauseThread, "kADPause", opq);
  169.  
  170.   if(pauseThread) SDL_DetachThread(pauseThread);
  171.   else            opq->fadeDelay = KIT_U32_MAX;
  172.  
  173.   opq->fadeOut = false;
  174.   opq->playing = false;
  175.  
  176.   return pauseThread != nullptr;
  177.  
  178. }
  179.  
  180.  
  181.  
  182.  
  183.  
  184. //not inlined
  185. static void apply_fade(_AudioDeviceOpaque* opq,
  186.                        f32* stream, u32 stream_len)
  187. {
  188.   f32 fadeDelta   = opq->fadeDelta;
  189.   f32 fadeVolume  = opq->fadeVolume;
  190.   u32 fadeDelay   = opq->fadeDelay;
  191.   u8  numChannels = opq->info_p->numChannels;
  192.  
  193.   u32 smp = 0; //this index is shared, as the loops can jump to others at will
  194.  
  195.  
  196.  
  197.   //FADING OUT
  198.   if(opq->fadeOut){
  199.     _FadeOut:;
  200.     for(; smp<stream_len; ++smp){
  201.       //if audio device starts fading in mid-fadeout, jump to the fade-in loop
  202.       if(!opq->fadeOut) goto _FadeIn;
  203.  
  204.       stream[smp] *= fadeVolume;
  205.  
  206.       //only change fadeVolume every numChannels samples,
  207.        //so that there's 1 fadeVolume state per sample frame
  208.       if(!((smp+1)%numChannels)) fadeVolume -= fadeDelta;
  209.  
  210.       //to enforce a minimum volume
  211.       if(fadeVolume < 0.0f) fadeVolume = 0.0f;
  212.  
  213.     }
  214.  
  215.     //trigger pause thread if fade out is complete
  216.     if(fadeVolume == 0.0f)
  217.       startPauseThread(opq);
  218.  
  219.  
  220.  
  221.   //FADING IN
  222.   } else if(fadeVolume < 1.0f){
  223.     //let stream warm up before fading in (if fadeDelay != 0)
  224.     for(; (fadeDelay)&&(smp<stream_len); ++smp){
  225.       stream[smp] = 0.0f;
  226.       if(!((smp+1)%numChannels)) --fadeDelay;
  227.  
  228.     }
  229.  
  230.  
  231.     _FadeIn:;
  232.     for(; smp<stream_len; ++smp){
  233.       if(opq->fadeOut) goto _FadeOut;
  234.  
  235.       stream[smp] *= fadeVolume;
  236.  
  237.       if(!((smp+1)%numChannels)) fadeVolume += fadeDelta;
  238.  
  239.       if(fadeVolume > 1.0f) fadeVolume = 1.0f;
  240.  
  241.     }
  242.  
  243.  
  244.   }
  245.  
  246.  
  247.  
  248.   //update relevant in opq
  249.   opq->fadeVolume = fadeVolume;
  250.   opq->fadeDelay  = fadeDelay;
  251.  
  252. }
  253.  
  254.  
  255.  
  256.  
  257.  
  258. //for multiplying the by inverse of stuff
  259. #define INV_S8  0.0078125000000000000000000000000f // = 1.0f/0x80
  260. #define INV_S16 0.0000305175781250000000000000000f // = 1.0f/0x8000
  261. #define INV_S32 0.0000000004656612873077392578125f // = 1.0f/0x80000000
  262.  
  263. #define fmtconvloop for(u32 i=0; i<length; ++i) to
  264.  
  265.  
  266. //used for output devices
  267.  //(length should be in samples, not sample frames)
  268. static inline void fmt_to_f32(Mono_smp from, f32* to,
  269.                               u32 length, u16 from_fmt)
  270. {
  271.   switch(from_fmt){
  272.     case SMPFMT_U8 : fmtconvloop[i] = ((f32)from.u8_ [i]-128  )*INV_S8 ; break;
  273.     case SMPFMT_S8 : fmtconvloop[i] = ((f32)from.s8_ [i]      )*INV_S8 ; break;
  274.     case SMPFMT_U16: fmtconvloop[i] = ((f32)from.u16_[i]-32768)*INV_S16; break;
  275.     case SMPFMT_S16: fmtconvloop[i] = ((f32)from.s16_[i]      )*INV_S16; break;
  276.     case SMPFMT_S32: fmtconvloop[i] = ((f32)from.s32_[i]      )*INV_S32; break;
  277.     case SMPFMT_F32: memory::copy(to, from.f32_, length*sizeof(f32));    break;
  278.     //(f32 samples aren't hard-clipped! make sure to keep them -1.0f -> 1.0f)
  279.   }
  280. }
  281.  
  282.  
  283. //used for input devices
  284.  //(again, length should be in samples, not sample frames)
  285. static inline void f32_to_fmt(f32* from, Mono_smp to,
  286.                               u32 length, u16 to_fmt)
  287. {
  288.   //(input f32 samples aren't hard-clipped here either!)
  289.   switch(to_fmt){
  290.     case SMPFMT_U8 : fmtconvloop.u8_ [i] = (u8 )(from[i]*127 + 128    ); break;
  291.     case SMPFMT_S8 : fmtconvloop.s8_ [i] = (s8 )(from[i]*127          ); break;
  292.     case SMPFMT_U16: fmtconvloop.u16_[i] = (u16)(from[i]*32767 + 32768); break;
  293.     case SMPFMT_S16: fmtconvloop.s16_[i] = (s16)(from[i]*32767        ); break;
  294.     case SMPFMT_S32: fmtconvloop.s32_[i] = (s32)(from[i]*0x7fffffff   ); break;
  295.     case SMPFMT_F32: memory::copy(to.f32_, from, length*sizeof(f32));
  296.   }
  297. }
  298.  
  299.  
  300.  
  301.  
  302.  
  303. void _AudioCallbackWrapper(void* userdata, u8* _stream, int len){
  304.   u64 timeStartTicks = SDL_GetPerformanceCounter();
  305.   u64 timeStartMS    = SDL_GetTicks64();
  306.  
  307.  
  308.   AudioDevice* device = (AudioDevice*)userdata;
  309.   f32*         stream = (f32*)_stream;
  310.   u32     stream_size = len;
  311.   u32      stream_len = len / sizeof(f32); //samples, not sample frames
  312.  
  313.  
  314.   _AudioDeviceOpaque* opq = (_AudioDeviceOpaque*)KIT_GET_CLASS_OPAQUE(device);
  315.   AudioDeviceInfo* info_p = opq->info_p;
  316.   info_p->timeStartTicks  = timeStartTicks;
  317.   info_p->timeStartMS     = timeStartMS;
  318.  
  319.  
  320.  
  321.   //if pause thread failed to start, simply write zeros to stream and exit
  322.   if(opq->fadeDelay == KIT_U32_MAX){
  323.     if(!info_p->isInput) memory::set(stream, 0, stream_size);
  324.     return;
  325.  
  326.   }
  327.  
  328.  
  329.  
  330.   if(!info_p->isInput){ //buffer will be written to
  331.     //(memset 0 the _user_ buffer, not the sdl stream)
  332.     if(info_p->zeroBuffer) memory::set(opq->buffer, 0, opq->buffer_size);
  333.  
  334.     try { //attempt to call user callback
  335.       if(info_p->callback)
  336.         opq->fadeOut = !info_p->callback(opq->buffer, info_p);
  337.  
  338.     } catch(const char* errortext){
  339.       SDL_Log("ERROR IN AUDIO CALLBACK: \"%s\"", errortext);
  340.       freeThreadError();
  341.       //set back to 0, since used callback failed
  342.       memory::set(stream, 0, stream_size);
  343.  
  344.     }
  345.  
  346.     //copy buffer to stream (X to f32)
  347.     fmt_to_f32(opq->buffer, stream, stream_len, info_p->sampleFormat);
  348.  
  349.     //apply fade to stream
  350.     apply_fade(opq, stream, stream_len);
  351.  
  352.  
  353.   } else { //buffer will be read from
  354.     //apply fade to stream
  355.     apply_fade(opq, stream, stream_len);
  356.  
  357.     //copy stream to buffer (f32 to X)
  358.     f32_to_fmt(stream, opq->buffer, stream_len, info_p->sampleFormat);
  359.  
  360.     try { //attempt to call user callback
  361.       if(info_p->callback)
  362.         opq->fadeOut = !info_p->callback(opq->buffer, info_p);
  363.  
  364.     } catch(const char* errortext){
  365.       SDL_Log("ERROR IN AUDIO CALLBACK: \"%s\"", errortext);
  366.       freeThreadError();
  367.  
  368.     }
  369.  
  370.   }
  371.  
  372.  
  373. }
  374.  
  375.  
  376.  
  377.  
  378.  
  379. }; /* namespace kit */
  380. /******************************************************************************/
  381. /******************************************************************************/
  382. //"ksdl2\src\kit_sdl2\kit_AudioDevice.cpp":
  383. #include "_kit_common.hpp"
  384.  
  385. #define INDEX_FUNC "AudioDevice::AudioDevice(index)"
  386. #define NAME_FUNC  "AudioDevice::AudioDevice(name)"
  387.  
  388. #define DEVICE_IS_INVALID (!_valid && !_constructing)
  389.  
  390. #define CONSTRUCTOR_ERR(_txt) PUSH_ERRORF("%s: " _txt , funcname)
  391. #define CONSTRUCTOR_ERRSDL    PUSH_ERRORF("%s: \"%s\"", funcname, SDL_GetError())
  392.  
  393. #define DEV_PTR ((_AudioDeviceOpaque*)_opq)
  394.  
  395.  
  396. namespace kit {
  397.  
  398.  
  399.  
  400.  
  401.  
  402. //in "kit_AudioCallbackWrapper.cpp"
  403. void _AudioCallbackWrapper(void* userdata, u8* _stream, int len);
  404.  
  405.  
  406.  
  407.  
  408.  
  409. static inline u32 _count_bits(u32 num){
  410.   u32 count = 0;
  411.  
  412.   while(num > 0){
  413.     if(num&1) ++count;
  414.     num >>= 1;
  415.   }
  416.  
  417.   return count;
  418.  
  419. }
  420.  
  421.  
  422. //not inlined
  423. static void validate_smpfmt(u16 sampleFormat, const char* funcname){
  424.   switch(sampleFormat){
  425.     case SMPFMT_U8    :
  426.     case SMPFMT_S8    :
  427.     case SMPFMT_U16LSB:
  428.     case SMPFMT_S16LSB:
  429.   //case SMPFMT_U16MSB:
  430.   //case SMPFMT_S16MSB:
  431.     case SMPFMT_S32LSB:
  432.   //case SMPFMT_S32MSB:
  433.     case SMPFMT_F32LSB:
  434.   //case SMPFMT_F32MSB:
  435.     case 0            : break;
  436.     default: throw PUSH_ERRORF("%s: unknown sample format 0x%04X",
  437.                                funcname, sampleFormat);
  438.   }
  439.  
  440. }
  441.  
  442.  
  443. static inline void validate_desired(const AudioDeviceInfo* desired,
  444.                                     const char* funcname)
  445. {
  446.   if(desired->sampleRate > KIT_S32_MAX)
  447.     throw PUSH_ERRORF("%s: desired->sampleRate > KIT_S32_MAX", funcname);
  448.  
  449.   if(_count_bits(desired->sampleFrames) > 1)
  450.     throw PUSH_ERRORF("%s: desired->sampleFrames is not a power of 2", funcname);
  451.  
  452.   validate_smpfmt(desired->sampleFormat, funcname);
  453.  
  454.   if(desired->numChannels > 8)
  455.     throw PUSH_ERRORF("%s: desired->numChannels > 8", funcname);
  456.  
  457.   if(desired->callback == nullptr)
  458.     throw PUSH_ERRORF("%s: desired->callback = nullptr", funcname);
  459.  
  460. }
  461.  
  462.  
  463. static inline s32 get_dev_params(SDL_AudioSpec& want,
  464.                                  const AudioDeviceInfo* desired,
  465.                                  AudioDevice* device)
  466. {
  467.   want.freq     = (s32)((desired->sampleRate) ? desired->sampleRate : 48000);
  468.   want.format   = AUDIO_F32LSB;
  469.   want.channels = (desired->numChannels) ? desired->numChannels : 2;
  470.   want.samples  = (desired->sampleFrames) ? desired->sampleFrames : 4096;
  471.   want.callback = _AudioCallbackWrapper;
  472.   want.userdata = device;
  473.  
  474.   s32 allowed_changes = 0;
  475.   if(!desired->sampleRate  ) allowed_changes |= SDL_AUDIO_ALLOW_FREQUENCY_CHANGE;
  476.   if(!desired->sampleFormat) allowed_changes |= SDL_AUDIO_ALLOW_FORMAT_CHANGE;
  477.   if(!desired->numChannels ) allowed_changes |= SDL_AUDIO_ALLOW_CHANNELS_CHANGE;
  478.   if(!desired->sampleFrames) allowed_changes |= SDL_AUDIO_ALLOW_SAMPLES_CHANGE;
  479.  
  480.   return allowed_changes;
  481.  
  482. }
  483.  
  484.  
  485. static inline AudioDeviceInfo set_dev_info(SDL_AudioDeviceID      deviceID,
  486.                                            SDL_AudioSpec          have,
  487.                                            const AudioDeviceInfo* desired)
  488. {
  489.   AudioDeviceInfo info;
  490. //info.timeStartTicks  = 0;
  491. //info.timeStartMS     = 0;
  492.   info.deviceID        = deviceID;
  493.   info.sampleRate      = have.freq;
  494.   info.sampleFrames    = have.samples;
  495.   info.sampleFormat    = have.format;
  496.   info.sampleFrameSize = KIT_AUDIO_BYTESIZE(have.format)*have.channels;
  497.   info.numChannels     = have.channels;
  498.   info.isInput         = desired->isInput;
  499.   info.zeroBuffer      = desired->zeroBuffer;
  500.   info.callback        = desired->callback;
  501.   info.userdata        = desired->userdata;
  502.  
  503.   return info;
  504.  
  505. }
  506.  
  507.  
  508.  
  509.  
  510.  
  511. AudioDevice::AudioDevice(s32 index, //-1 to use default device
  512.                          const AudioDeviceInfo* desired,
  513.                          bool disableFadeDelay)
  514. {
  515.   //check if desired is nullptr, since ->isInput is necessary to get device name
  516.   if(desired  == nullptr) throw PUSH_ERROR(INDEX_FUNC ": desired = nullptr");
  517.  
  518.   const char* name = nullptr;
  519.  
  520.   if(index >= 0){
  521.     name = SDL_GetAudioDeviceName(index, desired->isInput);
  522.  
  523.     if(name == nullptr)
  524.       throw PUSH_ERRORF(INDEX_FUNC ": \"%s\"", SDL_GetError());
  525.  
  526.   }
  527.  
  528.   _construct(name, desired, disableFadeDelay);
  529.  
  530. }
  531.  
  532.  
  533.  
  534.  
  535.  
  536. void AudioDevice::_construct(const char* name,
  537.                              const AudioDeviceInfo* desired,
  538.                              bool disableFadeDelay,
  539.                              bool indexed)
  540. {
  541.   _type = KIT_CLASSTYPE_AUDIODEVICE;
  542.  
  543.   const char* funcname = (indexed) ? INDEX_FUNC : NAME_FUNC;
  544.  
  545.   if(desired  == nullptr) throw PUSH_ERRORF("%s: desired = nullptr", funcname);
  546.  
  547.   AudioDeviceInfo* info_p = (AudioDeviceInfo*)&info; //info is normally const
  548.  
  549.  
  550.  
  551.   //a few domain checks
  552.   validate_desired(desired, funcname);
  553.  
  554.   SDL_AudioSpec want, have;
  555.   s32 allowed_changes = get_dev_params(want, desired, this);
  556.  
  557.  
  558.  
  559.   //actually create the device
  560.   SDL_AudioDeviceID deviceID = SDL_OpenAudioDevice(name, desired->isInput,
  561.                                                    &want, &have, allowed_changes);
  562.  
  563.   if(!deviceID) throw PUSH_ERRORF("%s: \"%s\"", funcname, SDL_GetError());
  564.  
  565.   if(desired->sampleFormat) have.format = desired->sampleFormat;
  566.   else                      validate_smpfmt(have.format, funcname);
  567.  
  568.   *info_p = set_dev_info(deviceID, have, desired);
  569.  
  570.  
  571.  
  572.   _opq = memory::alloc(sizeof(_AudioDeviceOpaque));
  573.  
  574.   if(_opq == nullptr){
  575.     SDL_CloseAudioDevice(info.deviceID);
  576.     throw PUSH_ERRORF("%s: failed to allocate memory for opaque struct", funcname);
  577.  
  578.   }
  579.  
  580.   memory::set(_opq, 0, sizeof(_AudioDeviceOpaque));
  581.  
  582.  
  583.  
  584.   DEV_PTR->info_p      = info_p;
  585.   DEV_PTR->buffer_size = info.sampleFrames * info.sampleFrameSize;
  586.   DEV_PTR->buffer      = memory::alloc(DEV_PTR->buffer_size);
  587.   DEV_PTR->fadeDelta   = 1.0f / ((f32)info.sampleRate*FADEDELTA_SEC);
  588. //DEV_PTR->fadeVolume  = 0.0f;
  589. //DEV_PTR->fadeDelay   = 0;
  590. //DEV_PTR->fadeOut     = false;
  591.   DEV_PTR->noFadeDelay = disableFadeDelay;
  592. //DEV_PTR->playing     = false;
  593.  
  594.   if(DEV_PTR->buffer == nullptr){
  595.     memory::free(&_opq);
  596.     SDL_CloseAudioDevice(info.deviceID);
  597.     throw PUSH_ERRORF("%s: failed to allocate memory for audio buffer", funcname);
  598.  
  599.   }
  600.  
  601.   memory::set(DEV_PTR->buffer, 0, DEV_PTR->buffer_size);
  602.  
  603.  
  604.  
  605.   _valid = true;
  606.   _constructing = false;
  607.  
  608. }
  609.  
  610.  
  611.  
  612.  
  613.  
  614. AudioDevice::~AudioDevice(){
  615.   if(!_valid) return;
  616.   _valid = false;
  617.  
  618.   if(info.deviceID != 0) SDL_CloseAudioDevice(info.deviceID);
  619.   if(_opq != nullptr){
  620.     memory::free(&DEV_PTR->buffer);
  621.     memory::free(&_opq);
  622.   }
  623.  
  624. }
  625.  
  626.  
  627.  
  628.  
  629.  
  630. bool AudioDevice::isPlaying(){
  631.   if(DEVICE_IS_INVALID)
  632.     throw PUSH_ERROR("AudioDevice::isPlaying(): invalid device");
  633.  
  634.   //return SDL_GetAudioDeviceStatus(info.deviceID) == SDL_AUDIO_PLAYING;
  635.   return DEV_PTR->playing;
  636.  
  637. }
  638.  
  639.  
  640.  
  641.  
  642.  
  643. bool AudioDevice::isActive(){
  644.   if(DEVICE_IS_INVALID)
  645.     throw PUSH_ERROR("AudioDevice::isActive(): invalid device");
  646.  
  647.   return SDL_GetAudioDeviceStatus(info.deviceID) == SDL_AUDIO_PLAYING;
  648.   //return DEV_PTR->playing;
  649.  
  650. }
  651.  
  652.  
  653.  
  654.  
  655.  
  656. void AudioDevice::setCallback(AudioCallback callback){
  657.   if(DEVICE_IS_INVALID)
  658.     throw PUSH_ERROR("AudioDevice::setCallback(): invalid device");
  659.  
  660.   if(callback == nullptr)
  661.     throw PUSH_ERROR("AudioDevice::setCallback(): callback = nullptr");
  662.  
  663.   SDL_LockAudioDevice(info.deviceID);
  664.  
  665.   ((AudioDeviceInfo*)&info)->callback = callback;
  666.  
  667.   SDL_UnlockAudioDevice(info.deviceID);
  668.  
  669. }
  670.  
  671.  
  672.  
  673.  
  674. void AudioDevice::setUserdata(void* userdata){
  675.   if(DEVICE_IS_INVALID)
  676.     throw PUSH_ERROR("AudioDevice::setUserdata(): invalid device");
  677.  
  678.   SDL_LockAudioDevice(info.deviceID);
  679.  
  680.   ((AudioDeviceInfo*)&info)->userdata = userdata;
  681.  
  682.   SDL_UnlockAudioDevice(info.deviceID);
  683.  
  684. }
  685.  
  686.  
  687.  
  688.  
  689. void AudioDevice::setPlayback(bool playing){
  690.   if(DEVICE_IS_INVALID)
  691.     throw PUSH_ERROR("AudioDevice::setPlayback(): invalid device");
  692.  
  693.  
  694.   //this should occur when _AudioCallbackWrapper
  695.    //fails to trigger the pause thread
  696.   if(DEV_PTR->fadeDelay == KIT_U32_MAX){
  697.     SDL_LockAudioDevice(info.deviceID);
  698.  
  699.     SDL_PauseAudioDevice(info.deviceID, true);
  700.  
  701.     DEV_PTR->fadeVolume = 0.0f;
  702.     DEV_PTR->fadeDelay  = 0;
  703.     DEV_PTR->fadeOut    = false;
  704.     DEV_PTR->playing    = false;
  705.  
  706.     SDL_UnlockAudioDevice(info.deviceID);
  707.  
  708.   }
  709.  
  710.  
  711.   DEV_PTR->fadeOut = !playing;
  712.   if(playing && !DEV_PTR->playing){
  713.     //the purpose of fadeDelay is to mute for some samples
  714.      //to give the sdl audio device some time to warm up,
  715.      //otherwise artifacts start to occur (for me, anyway)
  716.     if(!DEV_PTR->noFadeDelay) DEV_PTR->fadeDelay = (u32)(info.sampleRate * FADEDELAY_SEC);
  717.     else                      DEV_PTR->fadeDelay = 0;
  718.  
  719.     DEV_PTR->fadeVolume = 0.0f;
  720.     DEV_PTR->playing    = true;
  721.  
  722.     SDL_PauseAudioDevice(info.deviceID, false);
  723.  
  724.   }
  725.  
  726. }
  727.  
  728.  
  729.  
  730.  
  731. void AudioDevice::setPlaybackAndWait(bool playing){
  732.   if(DEVICE_IS_INVALID)
  733.     throw PUSH_ERROR("AudioDevice::setPlaybackAndWait(): invalid device");
  734.  
  735.  
  736.   bool wasPlaying = DEV_PTR->playing;
  737.  
  738.   setPlayback(playing);
  739.  
  740.  
  741.   if(playing && !wasPlaying && !DEV_PTR->noFadeDelay){
  742.     time::sleep((u32)( FADETOTAL_SEC*1000 ));
  743.  
  744.   } else {
  745.     time::sleep((u32)( FADEDELTA_SEC*1000 ));
  746.  
  747.   }
  748.  
  749. }
  750.  
  751.  
  752.  
  753.  
  754.  
  755. void AudioDevice::lock(bool locked){
  756.   if(DEVICE_IS_INVALID)
  757.     throw PUSH_ERROR("AudioDevice::lock(): invalid device");
  758.  
  759.   if(locked) SDL_LockAudioDevice(info.deviceID);
  760.   else       SDL_UnlockAudioDevice(info.deviceID);
  761.  
  762. }
  763.  
  764.  
  765.  
  766.  
  767.  
  768. }; /* namespace kit */
  769. /******************************************************************************/
  770. /******************************************************************************/
  771. //"ksdl2\src\kit_sdl2\kit_audio_func.cpp":
  772. #include "_kit_common.hpp"
  773.  
  774. #define AUDIO_UNINIT_CHECK(_funcname) \
  775.   if(!_gl.init.audio){ throw PUSH_ERROR(_funcname ": audio subsystem is uninitialized"); }
  776.  
  777. namespace kit {
  778.  
  779.  
  780.  
  781.  
  782.  
  783. static AudioDeviceInfo _AudioSpecToDevInfo(SDL_AudioSpec& spec, bool isInput){
  784.   AudioDeviceInfo info;
  785.   info.sampleRate      = spec.freq; //(hopefully freq is never negative!)
  786.   info.sampleFrames    = spec.samples;
  787.   info.sampleFormat    = spec.format;
  788.   info.sampleFrameSize = KIT_AUDIO_BYTESIZE(spec.format)*spec.channels;
  789.   info.numChannels     = spec.channels;
  790.   info.isInput         = isInput;
  791.  
  792.   return info;
  793.  
  794. }
  795.  
  796.  
  797.  
  798.  
  799.  
  800. AudioDeviceInfo audio::getDefaultDevInfo(char** name_p, bool isInput){
  801.   AUDIO_UNINIT_CHECK("audio::getDefaultDevInfo()");
  802.  
  803.   SDL_AudioSpec spec;
  804.   if(SDL_GetDefaultAudioInfo(name_p, &spec, isInput) != 0)
  805.     throw PUSH_ERRORF("audio::getDefaultDevInfo(): \"%s\"", SDL_GetError());
  806.  
  807.   if(name_p != nullptr)
  808.     ++numAllocations; //memory has been allocated; increment # of allocations
  809.  
  810.   return _AudioSpecToDevInfo(spec, isInput);
  811.  
  812. }
  813.  
  814.  
  815.  
  816.  
  817.  
  818. AudioDeviceInfo audio::getDeviceInfo(s32 index, bool isInput){
  819.   AUDIO_UNINIT_CHECK("audio::getDeviceInfo()");
  820.  
  821.   SDL_AudioSpec spec;
  822.   if(SDL_GetAudioDeviceSpec(index, isInput, &spec) != 0)
  823.     throw PUSH_ERRORF("audio::getDeviceInfo(): \"%s\"", SDL_GetError());
  824.  
  825.   return _AudioSpecToDevInfo(spec, isInput);
  826.  
  827. }
  828.  
  829.  
  830.  
  831.  
  832.  
  833. s32 audio::getNumDevices(bool isInput){
  834.   AUDIO_UNINIT_CHECK("audio::getNumDevices()");
  835.  
  836.   return SDL_GetNumAudioDevices(isInput);
  837.  
  838. }
  839.  
  840.  
  841.  
  842.  
  843.  
  844. const char* audio::getDeviceName(u32 index, bool isInput){
  845.   AUDIO_UNINIT_CHECK("audio::getDeviceName()");
  846.  
  847.   if(index > KIT_S32_MAX)
  848.     throw PUSH_ERROR("audio::getDeviceName(): index > KIT_S32_MAX");
  849.  
  850.   const char* name = SDL_GetAudioDeviceName((s32)index, isInput);
  851.   if(name == nullptr)
  852.     throw PUSH_ERRORF("audio::getDeviceName(): \"%s\"", SDL_GetError());
  853.  
  854.   return name;
  855.  
  856. }
  857.  
  858.  
  859.  
  860.  
  861.  
  862. }; /* namespace kit */
  863. /******************************************************************************/
  864. /******************************************************************************/
  865. //"ksdl2\src\kit_sdl2\kit_fileio.cpp":
  866. #include "_kit_common.hpp"
  867.  
  868.  
  869. //a wrapper; fileio::remove and remove are treated as the same inside fileio
  870. static inline int _remove(const char* filePath){ return remove(filePath); }
  871.  
  872.  
  873. namespace kit {
  874.  
  875.  
  876.  
  877.  
  878.  
  879. BinaryData::BinaryData(const char* filePath){
  880.   _type = KIT_CLASSTYPE_BINARYDATA;
  881.  
  882.  
  883.   _data = (char*)SDL_LoadFile(filePath, &_data_len);
  884.   if(_data == nullptr)
  885.     throw PUSH_ERRORF("BinaryData::BinaryData(file): \"%s\"", SDL_GetError());
  886.  
  887.   ++numAllocations;
  888.  
  889.  
  890.   _valid = true;
  891.   _constructing = false;
  892.  
  893. }
  894.  
  895.  
  896.  
  897.  
  898. BinaryData::BinaryData(const void* data, size_t data_len){
  899.   _type = KIT_CLASSTYPE_BINARYDATA;
  900.  
  901.   if(data_len == KIT_U64_MAX)
  902.     throw PUSH_ERROR("BinaryData::BinaryData(memory): data_len = KIT_U64_MAX"); //lol
  903.  
  904.  
  905.   _data = (char*)memory::alloc(data_len+1);
  906.   if(_data == nullptr)
  907.     throw PUSH_ERROR("BinaryData::BinaryData(memory): failed to allocate memory for _data");
  908.  
  909.  
  910.   _data_len = data_len;
  911.   _data[data_len] = 0; //add null-terminator for convenience
  912.  
  913.   if(data != nullptr) memory::copy(_data, data, data_len);
  914.  
  915.  
  916.   _valid = true;
  917.   _constructing = false;
  918.  
  919. }
  920.  
  921.  
  922.  
  923.  
  924. BinaryData::~BinaryData(){
  925.   if(!_valid) return;
  926.   _valid = false;
  927.  
  928.  
  929.   if(_data != nullptr) memory::free(&_data);
  930.  
  931. }
  932.  
  933.  
  934.  
  935.  
  936.  
  937. //unlike the other fileio functions and whatnot,
  938.  //this obviously doesn't throw if the file doesn't exist
  939. bool fileio::exists(const char* filePath){
  940.   if(filePath == nullptr)
  941.     throw PUSH_ERROR("fileio::exists(): filePath = nullptr");
  942.  
  943.   SDL_RWops* file = SDL_RWFromFile(filePath, "rb");
  944.  
  945.   if(file != nullptr)
  946.     SDL_RWclose(file);
  947.  
  948.   return file != nullptr;
  949.  
  950. }
  951.  
  952.  
  953.  
  954. size_t fileio::size(const char* filePath){
  955.   if(filePath == nullptr)
  956.     throw PUSH_ERROR("fileio::size(): filePath = nullptr");
  957.  
  958.   SDL_RWops* file = SDL_RWFromFile(filePath, "rb");
  959.   if(file == nullptr)
  960.     throw PUSH_ERRORF("fileio::size(): \"%s\"", SDL_GetError());
  961.  
  962.   if(SDL_RWseek(file, 0, RW_SEEK_END)<0){
  963.     SDL_RWclose(file);
  964.     throw PUSH_ERRORF("fileio::size(): \"%s\"", SDL_GetError());
  965.   }
  966.  
  967.   s64 fileSize = SDL_RWtell(file);
  968.   if(fileSize < 0){
  969.     //since SDL_RWclose() can overwrite the previous result of SDL_GetError(),
  970.      //the result of fstr is cached before SDL_RWclose() is actually called
  971.     const char* fstr_result = fstr("fileio::size(): \"%s\"", SDL_GetError());
  972.  
  973.     SDL_RWclose(file);
  974.  
  975.     throw PUSH_ERROR(fstr_result);
  976.  
  977.   }
  978.  
  979.   SDL_RWclose(file);
  980.  
  981.   return (size_t)fileSize;
  982.  
  983. }
  984.  
  985.  
  986.  
  987. void fileio::remove(const char* filePath){
  988.   if(filePath == nullptr)
  989.     throw PUSH_ERROR("fileio::remove(): filePath = nullptr");
  990.  
  991.   if(_remove(filePath) != 0) //this is a wrapper for remove() (see line 5)
  992.     throw PUSH_ERRORF("fileio::remove(): failed to delete file \"%s\"", filePath);
  993.  
  994. }
  995.  
  996.  
  997.  
  998.  
  999.  
  1000. //heap memory is allocated here,
  1001.  //and should be freed with memory::free()
  1002.  //(also, while *dataSize_p won't be populated with resulting
  1003.  // filesize if dataSize_p is nullptr, it won't actually error)
  1004. void* fileio::readAll(const char* filePath, size_t* dataSize_p){
  1005.   if(filePath == nullptr)
  1006.     throw PUSH_ERROR("fileio::readAll(): filePath = nullptr");
  1007.  
  1008.   void* data = SDL_LoadFile(filePath, dataSize_p);
  1009.  
  1010.   if(data == nullptr)
  1011.     throw PUSH_ERRORF("fileio::readAll(): \"%s\"", SDL_GetError());
  1012.  
  1013.   ++numAllocations;
  1014.  
  1015.   return data;
  1016.  
  1017. }
  1018.  
  1019.  
  1020.  
  1021. //writes to a binary file from a buffer
  1022. void fileio::writeAll(const char* filePath, const void* data,
  1023.                        size_t dataSize, bool append)
  1024. {
  1025.   if(filePath == nullptr) throw PUSH_ERROR("fileio::writeAll(): filePath = nullptr");
  1026.   if(data     == nullptr) throw PUSH_ERROR("fileio::writeAll(): data = nullptr");
  1027.  
  1028.   SDL_RWops* file = SDL_RWFromFile(filePath, (append) ? "ab" : "wb");
  1029.   if(file == nullptr)
  1030.     throw PUSH_ERRORF("fileio::writeAll(): \"%s\"", SDL_GetError());
  1031.  
  1032.   size_t bytesWritten = SDL_RWwrite(file, data, 1, dataSize);
  1033.  
  1034.   SDL_RWclose(file);
  1035.  
  1036.   if(bytesWritten < dataSize)
  1037.     throw PUSH_ERROR("fileio::writeAll(): bytesWritten < dataSize");
  1038.  
  1039. }
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045. }; /* namespace kit */
  1046.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement