Advertisement
Kitomas

kit_sdl2_kmixerDevice.c as of 2023-8-31

Sep 1st, 2023
750
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.99 KB | None | 0 0
  1. #include "../include/kit_sdl2/kit_kmixer.h"
  2. #include "../_private/include/_kit_kmixerPrivate.h"
  3. #include "../_private/include/_kit_privmacro.h"
  4.  
  5.  
  6.  
  7.  
  8. #define fadeCutoff 0.0002
  9. //sdl audio artifacts seem to end at 10ms after unpausing,
  10.  //so i'll add one more millisecond just to be sure
  11. #define fadeInDelaySeconds 0.011
  12.  
  13.  
  14.  
  15.  
  16. int kit_kmixerDeviceLock(kit_kmixerDevice* device, SDL_bool lockState){
  17.   _CHECK_IF_DEVICE_IS_VALID(-1)
  18.  
  19.   if(lockState){ //lock
  20.     SDL_LockAudioDevice(device->_devID);
  21.     if(SDL_LockMutex(device->_lock)) return -2;
  22.     ++device->_lockCount;
  23.   } else if (device->_lockCount>0){ //unlock (only if actually locked)
  24.     --device->_lockCount;
  25.     if(SDL_UnlockMutex(device->_lock)) return -2;
  26.     SDL_UnlockAudioDevice(device->_devID);
  27.   } else { //lockstate is false, but _lockcount is also 0
  28.     SDL_SetError("device is fully unlocked");
  29.     return 1; //warning, not technically an error
  30.   }
  31.  
  32.   return 0;
  33. }
  34.  
  35.  
  36.  
  37.  
  38. //workaround for having _kit_kmixerDeviceCallback pause the device,
  39.  //without having to call SDL_PauseAudioDevice inside the callback itself
  40. int _kit_kmixerDevicePauseThread(void* data){
  41.   kit_kmixerDevice* device=data;
  42.  
  43.   kit_kmixerDeviceLock(device,SDL_TRUE);
  44.  
  45.   SDL_PauseAudioDevice(device->_devID,1);
  46.   device->_playing=SDL_FALSE;
  47.  
  48.   kit_kmixerDeviceLock(device,SDL_FALSE);
  49.   return 0;
  50. }
  51.  
  52.  
  53.  
  54. //remember, ignore input if index is 0
  55. void _kit_kmixerDeviceCallback(void* userdata, Uint8* _stream, int len){
  56.   kit_kmixerDevice* device=userdata;
  57.   SDL_LockMutex(device->_lock);
  58.   _IF_GOTO(device->_closing,_unlock_device,;)
  59.   //if previous attempt to pause device failed, memset 0 the entire buffer
  60.   _IF_GOTO(device->_fadeInDelay==-1,_unlock_device, memset(_stream,0,len))
  61.  
  62.   //get values from device
  63.   float fadeMultiplier=device->_fadeMuliplier;
  64.   float fadeVolume=device->_fadeVolume;
  65.   Uint32 fadeInDelay=device->_fadeInDelay;
  66.  
  67.   //get values from voice 0 (device proxy)
  68.    //(input is for voice 0 is always set to _stream here)
  69.   _kit_kmixerVoice* raw=device->_voices.raw->ptr;
  70.    //(also memset 0 if there are literally no voices connected to the device)
  71.   _IF_GOTO(raw[0].inputs==NULL,_unlock_device, memset(_stream,0,len))
  72.   _kit_kmixerVoice* voice0=&raw[0];
  73.   SDL_bool stereo=voice0->spec.stereo;
  74.   float volL=voice0->volL; volL=(volL>=0)?volL:1.0f;
  75.   float volR=voice0->volR; volR=(volR>=0)?volR:volL;
  76.  
  77.   int size=len; //will stay as len's original value; the buffer size in bytes
  78.   len/=sizeof(float)<<stereo; // = number of sample frames
  79.  
  80.   /**/
  81.   if(voice0->spec.callback!=NULL)
  82.     voice0->spec.callback(voice0->spec.userdata,voice0->bufferInput.v,size,SDL_FALSE);
  83.   //_kit_kmixerVoice* voice=&raw[1];
  84.   //memset(voice0->bufferInput.v,0,size);
  85.   /**/
  86.  
  87.   //apply simple fade effect to reduce popping when pausing and unpausing the device
  88.    //as well as apply voice 0's volume
  89.   memcpy(_stream, voice0->bufferInput.v, size);
  90.   Uint32 i=0; //this index is shared, as the loops can jump to others at will
  91.    //stereo samples
  92.   if(stereo){ _stereo_samples_f32* stream=(void*)_stream;
  93.     if(device->_fadeOut){
  94.       _do_fade_out_stereo: //SDL_Log("fade out stereo");
  95.       for(; i<len; ++i){
  96.         if(!device->_fadeOut){ fadeVolume=1-fadeVolume; goto _do_fade_in_stereo; }
  97.         stream[i].l*=fadeVolume*volL;
  98.         stream[i].r*=fadeVolume*volR;
  99.         fadeVolume*=fadeMultiplier;
  100.       }
  101.       if(fadeVolume<fadeCutoff){
  102.         SDL_Thread* t=SDL_CreateThread(_kit_kmixerDevicePauseThread,"_PauseTh", device);
  103.         //setting _fadeInDelay to -1 will make further calls to the device callback
  104.          //to simply memset 0 until kit_kmixerDevicePlay is called again
  105.         if(t==NULL) device->_fadeInDelay=-1; //0xffffffff
  106.       }
  107.  
  108.     } else if(!fadeInDelay){
  109.       _do_normal_stereo: //SDL_Log("normal stereo");
  110.       for(; i<len; ++i){
  111.         if(device->_fadeOut){ goto _do_fade_out_stereo; }
  112.         stream[i].l*=volL;
  113.         stream[i].r*=volR;
  114.       }
  115.  
  116.     } else { //let device warm up before fading in
  117.       for(; (fadeInDelay)&&(i<len); ++i){ //write 0s for fadeInDelaySeconds
  118.         stream[i].l=stream[i].r = 0; --fadeInDelay;
  119.       }
  120.       _do_fade_in_stereo: //SDL_Log("fade in stereo");
  121.       for(; i<len; ++i){
  122.         if(device->_fadeOut){ fadeVolume=1-fadeVolume; goto _do_fade_out_stereo; }
  123.         else if(fadeVolume<fadeCutoff){ fadeVolume=1; goto _do_normal_stereo; }
  124.         stream[i].l*=(1-fadeVolume)*volL;
  125.         stream[i].r*=(1-fadeVolume)*volR;
  126.         fadeVolume*=fadeMultiplier;
  127.       }
  128.  
  129.     }
  130.  
  131.    //mono samples
  132.   } else { float* stream=(void*)_stream;
  133.     if(device->_fadeOut){
  134.       _do_fade_out_mono: //SDL_Log("fade out mono");
  135.       for(; i<len; ++i){
  136.         if(!device->_fadeOut){ fadeVolume=1-fadeVolume; goto _do_fade_in_mono; }
  137.         stream[i]*=fadeVolume*volL;
  138.         fadeVolume*=fadeMultiplier;
  139.       }
  140.       if(fadeVolume<fadeCutoff){
  141.         SDL_Thread* t=SDL_CreateThread(_kit_kmixerDevicePauseThread,"_PauseTh", device);
  142.         if(t==NULL) device->_fadeInDelay=-1; //0xffffffff
  143.       }
  144.  
  145.     } else if(!fadeInDelay){
  146.       _do_normal_mono: //SDL_Log("normal mono");
  147.       for(; i<len; ++i){
  148.         if(device->_fadeOut){ goto _do_fade_out_mono; }
  149.         stream[i]*=volL;
  150.       }
  151.  
  152.     } else { //let device warm up before fading in
  153.       for(; (fadeInDelay)&&(i<len); ++i){ //write 0s for fadeInDelaySeconds
  154.         stream[i]=0; --fadeInDelay;
  155.       }
  156.       _do_fade_in_mono: //SDL_Log("fade in mono");
  157.       for(; i<len; ++i){
  158.         if(device->_fadeOut){ fadeVolume=1-fadeVolume; goto _do_fade_out_mono; }
  159.         else if(fadeVolume<fadeCutoff){ fadeVolume=1; goto _do_normal_mono; }
  160.         stream[i]*=(1-fadeVolume)*volL;
  161.         fadeVolume*=fadeMultiplier;
  162.       }
  163.  
  164.     }
  165.  
  166.   }
  167.  
  168.  
  169.   //update device struct to any relevant new values
  170.   device->_fadeVolume=fadeVolume;   //update fade volume
  171.   device->_fadeInDelay=fadeInDelay; //update fade in delay
  172.   _unlock_device: SDL_UnlockMutex(device->_lock);
  173. }
  174.  
  175.  
  176.  
  177.  
  178. int kit_kmixerDevicePlay(kit_kmixerDevice* device, SDL_bool playState){
  179.   _CHECK_IF_DEVICE_IS_VALID(-1)
  180.  
  181.   kit_kmixerDeviceLock(device,SDL_TRUE);
  182.   _IF_GOTO(device->_closing,_unlock_device,;)
  183.  
  184.   //this should occur when the device callback
  185.    //fails to trigger the pause thread
  186.   if(device->_fadeInDelay==-1){
  187.     SDL_PauseAudioDevice(device->_devID,1);
  188.     device->_playing=SDL_FALSE;
  189.     device->_fadeInDelay=0;
  190.   }
  191.  
  192.   device->_fadeOut=!(playState&=1);
  193.   if(playState && !device->_playing){
  194.     //the purpose of fadeInDelay is to mute for some samples
  195.      //to give the sdl audio device some time to warm up
  196.     device->_fadeInDelay=device->_spec.freq*fadeInDelaySeconds;
  197.     SDL_PauseAudioDevice(device->_devID,0);
  198.   }
  199.  
  200.   _unlock_device: kit_kmixerDeviceLock(device,SDL_FALSE);
  201.   return 0;
  202. }
  203.  
  204.  
  205.  
  206.  
  207. int kit_kmixerDeviceClose(kit_kmixerDevice** device_p){
  208.   _IF_SDLERR_R(device_p==NULL,-1,;,"device_p cannot be NULL")
  209.   kit_kmixerDevice* device=*device_p;
  210.   _IF_SDLERR_R(device==NULL,-2,;,"*device_p cannot be NULL")
  211.   //ignore MSB of struct ID when comparing here
  212.   _IF_SDLERR_R((device->_magic.num&U64_MSBC)!=_DEV_MAGIC_NUM,-3,;,"*device_p is invalid")
  213.  
  214.   device->_closing=SDL_TRUE;
  215.  
  216.   //this should pause this thread until _kit_kmixerDeviceCallback finishes
  217.   if(device->_devID!=0) SDL_CloseAudioDevice(device->_devID);
  218.  
  219.   if(device->_voices.raw != NULL){
  220.     //since voice removal is recursive, removing voice 0 will remove every
  221.      //other voice too, as every voice is connected to it in some way
  222.     if(kit_kmixerVoiceRemove(device,0)) return -4;
  223.   }
  224.  
  225.   if(device->_voices.chain != NULL) kit_coreVectorDestroy(&device->_voices.chain);
  226.   if(device->_voices.ord != NULL)   kit_coreVectorDestroy(&device->_voices.ord);
  227.   if(device->_voices.raw != NULL)   kit_coreVectorDestroy(&device->_voices.raw);
  228.  
  229.   if(device->_thread.pool != NULL)  kit_coreVectorDestroy(&device->_thread.pool);
  230.   if(device->_thread.queue != NULL) kit_coreVectorDestroy(&device->_thread.queue);
  231.   if(device->_thread.cond != NULL)  SDL_DestroyCond(device->_thread.cond);
  232.  
  233.   if(device->_lock!=NULL) SDL_DestroyMutex(device->_lock);
  234.  
  235.   SDL_free(device); *device_p=NULL;
  236.  
  237.   return 0;
  238. }
  239.  
  240.  
  241.  
  242. //(i don't know how to do exponential decay, so i'm using a lookup table)
  243. Sint32 _kit_kmixerDeviceRates[16]={
  244.     1000,   2000,   4000,   8000,
  245.    11025,  16000,  22050,  32000,
  246.    44100,  48000,  88200,  96000,
  247.   176400, 192000, 352800, 384000
  248. };
  249. float _kit_kmixerDeviceFadeMuls[16]={
  250.   0.021649449000, 0.147112140000, 0.383552000000, 0.619332447000,
  251.   0.706352736000, 0.786982133000, 0.840447939000, 0.887121599000,
  252.   0.916759476883, 0.923258340930, 0.957475575084, 0.960862072327,
  253.   0.978506808910, 0.980235906283, 0.989195030775, 0.990068556095
  254. };
  255. #define _LERP(_v0,_v1, _t) ((1-(_t))*(_v0) + (_t)*(_v1))
  256. static inline float _kit_kmixerDeviceGetFadeMul(Sint32 sampleRate){
  257.   //range checks for sampleRate is done inside kit_kmixerDeviceOpen
  258.   Sint32 rangeLow,rangeHigh, i=0;
  259.   for(; i<((sizeof(_kit_kmixerDeviceRates)/sizeof(Sint32))-1); ++i){
  260.     rangeLow =_kit_kmixerDeviceRates[i  ];
  261.     rangeHigh=_kit_kmixerDeviceRates[i+1];
  262.     if(rangeLow<=sampleRate && sampleRate<=rangeHigh) break;
  263.   }
  264.   sampleRate-=rangeLow; rangeHigh -=rangeLow;
  265.   return _LERP(_kit_kmixerDeviceFadeMuls[i  ], //from
  266.                _kit_kmixerDeviceFadeMuls[i+1], //to
  267.                (float)sampleRate/rangeHigh);   //percentage
  268. }
  269.  
  270. kit_kmixerDevice* kit_kmixerDeviceOpen(const char* deviceName, int allowedChanges,
  271.                                        const kit_kmixerVoiceSpec* voiceSpecDesired,
  272.                                        kit_kmixerVoiceSpec* voiceSpecObtained)
  273. {
  274.   kit_kmixerDevice* device=NULL;
  275.   _IF_SDLERR(!_kit_kmixerGlobals.init,;,"kmixer is not initialized")
  276.   _IF_SDLERR(voiceSpecDesired==NULL,;,"voiceSpecDesired cannot be NULL")
  277.   device=SDL_malloc(sizeof(kit_kmixerDevice));
  278.   _IF_GOTO_ERROR(device==NULL,;)
  279.   memset(device, 0, sizeof(kit_kmixerDevice));
  280.  
  281.  
  282.   //the high byte will be set to \x00 on success,
  283.    //because _magic.str could then be used as a null-terminated string ("kmxrDev\x00")
  284.   device->_magic.num=U64_MSB|_DEV_MAGIC_NUM; //="kmxrDev\xff"
  285.  
  286.  
  287.   SDL_AudioSpec specWant, specHave;
  288.   specWant.freq=voiceSpecDesired->freq;
  289.   specWant.format=AUDIO_F32;
  290.   specWant.channels=1+(voiceSpecDesired->stereo&1);
  291.   specWant.samples=voiceSpecDesired->samples;
  292.   specWant.callback=_kit_kmixerDeviceCallback;
  293.   specWant.userdata=device;
  294.  
  295.  
  296.    //assuming 44.1kHz, <=16 sample frames would be well under 1ms lol
  297.    //(even at 8kHz, it'd only be 2ms)
  298.   _IF_SDLERR(specWant.samples<32,;,"samples < 32");
  299.   _IF_SDLERR(count_bits(specWant.samples)>1,;,"samples not a power of 2");
  300.  
  301.  
  302.   //the sdl audio device itself
  303.   allowedChanges&=~SDL_AUDIO_ALLOW_FORMAT_CHANGE;  //samples are always f32 internally
  304.   allowedChanges&=~SDL_AUDIO_ALLOW_SAMPLES_CHANGE; //i want to guarantee that samples is a power of 2
  305.   device->_devID=SDL_OpenAudioDevice(deviceName,0, &specWant,&specHave, allowedChanges);
  306.   _IF_GOTO_ERROR(!device->_devID,;)
  307.   _IF_SDLERR(!specHave.channels,;,"channels returned as 0") //this shouldn't be able to happen
  308.   _IF_SDLERR(specHave.channels>2,;,"channels returned as %i",specHave.channels)
  309.   _IF_SDLERR(specHave.freq<1000,;,"freq returned as <1kHz")
  310.   _IF_SDLERR(specHave.freq>384000,;,"freq returned as >384kHz")
  311.   device->_spec=specHave;
  312.  
  313.  
  314.   //fill in obtained voice
  315.   voiceSpecObtained->remove  =voiceSpecDesired->remove;
  316.   voiceSpecObtained->callback=voiceSpecDesired->callback;
  317.   voiceSpecObtained->userdata=voiceSpecDesired->userdata;
  318.   voiceSpecObtained->freq    =specHave.freq;
  319.   voiceSpecObtained->_size   =0; //filled in during call to kit_kmixerVoiceAdd
  320.   voiceSpecObtained->stereo  =specHave.channels==2;
  321.   voiceSpecObtained->samples =specHave.samples;
  322.   voiceSpecObtained->format  =voiceSpecDesired->format;
  323.  
  324.  
  325.   device->_lock=SDL_CreateMutex();
  326.   _IF_GOTO_ERROR(device->_lock==NULL,;)
  327.  
  328.  
  329.   //thread stuff
  330.   device->_thread.cond=SDL_CreateCond();
  331.   _IF_GOTO_ERROR(device->_thread.cond==NULL,;)
  332.   device->_thread.queue=kit_coreVectorCreate(1,0,0,sizeof(kit_coreThread),U32_STR("cT \x00"),NULL);
  333.   _IF_GOTO_ERROR(device->_thread.queue==NULL,;)
  334.   device->_thread.pool=kit_coreVectorCreate(_kit_kmixerGlobals.threadPoolSize,0,0,
  335.                                             sizeof(kit_coreThread),U32_STR("cT \x00"),NULL);
  336.   _IF_GOTO_ERROR(device->_thread.pool==NULL,;)
  337.  
  338.  
  339.   //voices lists-related
  340.   device->_voices.raw=kit_coreVectorCreate(1,0,0,sizeof(_kit_kmixerVoice),U32_STR("kV \x00"),NULL);
  341.   _IF_GOTO_ERROR(device->_voices.raw==NULL,;)
  342.   device->_voices.ord=kit_coreVectorCreate(1,1,0,sizeof(_kit_kmixerVoice),U32_STR("kV \x00"),NULL);
  343.   _IF_GOTO_ERROR(device->_voices.ord==NULL,;)
  344.   device->_voices.chain=kit_coreVectorCreate(1,0,0,sizeof(Uint32),U32_STR("U4 \x00"),NULL);
  345.   _IF_GOTO_ERROR(device->_voices.chain==NULL,;)
  346.  
  347.  
  348.   //fill in voice 0
  349.   _kit_kmixerVoice* raw=device->_voices.raw->ptr;
  350.  
  351.   raw->lock=SDL_CreateMutex();
  352.   _IF_GOTO_ERROR(raw->lock==NULL,;)
  353.   raw->inputs   =NULL; //created when a voice gets added
  354.   raw->inputRefs=NULL; //also created when a voice gets added
  355.   raw->output   =NULL; //unused for voice 0
  356.  
  357.    //(voice 0's bufferInput is copied to device callback's _stream)
  358.   raw->bufferInput.v  =SDL_malloc(specHave.size);
  359.   raw->bufferUser.v   =NULL; //unused for voice 0
  360.   raw->bufferConvert.v=NULL; //unused for voice 0
  361.   raw->bufferOutput.v =NULL; //unused for voice 0
  362.  
  363.   raw->spec.callback=voiceSpecObtained->callback;
  364.   raw->spec.userdata=voiceSpecObtained->userdata;
  365.   raw->spec.freq    =specHave.freq;
  366.   raw->spec._size   =specHave.size;
  367.   raw->spec.stereo  =specHave.channels==2;
  368.   raw->spec.samples =specHave.samples;
  369.   raw->spec.format  =specHave.format;
  370.  
  371.   raw->chainStage=0;
  372.   raw->index=0;
  373.  
  374.   raw->volL=1.0f;
  375.   raw->volR=(raw->spec.stereo) ? 1.0f : -1.0f;
  376.  
  377.   raw->applyVolume=SDL_TRUE;
  378.   raw->stereoOutput=raw->spec.stereo;
  379.  
  380.  
  381.   //copy reference of voice 0 to ord...
  382.   ((_kit_kmixerVoice***)device->_voices.ord->ptr)[0][0]=&raw[0];
  383.   //...then set first element of chain to 1
  384.   ((Uint32*)device->_voices.chain->ptr)[0]=1;
  385.  
  386.  
  387.   device->_fadeMuliplier=_kit_kmixerDeviceGetFadeMul(specHave.freq);
  388.   //actual volume when fading in will be 1-_fadeVolume,
  389.    //before _fadeVolume*=_fadeMultiplier
  390.   device->_fadeVolume=1.0f;
  391.  
  392.  
  393.   //redundant because of the memset, but whatever
  394.   device->_closing=SDL_FALSE;
  395.   device->_fadeOut=SDL_FALSE;
  396.  
  397.  
  398.   //create initial voice, only if format != 0
  399.   if(voiceSpecObtained->format){
  400.     _IF_GOTO_ERROR(!kit_kmixerVoiceAdd(device,voiceSpecObtained,0),;)
  401.   }
  402.  
  403.  
  404.   device->_magic.num&=U64_MSBC; //set high byte to 0 to indicate success
  405.   _error_: //high byte will remain 0xFF on failure
  406.   if(device!=NULL && device->_magic.num&U64_MSB) kit_kmixerDeviceClose(&device);
  407.   return device; //will be null if DeviceClose is called
  408. }
  409.  
  410.  
  411.  
  412.  
  413. #if defined(_KIT_KMIXER_DEBUG) || defined(_KIT_ALL_DEBUG)
  414. int kit_kmixerDeviceTest(){
  415.   SDL_SetError("not implemented");
  416.   return 0;
  417. }
  418. #else
  419. int kit_kmixerDeviceTest(){
  420.   SDL_SetError("!defined(_KIT_KMIXER_DEBUG)");
  421.   return 999;
  422. }
  423. #endif
  424.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement