Advertisement
Kitomas

kit_sdl2_kmixerAsync.c as of 2023-10-27

Oct 27th, 2023
705
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.13 KB | None | 0 0
  1. #include "../include/kit_sdl2/kit_kmixer.h"
  2. #include "../_private/include/_kit_privmacro.h"
  3. #include "../_private/include/_kit_kmixerAllPrivate.h"
  4.  
  5.  
  6.  
  7.  
  8. void _kit_kmixerAsyncRemoveCallback(void* userdata){  if(userdata != NULL) SDL_free(userdata);  }
  9.  
  10.  
  11.  
  12. void _kit_kmixerAsyncTrackCallback(void* userdata, void* _stream, int size, SDL_bool hasInput){
  13.   _kit_kmixerAsyncTrack* track = userdata;
  14.   kit_acodecPCM*           pcm = track->pcm;
  15.  
  16.   kit_coreMemset(_stream,0,size);
  17.   //if pcm is NULL, the clip has finished playing, and will be deactivated by the main voice
  18.   if(pcm == NULL) return;
  19.   kit_kmixerVoiceSpec vspec = track->voice->spec; //make copy of voice spec
  20.  
  21.   //lower volume to 0 within 10ms if speed reaches 0
  22.   #define speed0DeltaVolMS 10.0f
  23.   const float speed0DeltaVol = -( (1000.0f/speed0DeltaVolMS) / vspec.freq);
  24.  
  25.  
  26.   if(track->timeStamp){
  27.     //loops will count down to 0, whereupon the clip will finish (-1 for endless loop)
  28.     track->loops = pcm->loopCount;
  29.  
  30.     //calculate position based on difference between device and clip timestamps
  31.     Uint64  trackTimeStamp = track->timeStamp;
  32.     Uint64 deviceTimeStamp = *track->deviceTimeStamp; // = device->_timeStampEnd
  33.  
  34.     //device->_timeStampEnd is used instead of Start, so the clip's time stamp
  35.      //can be compared to the last time the device callback exited
  36.     double difference = (double)(trackTimeStamp-deviceTimeStamp)/1000;
  37.     difference *= vspec.freq; //convert seconds to samples
  38.     track->position = -(difference*track->speed); //starts playing when position reaches 0
  39.  
  40.     track->timeStamp = 0; //to ensure that this only occurs once per clip queued
  41.   }
  42.  
  43.  
  44.   float        pan = track->pan;
  45.   double  position = track->position;
  46.   float      speed = track->speed;
  47.   Uint16     loops = track->loops;
  48.   Uint64 loopStart = pcm->loopStart;
  49.   Uint64   loopEnd = pcm->loopEnd-1;
  50.   //Uint64 src_len = pcm->numSamples; (unnecessary, as loopEnd is used instead)
  51.   Uint16   dst_len = size / (sizeof(float)<<vspec.stereo);
  52.  
  53.  
  54.   if(vspec.stereo){
  55.     kit_acodecPCM_F32S* dst = _stream,  *src = pcm->f32s;
  56.  
  57.     if(track->linear){ //linear resampling
  58.       for(Uint32 i=0; i<dst_len; ++i) _stereo_iteration(_stereo_linear)
  59.     } else { //nearest-neighbor resampling
  60.       for(Uint32 i=0; i<dst_len; ++i) _stereo_iteration(_stereo_nearest)
  61.     }
  62.  
  63.   } else { //mono
  64.     float* dst = _stream,  *src = pcm->f32;
  65.  
  66.     if(track->linear){ //linear resampling
  67.       for(Uint32 i=0; i<dst_len; ++i) _mono_iteration(_mono_linear)
  68.     } else { //nearest-neighbor resampling
  69.       for(Uint32 i=0; i<dst_len; ++i) _mono_iteration(_mono_nearest)
  70.     }
  71.  
  72.   }
  73.  
  74.  
  75.   //update some values
  76.   track->pcm       = pcm; //will either set track->pcm to itself, or NULL
  77.   track->position  = position;
  78.   track->speed     = speed;
  79.   track->loops     = loops;
  80.  
  81.   //if the track's stopOnMute condition is met, mark track as finished,
  82.    //so it'll be deactivated until a new clip is queued
  83.   if(!vspec.stereo) track->volume.r = track->volume.l;
  84.   if(track->volume.l<=0 && track->volume.r<=0  && track->stopOnMute) track->pcm = NULL;
  85. }
  86.  
  87.  
  88.  
  89. void _kit_kmixerAsyncVoiceCallback(void* _userdata, void* _stream, int size, SDL_bool hasInput){
  90.   _kit_kmixerAsyncUserdata* userdata = _userdata;
  91.  
  92.   float       pan = userdata->pan;
  93.   SDL_bool stereo = userdata->voice->spec.stereo;
  94.   Uint16  dst_len = size / (sizeof(float)<<stereo);
  95.  
  96.  
  97.   if(stereo){
  98.     kit_acodecPCM_F32S* dst = _stream;
  99.     for(Uint32 i=0; i<dst_len; ++i){
  100.       kit_acodecPCM_F32S sample = _stereo_volume(dst[i], (void*)userdata);
  101.       dst[i] = _apply_pan(_stereo_clamp(sample), pan);
  102.       _stereo_deltaVol((void*)userdata);
  103.     }
  104.  
  105.   } else { //mono
  106.     float* dst = _stream;
  107.     for(Uint32 i=0; i<dst_len; ++i){
  108.       dst[i] = _mono_clamp(_mono_volume(dst[i],(void*)userdata));
  109.       _mono_deltaVol((void*)userdata);
  110.     }
  111.  
  112.   }
  113.  
  114.  
  115.   Uint32              numTracks = userdata->numTracks;
  116.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  117.   //deactivate all active tracks if main voice stopOnMute condition is met
  118.   if(!stereo) userdata->volume.r = userdata->volume.l;
  119.   if(userdata->volume.l<=0 && userdata->volume.r<=0  &&  userdata->stopOnMute){
  120.     for(Uint32 ti=0; ti<numTracks; ++ti){
  121.       _kit_kmixerAsyncTrack* track = &tracks[ti];
  122.       _deactivate_track_if(track->pcm!=NULL, track);
  123.     }
  124.  
  125.   //otherwise, just deactivate the tracks that have finished playing its queued clip
  126.   } else {
  127.     for(Uint32 ti=0; ti<numTracks; ++ti){
  128.       _kit_kmixerAsyncTrack* track = &tracks[ti];
  129.       _kit_kmixerVoice* voice = track->voice;
  130.       if(voice == NULL) return;
  131.       if(voice->lock == NULL) return;
  132.       _deactivate_track_if(track->pcm==NULL && voice->active, track);
  133.     }
  134.  
  135.   }
  136. }
  137.  
  138.  
  139.  
  140.  
  141. Uint32 kit_kmixerAsyncAdd(kit_kmixerDevice* device,
  142.                           SDL_bool linearInterpolation, SDL_bool stereo,
  143.                           Uint32 outputVoiceID, Uint32 numTracks)
  144. {
  145.   Uint32 mainVoiceID = 0; //0 for error by default
  146.   _DEVICE_VALIDITY_CHECK(0)
  147.   _IF_SDLERR(outputVoiceID>=device->_raw->x,;,"outputVoiceID out of bounds")
  148.   _IF_SDLERR(numTracks==0,;,"!numTracks")
  149.   kit_coreVector** raw_p = &device->_raw;
  150.  
  151.   size_t userdataSize = sizeof(_kit_kmixerAsyncUserdata);
  152.   userdataSize += sizeof(_kit_kmixerAsyncTrack)*numTracks;
  153.  
  154.   //create main voice
  155.   kit_kmixerVoiceSpec vspec = VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, 0).spec;
  156.   vspec.remove   = _kit_kmixerAsyncRemoveCallback;
  157.   vspec.callback = _kit_kmixerAsyncVoiceCallback;
  158.   _IF_GOTO_ERROR(kit_coreRealloc(&vspec.userdata,0,userdataSize),;)
  159.   vspec.stereo   = stereo&1;
  160.  
  161.   mainVoiceID = kit_kmixerVoiceAdd(device,&vspec,outputVoiceID);
  162.   _IF_GOTO_ERROR(!mainVoiceID, SDL_free(vspec.userdata) )
  163.   VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, mainVoiceID).active = SDL_FALSE;
  164.  
  165.  
  166.   //fill in userdata
  167.   _kit_kmixerAsyncUserdata* userdata = vspec.userdata;
  168.   userdata->type      = type_UDAT; //U[SER]DAT[A]
  169.   userdata->volume.l  = 1.0f;
  170.   userdata->volume.r  = 1.0f;
  171.   userdata->numTracks = numTracks;
  172.   userdata->voice     = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, mainVoiceID);
  173.   userdata->tracks    = (void*)userdata+sizeof(_kit_kmixerAsyncUserdata);
  174.  
  175.  
  176.   //create tracks
  177.   vspec.remove   = NULL; //only the main voice should be doing the free()'ing
  178.   vspec.callback = _kit_kmixerAsyncTrackCallback;
  179.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  180.   for(Uint32 ti=0; ti<numTracks; ++ti){
  181.     _kit_kmixerAsyncTrack* track = vspec.userdata = &tracks[ti];
  182.     track->type            = type_TRCK; //TR[A]CK
  183.     track->volume.l        = 1.0f;
  184.     track->volume.r        = 1.0f;
  185.     track->linear          = linearInterpolation&1;
  186.     track->deviceTimeStamp = &device->_timeStampEnd;
  187.     track->rawIndex        = kit_kmixerVoiceAdd(device,&vspec,mainVoiceID);
  188.     if(!track->rawIndex){ kit_kmixerVoiceRemove(device, mainVoiceID); return 0; }
  189.     track->voice = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, track->rawIndex);
  190.     kit_kmixerVoiceSetActive(device, track->rawIndex, SDL_FALSE);
  191.   }
  192.  
  193.  
  194.   _noerr_:
  195.   _error_:
  196.   return mainVoiceID;
  197. }
  198.  
  199.  
  200.  
  201.  
  202. _kit_kmixerAsyncUserdata* _kit_kmixerAsyncGetUserdata(kit_kmixerDevice* device, Uint32 voiceID){
  203.   _DEVICE_VALIDITY_CHECK(0)
  204.   _IF_SDLERR(voiceID>=device->_raw->x,;,"voiceID out of bounds")
  205.  
  206.   kit_coreVector** raw_p = &device->_raw;
  207.   _kit_kmixerVoice* voice = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, voiceID);
  208.   _IF_SDLERR(voice->lock==NULL,;,"voice does not exist")
  209.  
  210.   _kit_kmixerAsyncUserdata* userdata = voice->spec.userdata;
  211.   _IF_SDLERR(userdata==NULL,;,"invalid async voice")
  212.   _IF_SDLERR(userdata->type!=type_UDAT,;,"invalid async voice")
  213.  
  214.   _noerr_: return userdata;
  215.   _error_: return NULL;
  216. }
  217.  
  218.  
  219.  
  220. _kit_kmixerAsyncTrack* _kit_kmixerAsyncGetTrack(_kit_kmixerAsyncUserdata* userdata, Uint32 trackNum){
  221.   _IF_SDLERR(trackNum>=userdata->numTracks,;,"trackNum out of bounds")
  222.   _kit_kmixerAsyncTrack* track = &userdata->tracks[trackNum];
  223.   _IF_SDLERR(track->pcm==NULL,;,"no clip queued in track")
  224.  
  225.   /*!err*/ return track;
  226.   _error_: return NULL;
  227. }
  228.  
  229.  
  230.  
  231.  
  232. Uint32 kit_kmixerAsyncPlayPVS(kit_kmixerDevice* device, Uint32 voiceID, kit_acodecPCM* pcm,
  233.                               float pan, float volumeL, float volumeR, double speedMultiplier)
  234. {
  235.   Uint64 trackTimeStamp = SDL_GetTicks64();
  236.   Uint32 trackNum = -1; //set to -1 for error by default
  237.   _IF_SDLERR(pcm==NULL,;,"!pcm")
  238.   _IF_SDLERR(!NORMALIZED(pan),;,"pan must be -1.0f -> 1.0f")
  239.   _IF_SDLERR(volumeL<0,;,"volumeL < 0")
  240.   _IF_SDLERR(volumeR<0,;,"volumeR < 0")
  241.   _IF_SDLERR(speedMultiplier<=0,;,"speedMultiplier <= 0")
  242.  
  243.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  244.   _IF_GOTO_ERROR(userdata==NULL,;)
  245.   kit_kmixerVoiceSpec* vspec = &userdata->voice->spec;
  246.  
  247.   _IF_SDLERR(pcm->magic!=KPCM_MAGIC,;,"invalid pcm struct")
  248.   _IF_SDLERR(pcm->format!=AUDIO_F32,;,"pcm->format != AUDIO_F32")
  249.   _IF_SDLERR(pcm->loopStart>=pcm->loopEnd,;,"pcm->loopStart >= pcm->loopEnd")
  250.   _IF_SDLERR(pcm->loopEnd>pcm->numSamples,;,"pcm->loopEnd > pcm->numSamples")
  251.   _IF_SDLERR(pcm->numSamples<2,;,"pcm->numSamples < 2")
  252.   _IF_SDLERR(pcm->sampleRate!=vspec->freq,;,"pcm->sampleRate != device freq")
  253.   _IF_SDLERR((pcm->channels-1)!=vspec->stereo,;,"pcm->channels is invalid")
  254.  
  255.  
  256.   //look for empty track to queue pcm clip with
  257.   Uint32              numTracks = userdata->numTracks;
  258.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  259.   for(Uint32 i=0; i<numTracks; ++i){
  260.     if(tracks[i].pcm == NULL){ trackNum = i; break; }
  261.   }
  262.   _IF_GOTO(trackNum==-1,_noerr_,;) //exit early if no free track was found
  263.  
  264.  
  265.   _kit_kmixerAsyncTrack* track = &tracks[trackNum];
  266.   track->pan        = pan;
  267.   track->volume.l   = volumeL;
  268.   track->volume.r   = volumeR;
  269.   track->delta.l    = 0.0f;
  270.   track->delta.r    = 0.0f;
  271.   track->stopOnMute = SDL_TRUE;
  272.  
  273.   track->pcm        = pcm;
  274.   track->timeStamp  = trackTimeStamp;
  275.   track->speed      = speedMultiplier;
  276.   track->deltaS     = 0.0;
  277.  
  278.  
  279.   kit_kmixerVoiceSetActive(device, track->rawIndex, SDL_TRUE);
  280.   if(!kit_kmixerVoiceGetActive(device, voiceID)) kit_kmixerVoiceSetActive(device, voiceID, SDL_TRUE);
  281.   _noerr_: if(trackNum == -1) trackNum = -2; //-2 for 'no available track found; no error'
  282.   _error_: return trackNum;
  283. }
  284.  
  285.  
  286.  
  287. int kit_kmixerAsyncStopTrack(kit_kmixerDevice* device, Uint32 voiceID,
  288.                              Uint32 trackNum)
  289. {
  290.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  291.   _IF_GOTO_ERROR(userdata==NULL,;)
  292.  
  293.  
  294.   _IF_SDLERR(trackNum>=userdata->numTracks,;,"trackNum out of bounds")
  295.   _kit_kmixerAsyncTrack* track = &userdata->tracks[trackNum];
  296.   if(track->pcm == NULL) return 1;
  297.   else track->pcm = NULL;
  298.  
  299.  
  300.   _kit_kmixerVoice* trackVoice = track->voice;
  301.   _IF_SDLERR(trackVoice->lock==NULL,;,"track's voice doesn't exist")
  302.   _IF_GOTO_ERROR(SDL_LockMutex(trackVoice->lock),;)
  303.  
  304.   trackVoice->active = SDL_FALSE;
  305.  
  306.   _IF_GOTO_ERROR(SDL_UnlockMutex(trackVoice->lock),;)
  307.  
  308.   /*!err*/ return  0;
  309.   _error_: return -1;
  310. }
  311.  
  312.  
  313.  
  314. int kit_kmixerAsyncStopAllTracks(kit_kmixerDevice* device, Uint32 voiceID){
  315.   int returnStatus = 0;
  316.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  317.   _IF_GOTO_ERROR(userdata==NULL, returnStatus=-1)
  318.  
  319.  
  320.   Uint32 numTracks = userdata->numTracks;
  321.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  322.  
  323.   for(Uint32 i=0; i<numTracks; ++i){
  324.     tracks[i].pcm = NULL;
  325.     _kit_kmixerVoice* trackVoice = tracks[i].voice;
  326.     _IF_SDLERR(trackVoice->lock==NULL, returnStatus=-1,
  327.                "track %u's voice doesn't exist",i)
  328.  
  329.     if(SDL_LockMutex(trackVoice->lock)){ returnStatus = -1; continue; }
  330.     trackVoice->active = SDL_FALSE;
  331.     if(SDL_UnlockMutex(trackVoice->lock)) returnStatus = -1;
  332.  
  333.   }
  334.  
  335.  
  336.   _error_:
  337.   return returnStatus;
  338. }
  339.  
  340.  
  341.  
  342.  
  343. Uint32 kit_kmixerAsyncGetActiveTracks(kit_kmixerDevice* device, Uint32 voiceID){
  344.   Uint32 activeTracks = -1; //-1 for error by default
  345.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  346.   _IF_GOTO_ERROR(userdata==NULL,;)
  347.  
  348.  
  349.   activeTracks = 0; //there are no errors past this, so setting to 0 is safe here
  350.   Uint32              numTracks = userdata->numTracks;
  351.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  352.   for(Uint32 i=0; i<numTracks; ++i){
  353.     if(tracks[i].pcm != NULL) ++activeTracks;
  354.   }
  355.  
  356.  
  357.   _error_: return activeTracks;
  358. }
  359.  
  360.  
  361.  
  362. Uint32 kit_kmixerAsyncGetNumTracks(kit_kmixerDevice* device, Uint32 voiceID){
  363.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  364.  
  365.   if(userdata==NULL) return -1;
  366.   else return userdata->numTracks;
  367. }
  368.  
  369.  
  370.  
  371. int kit_kmixerAsyncGetTrackPlayState(kit_kmixerDevice* device, Uint32 voiceID,
  372.                                      Uint32 trackNum)
  373. {
  374.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  375.   _IF_GOTO_ERROR(userdata==NULL,;)
  376.  
  377.   _IF_SDLERR(trackNum>=userdata->numTracks,;,"trackNum out of bounds")
  378.   /*!err*/ return userdata->tracks[trackNum].pcm != NULL;
  379.   _error_: return -1;
  380. }
  381.  
  382.  
  383.  
  384. double kit_kmixerAsyncGetTrackPosition(kit_kmixerDevice* device, Uint32 voiceID,
  385.                                        Uint32 trackNum)
  386. {
  387.   double position = NAN; //NaN for error by default
  388.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  389.   _IF_GOTO_ERROR(userdata==NULL,;)
  390.  
  391.   _kit_kmixerAsyncTrack* track = _kit_kmixerAsyncGetTrack(userdata, trackNum);
  392.   _IF_GOTO_ERROR(track==NULL,;)
  393.  
  394.   _kit_kmixerVoice* trackVoice = track->voice;
  395.   _IF_SDLERR(trackVoice->lock==NULL,;,"track's voice doesn't exist")
  396.  
  397.  
  398.   Sint32 freq = trackVoice->spec.freq; //sample rate
  399.   position = track->position*freq; //position, in seconds
  400.  
  401.  
  402.   _error_:
  403.   return position;
  404. }
  405.  
  406.  
  407.  
  408.  
  409. int kit_kmixerAsyncSetTrackDeltaS(kit_kmixerDevice* device, Uint32 voiceID,
  410.                                   Uint32 trackNum, double deltaS)
  411. {
  412.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  413.   _IF_GOTO_ERROR(userdata==NULL,;)
  414.  
  415.   _kit_kmixerAsyncTrack* track = _kit_kmixerAsyncGetTrack(userdata, trackNum);
  416.   _IF_GOTO_ERROR(track==NULL,;)
  417.   track->deltaS = deltaS; //changing deltaS doesn't require a lock
  418.  
  419.   /*!err*/ return  0;
  420.   _error_: return -1;
  421. }
  422.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement