Advertisement
Kitomas

kit_sdl2_kmixerAsync.c as of 2023-11-02

Nov 3rd, 2023
715
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 18.24 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){
  9.   if(_userdata != NULL){
  10.     _kit_kmixerAsyncUserdata* userdata = _userdata;
  11.  
  12.     //destroy all of the track mutexes
  13.     _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  14.     Uint32              numTracks = userdata->numTracks;
  15.     for(Uint32 i=0; i<numTracks; ++i){
  16.       if(tracks[i].lock != NULL){
  17.         SDL_DestroyMutex(tracks[i].lock);
  18.         tracks[i].lock = NULL;
  19.       }
  20.     }
  21.  
  22.     //destroy main userdata mutex
  23.     if(userdata->lock != NULL){
  24.       SDL_DestroyMutex(userdata->lock);
  25.       userdata->lock = NULL;
  26.     }
  27.  
  28.     SDL_free(userdata);
  29.   }
  30. }
  31.  
  32.  
  33.  
  34. void _kit_kmixerAsyncTrackCallback(void* userdata, void* _stream, int size, SDL_bool hasInput){
  35.   _kit_kmixerAsyncTrack* track = userdata;
  36.   kit_acodecPCM*           pcm = track->pcm;
  37.  
  38.   SDL_LockMutex(track->lock);
  39.  
  40.   kit_coreMemset(_stream,0,size);
  41.   //if pcm is NULL, the clip has finished playing, and will be deactivated by the main voice
  42.   if(pcm == NULL) goto _exit_early;
  43.   kit_kmixerVoiceSpec* vspec = track->vspec;
  44.  
  45.   //lower volume to 0 within 10ms if speed reaches 0
  46.   #define speed0DeltaVolMS 10.0f
  47.   const float speed0DeltaVol = -( (1000.0f/speed0DeltaVolMS) / vspec->freq);
  48.  
  49.  
  50.   if(track->timeStamp){
  51.     //loops will count down to 0, whereupon the clip will finish (-1 for endless loop)
  52.     track->loops = pcm->loopCount;
  53.  
  54.     //calculate position based on difference between device and clip timestamps
  55.     Uint64  trackTimeStamp = track->timeStamp;
  56.     Uint64 deviceTimeStamp = track->device->_timeStampEnd;
  57.  
  58.     //device->_timeStampEnd is used instead of Start, so the clip's time stamp
  59.      //can be compared to the last time the device callback exited
  60.     double difference = (double)(trackTimeStamp-deviceTimeStamp)/1000;
  61.     difference *= vspec->freq; //convert seconds to samples
  62.     track->position = -(difference*track->speed); //starts playing when position reaches 0
  63.  
  64.     track->timeStamp = 0; //to ensure that this only occurs once per clip queued
  65.   }
  66.  
  67.  
  68.   float        pan = track->pan;
  69.   double  position = track->position;
  70.   float      speed = track->speed;
  71.   Uint16     loops = track->loops;
  72.   Uint16  stopping = track->stopping;
  73.   Uint64 loopStart = pcm->loopStart;
  74.   Uint64   loopEnd = pcm->loopEnd-1;
  75.   //Uint64 src_len = pcm->numSamples; (unnecessary, as loopEnd is used instead)
  76.   Uint16   dst_len = size / (sizeof(float)<<vspec->stereo);
  77.  
  78.   //make sure volume is clamped before applying it to the first sample,
  79.    //since volume is only clamped after deltaVol is applied otherwise
  80.   track->volume.l = CLAMP(track->volume.l, 0.0f,1.0f);
  81.   track->volume.r = CLAMP(track->volume.r, 0.0f,1.0f);
  82.  
  83.  
  84.   if(vspec->stereo){
  85.     kit_acodecPCM_F32S* dst = _stream,  *src = pcm->f32s;
  86.  
  87.     if(track->linear){ //linear resampling
  88.       for(Uint32 i=0; i<dst_len; ++i) _stereo_iteration(_stereo_linear)
  89.     } else { //nearest-neighbor resampling
  90.       for(Uint32 i=0; i<dst_len; ++i) _stereo_iteration(_stereo_nearest)
  91.     }
  92.  
  93.   } else { //mono
  94.     float* dst = _stream,  *src = pcm->f32;
  95.  
  96.     if(track->linear){ //linear resampling
  97.       for(Uint32 i=0; i<dst_len; ++i) _mono_iteration(_mono_linear)
  98.     } else { //nearest-neighbor resampling
  99.       for(Uint32 i=0; i<dst_len; ++i) _mono_iteration(_mono_nearest)
  100.     }
  101.  
  102.   }
  103.  
  104.  
  105.   //update some values
  106.   //track->pcm      = pcm; (unnecessary)
  107.   track->position = position;
  108.   track->speed    = speed;
  109.   track->loops    = loops;
  110.   track->stopping = stopping;
  111.  
  112.   //if the track's stopOnMute condition is met, mark track as finished,
  113.    //so it'll be deactivated until a new clip is queued
  114.   if(!vspec->stereo) track->volume.r = track->volume.l;
  115.   if(track->volume.l<=0 && track->volume.r<=0  && track->stopOnMute)
  116.     track->stopping = SDL_TRUE;
  117.  
  118.   _exit_early:
  119.   SDL_UnlockMutex(track->lock);
  120. }
  121.  
  122.  
  123.  
  124. void _kit_kmixerAsyncVoiceCallback(void* _userdata, void* _stream, int size, SDL_bool hasInput){
  125.   _kit_kmixerAsyncUserdata* userdata = _userdata;
  126.  
  127.   SDL_LockMutex(userdata->lock);
  128.   if(!kit_kmixerAsyncGetActiveTracks(userdata->device, userdata->rawIndex)){
  129.     kit_coreMemset(_stream,0,size);
  130.     goto _exit_early;
  131.   }
  132.  
  133.   float                  pan = userdata->pan;
  134.   kit_kmixerVoiceSpec* vspec = &userdata->vspec;
  135.   Uint16             dst_len = size / (sizeof(float)<<vspec->stereo);
  136.  
  137.   userdata->volume.l = CLAMP(userdata->volume.l, 0.0f,1.0f);
  138.   userdata->volume.r = CLAMP(userdata->volume.r, 0.0f,1.0f);
  139.  
  140.  
  141.   if(vspec->stereo){
  142.     kit_acodecPCM_F32S* dst = _stream;
  143.     for(Uint32 i=0; i<dst_len; ++i){
  144.       kit_acodecPCM_F32S sample = _stereo_volume(dst[i], (void*)userdata);
  145.       dst[i] = _apply_pan(_stereo_clamp(sample), pan);
  146.       _stereo_deltaVol((void*)userdata);
  147.     }
  148.  
  149.   } else { //mono
  150.     float* dst = _stream;
  151.     for(Uint32 i=0; i<dst_len; ++i){
  152.       dst[i] = _mono_clamp(_mono_volume(dst[i], (void*)userdata));
  153.       _mono_deltaVol((void*)userdata);
  154.     }
  155.  
  156.   }
  157.  
  158.  
  159.   SDL_bool* main_active_p = kit_kmixerVoiceGetActiveRef(userdata->device, userdata->rawIndex);
  160.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  161.   Uint32              numTracks = userdata->numTracks;
  162.  
  163.   //force all tracks to deactivate if main voice's stopOnMute condition is met
  164.   if(!vspec->stereo) userdata->volume.r = userdata->volume.l;
  165.   if(userdata->volume.l<=0 && userdata->volume.r<=0  &&  userdata->stopOnMute){
  166.     for(Uint32 ti=0; ti<numTracks; ++ti){
  167.       _kit_kmixerAsyncTrack* track = &tracks[ti];
  168.       _deactivate_track_if(track->pcm!=NULL, track);
  169.     }
  170.     //setting active to false here directly should be safe,
  171.      //since voices are always locked during their callback
  172.     //*main_active_p = SDL_FALSE;
  173.  
  174.   //otherwise, just deactivate the tracks that have finished playing its queued clip
  175.   } else {
  176.     //Uint32 inactiveTracks = 0;
  177.     for(Uint32 ti=0; ti<numTracks; ++ti){
  178.       _kit_kmixerAsyncTrack* track = &tracks[ti];
  179.  
  180.       if(kit_kmixerVoiceExists(track->device, track->rawIndex)<1) continue;
  181.       SDL_bool track_active = kit_kmixerVoiceGetActive(track->device, track->rawIndex);
  182.  
  183.       _deactivate_track_if(track->stopping, track);
  184.       //if(!track_active) ++inactiveTracks;
  185.  
  186.     }
  187.  
  188.     //deactivate main voice if all of its tracks are inactive
  189.     //if(inactiveTracks == numTracks) *main_active_p = SDL_FALSE;
  190.   }
  191.  
  192.   _exit_early:
  193.   SDL_UnlockMutex(userdata->lock);
  194. }
  195.  
  196.  
  197.  
  198.  
  199. Uint32 kit_kmixerAsyncAdd(kit_kmixerDevice* device,
  200.                           SDL_bool linearInterpolation, SDL_bool stereo,
  201.                           Uint32 outputVoiceID, Uint32 numTracks)
  202. {
  203.   Uint32 mainVoiceID = 0; //0 for error by default
  204.   _DEVICE_VALIDITY_CHECK(0)
  205.   _IF_SDLERR(numTracks==0,;,"!numTracks")
  206.   int outputExists = kit_kmixerVoiceExists(device, outputVoiceID);
  207.   _IF_SDLERR(outputExists<0,;,"outputVoiceID out of bounds")
  208.   _IF_SDLERR(!outputExists,;,"output voice doesn't exist")
  209.  
  210.   //create main voice
  211.    //(userdata is contiguous with the track data)
  212.   size_t userdataSize = sizeof(_kit_kmixerAsyncUserdata);
  213.   userdataSize += sizeof(_kit_kmixerAsyncTrack)*numTracks;
  214.  
  215.   kit_kmixerVoiceSpec vspec = kit_kmixerVoiceGetSpec(device,0);
  216.   _IF_GOTO_ERROR(vspec.format==0,;)
  217.  
  218.   vspec.remove   = _kit_kmixerAsyncRemoveCallback;
  219.   vspec.callback = _kit_kmixerAsyncVoiceCallback;
  220.   _IF_GOTO_ERROR(kit_coreRealloc(&vspec.userdata,0,userdataSize),;)
  221.   vspec.stereo   = stereo&1; //stereo is the only non-pointer member that's different
  222.  
  223.   mainVoiceID = kit_kmixerVoiceAdd(device,&vspec,outputVoiceID);
  224.   _IF_GOTO_ERROR(!mainVoiceID, SDL_free(vspec.userdata) )
  225.   kit_kmixerVoiceSetActive(device, mainVoiceID, SDL_TRUE);
  226.  
  227.  
  228.   //fill in userdata
  229.   _kit_kmixerAsyncUserdata* userdata = vspec.userdata;
  230.   userdata->type       = type_UDAT; //U[SER]DAT[A]
  231.   userdata->volume.l   = 1.0f;
  232.   userdata->volume.r   = 1.0f;
  233.   userdata->stopOnMute = SDL_FALSE; //unlike track, main's stopOnMute is false by default
  234.   userdata->rawIndex   = mainVoiceID;
  235.   userdata->device     = device;
  236.   userdata->vspec      = vspec;
  237.   userdata->tracks     = (void*)userdata+sizeof(_kit_kmixerAsyncUserdata);
  238.   userdata->numTracks  = numTracks;
  239.   userdata->lock       = SDL_CreateMutex();
  240.   _IF_GOTO_ERROR(userdata->lock==NULL, kit_kmixerVoiceRemove(device, mainVoiceID) )
  241.  
  242.  
  243.   //create tracks
  244.   vspec.remove   = NULL; //only the main voice should be doing the free()'ing
  245.   vspec.callback = _kit_kmixerAsyncTrackCallback;
  246.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  247.   for(Uint32 ti=0; ti<numTracks; ++ti){
  248.     _kit_kmixerAsyncTrack* track = vspec.userdata = &tracks[ti];
  249.     track->type       = type_TRCK; //TR[A]CK
  250.     track->volume.l   = 1.0f;
  251.     track->volume.r   = 1.0f;
  252.     track->stopOnMute = SDL_TRUE;
  253.     track->rawIndex   = kit_kmixerVoiceAdd(device,&vspec,mainVoiceID);
  254.     track->device     = device;
  255.     track->lock       = SDL_CreateMutex();
  256.     track->vspec      = &userdata->vspec;
  257.     track->linear     = linearInterpolation&1;
  258.     if(!track->rawIndex || track->lock==NULL){
  259.       kit_kmixerVoiceRemove(device, mainVoiceID); return 0;
  260.     }
  261.     kit_kmixerVoiceSetActive(device, track->rawIndex, SDL_TRUE);
  262.   }
  263.  
  264.  
  265.   _noerr_:
  266.   _error_:
  267.   return mainVoiceID;
  268. }
  269.  
  270.  
  271.  
  272. Uint32 kit_kmixerAsyncPlayPVS(kit_kmixerDevice* device, Uint32 voiceID, kit_acodecPCM* pcm,
  273.                               float pan, float volumeL, float volumeR, double speedMultiplier)
  274. {
  275.   Uint64 trackTimeStamp = SDL_GetTicks64();
  276.   Uint32 trackNum = -1; //set to -1 for error by default
  277.   SDL_bool udat_lock = SDL_FALSE,  trck_lock = SDL_FALSE;
  278.   _kit_kmixerAsyncUserdata* userdata = NULL;
  279.   _kit_kmixerAsyncTrack* track = NULL;
  280.  
  281.   _IF_SDLERR(pcm==NULL,;,"!pcm")
  282.   _IF_SDLERR(!NORMALIZED(pan),;,"pan must be -1.0f -> 1.0f")
  283.   _IF_SDLERR(volumeL<0,;,"volumeL < 0")
  284.   _IF_SDLERR(volumeR<0,;,"volumeR < 0")
  285.   _IF_SDLERR(speedMultiplier<=0,;,"speedMultiplier <= 0")
  286.  
  287.   kit_kmixerVoiceSpec vspec = kit_kmixerVoiceGetSpec(device, voiceID);
  288.   _IF_GOTO_ERROR(!vspec.format,;)
  289.   userdata = vspec.userdata;
  290.   _IF_SDLERR(userdata==NULL,;,"invalid async voice")
  291.   _IF_SDLERR(userdata->type!=type_UDAT,;,"invalid async voice")
  292.  
  293.   _IF_SDLERR(pcm->magic!=KPCM_MAGIC,;,"invalid pcm struct")
  294.   _IF_SDLERR(pcm->format!=AUDIO_F32,;,"pcm->format != AUDIO_F32")
  295.   _IF_SDLERR(pcm->loopStart>=pcm->loopEnd,;,"pcm->loopStart >= pcm->loopEnd")
  296.   _IF_SDLERR(pcm->loopEnd>pcm->numSamples,;,"pcm->loopEnd > pcm->numSamples")
  297.   _IF_SDLERR(pcm->numSamples<2,;,"pcm->numSamples < 2")
  298.   _IF_SDLERR(pcm->sampleRate!=vspec.freq,;,"pcm->sampleRate != device freq")
  299.   _IF_SDLERR((pcm->channels-1)!=vspec.stereo,;,"pcm->channels is invalid")
  300.  
  301.  
  302.   //look for empty track to queue pcm clip with
  303. kit_kmixerDeviceLock(device, SDL_TRUE);
  304.   SDL_LockMutex(userdata->lock);  udat_lock = SDL_TRUE;
  305.   Uint32              numTracks = userdata->numTracks;
  306.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  307.  
  308.   for(Uint32 i=0; i<numTracks; ++i){
  309.     track = &tracks[i];
  310.     SDL_LockMutex(track->lock);  trck_lock = SDL_TRUE;
  311.     while(device->_timeStampStart > device->_timeStampEnd) SDL_Delay(1);
  312.     if(!track->stopping && track->pcm==NULL){
  313.       int exists = kit_kmixerVoiceExists(device, track->rawIndex);
  314.       _IF_SDLERR(!exists,;,"track %u's voice doesn't exist",i)
  315.       trackNum = i; break;
  316.     }
  317.  
  318.     SDL_UnlockMutex(track->lock);  trck_lock = SDL_FALSE;
  319.  
  320.   }
  321. kit_kmixerDeviceLock(device, SDL_FALSE);
  322.   SDL_UnlockMutex(userdata->lock);  udat_lock = SDL_FALSE;
  323.   _IF_GOTO(trackNum==-1,_noerr_,;) //exit early if no free track was found
  324.  
  325.  
  326.   //track = &tracks[trackNum]; (track was already set inside the loop)
  327.   track->pan        = pan;
  328.   track->volume.l   = volumeL;
  329.   track->volume.r   = volumeR;
  330.   track->delta.l    = 0.0f;
  331.   track->delta.r    = 0.0f;
  332.   track->stopOnMute = SDL_TRUE;
  333.  
  334.   track->pcm        = pcm;
  335.   track->timeStamp  = trackTimeStamp;
  336.   track->speed      = speedMultiplier;
  337.   track->deltaS     = 0.0;
  338.  
  339.  
  340.   //kit_kmixerVoiceSetActive(device, track->rawIndex, SDL_TRUE);
  341.   //if(!kit_kmixerVoiceGetActive(device, voiceID)) kit_kmixerVoiceSetActive(device, voiceID, SDL_TRUE);
  342.   _noerr_: if(trackNum == -1) trackNum = -2; //-2 for 'no available track found; no error'
  343.   _error_:
  344.   if(udat_lock) SDL_UnlockMutex(userdata->lock);
  345.   if(trck_lock) SDL_UnlockMutex(track->lock);
  346.   return trackNum;
  347. }
  348.  
  349.  
  350.  
  351.  
  352. //returns -1 (U64_MAX) pointer on error
  353. #define UDAT_ERROR ((void*)U64_MAX) //(also used for GetTrack's error)
  354. _kit_kmixerAsyncUserdata* _kit_kmixerAsyncGetUserdata(kit_kmixerDevice* device, Uint32 voiceID){
  355.   kit_kmixerVoiceSpec vspec = kit_kmixerVoiceGetSpec(device, voiceID);
  356.   _IF_GOTO_ERROR(!vspec.format,;)
  357.  
  358.   _kit_kmixerAsyncUserdata* userdata = vspec.userdata;
  359.   _IF_SDLERR(userdata==NULL,;,"invalid async voice")
  360.   _IF_SDLERR(userdata->type!=type_UDAT,;,"invalid async voice")
  361.  
  362.   /*!err*/ return userdata;
  363.   _error_: return UDAT_ERROR; // = (void*)0xffffffffffffffff
  364. }
  365.  
  366.  
  367.  
  368. _kit_kmixerAsyncTrack* _kit_kmixerAsyncGetTrack(kit_kmixerDevice* device,
  369.                                                 _kit_kmixerAsyncUserdata* userdata, Uint32 trackNum)
  370. {
  371.   _IF_SDLERR(trackNum>=userdata->numTracks,;,"trackNum out of bounds")
  372.   _kit_kmixerAsyncTrack* track = &userdata->tracks[trackNum];
  373.  
  374.   int exists = kit_kmixerVoiceExists(device, track->rawIndex);
  375.   _IF_SDLERR(!exists,;,"track %u's voice nonexistent",trackNum)
  376.  
  377.   /*!err*/ return track; //will not error even if no clip is queued (track->pcm = NULL)
  378.   _error_: return UDAT_ERROR; // = (void*)0xffffffffffffffff
  379. }
  380.  
  381.  
  382.  
  383.  
  384. int kit_kmixerAsyncStopTrack(kit_kmixerDevice* device, Uint32 voiceID,
  385.                              Uint32 trackNum)
  386. {
  387.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  388.   _IF_GOTO_ERROR(userdata==UDAT_ERROR,;)
  389.  
  390.  
  391.   _kit_kmixerAsyncTrack* track = _kit_kmixerAsyncGetTrack(device, userdata, trackNum);
  392.   _IF_GOTO_ERROR(track==UDAT_ERROR,;)
  393.   if(track->pcm == NULL) return 1; //already stopped; return a 1
  394.   else track->pcm = NULL;
  395.  
  396.  
  397.   int exists = kit_kmixerVoiceExists(device, track->rawIndex);
  398.   _IF_SDLERR(!exists,;,"track %u's voice nonexistent",trackNum)
  399.  
  400.   //_IF_GOTO_ERROR(kit_kmixerVoiceSetActive(device, track->rawIndex, SDL_FALSE),;)
  401.  
  402.   /*!err*/ return  0;
  403.   _error_: return -1;
  404. }
  405.  
  406.  
  407.  
  408. int kit_kmixerAsyncStopAllTracks(kit_kmixerDevice* device, Uint32 voiceID){
  409.   int returnStatus = -1;
  410.   SDL_bool locked = SDL_FALSE;
  411.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  412.   _IF_GOTO_ERROR(userdata==UDAT_ERROR,;)
  413.   _IF_GOTO_ERROR(kit_kmixerVoiceLock(device, voiceID)<0,;)
  414.   locked = SDL_TRUE;
  415.  
  416.  
  417.   Uint32              numTracks = userdata->numTracks;
  418.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  419.   SDL_bool tracksAlreadyStopped = SDL_TRUE; //set to false if any track was halted
  420.   for(Uint32 i=0; i<numTracks; ++i){
  421.     if(tracks[i].pcm != NULL) tracksAlreadyStopped = SDL_FALSE;
  422.     tracks[i].pcm = NULL;
  423.  
  424.     Uint32 rawIndex = tracks[i].rawIndex;
  425.  
  426.     int exists = kit_kmixerVoiceExists(device, rawIndex);
  427.     _IF_SDLERR(!exists,;,"track %u's voice nonexistent",rawIndex)
  428.  
  429.     //_IF_GOTO_ERROR(kit_kmixerVoiceSetActive(device, rawIndex, SDL_FALSE),;)
  430.   }
  431.  
  432.  
  433.   returnStatus = tracksAlreadyStopped;
  434.  
  435.   _error_:
  436.   if(locked && kit_kmixerVoiceUnlock(device, voiceID)<0) returnStatus = -1;
  437.   return returnStatus;
  438. }
  439.  
  440.  
  441.  
  442.  
  443. Uint32 kit_kmixerAsyncGetActiveTracks(kit_kmixerDevice* device, Uint32 voiceID){
  444.   Uint32 activeTracks = -1; //-1 for error by default
  445.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  446.   _IF_GOTO_ERROR(userdata==UDAT_ERROR,;)
  447.  
  448.  
  449.   activeTracks = 0; //there are no errors past this, so setting to 0 is safe here
  450.   Uint32              numTracks = userdata->numTracks;
  451.   _kit_kmixerAsyncTrack* tracks = userdata->tracks;
  452.   for(Uint32 i=0; i<numTracks; ++i){
  453.     if(tracks[i].pcm != NULL) ++activeTracks;
  454.   }
  455.  
  456.  
  457.   _error_: return activeTracks;
  458. }
  459.  
  460.  
  461.  
  462. Uint32 kit_kmixerAsyncGetNumTracks(kit_kmixerDevice* device, Uint32 voiceID){
  463.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  464.   if(userdata==UDAT_ERROR) return -1;
  465.   else return userdata->numTracks;
  466. }
  467.  
  468.  
  469.  
  470. int kit_kmixerAsyncGetTrackPlayState(kit_kmixerDevice* device, Uint32 voiceID,
  471.                                      Uint32 trackNum)
  472. {
  473.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  474.   _IF_GOTO_ERROR(userdata==UDAT_ERROR,;)
  475.  
  476.   _kit_kmixerAsyncTrack* track = _kit_kmixerAsyncGetTrack(device, userdata, trackNum);
  477.   _IF_GOTO_ERROR(track==UDAT_ERROR,;)
  478.   /*!err*/ return track->pcm != NULL;
  479.   _error_: return -1;
  480. }
  481.  
  482.  
  483.  
  484. double kit_kmixerAsyncGetTrackPosition(kit_kmixerDevice* device, Uint32 voiceID,
  485.                                        Uint32 trackNum)
  486. {
  487.   double position = NAN; //NaN for error by default
  488.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  489.   _IF_GOTO_ERROR(userdata==UDAT_ERROR,;)
  490.  
  491.   _kit_kmixerAsyncTrack* track = _kit_kmixerAsyncGetTrack(device, userdata, trackNum);
  492.   _IF_GOTO_ERROR(track==UDAT_ERROR,;)
  493.  
  494.  
  495.   Sint32 freq = userdata->vspec.freq; //sample rate
  496.   position = track->position*freq; //position, in seconds
  497.  
  498.  
  499.   _error_:
  500.   return position;
  501. }
  502.  
  503.  
  504.  
  505. int kit_kmixerAsyncSetTrackStopOnMute(kit_kmixerDevice* device, Uint32 voiceID,
  506.                                       Uint32 trackNum, SDL_bool stopOnMute)
  507. {
  508.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  509.   _IF_GOTO_ERROR(userdata==UDAT_ERROR,;)
  510.  
  511.   _kit_kmixerAsyncTrack* track = _kit_kmixerAsyncGetTrack(device, userdata, trackNum);
  512.   _IF_GOTO_ERROR(track==UDAT_ERROR,;)
  513.   track->stopOnMute = stopOnMute; //changing stopOnMute doesn't require a lock
  514.  
  515.   /*!err*/ return  0;
  516.   _error_: return -1;
  517. }
  518.  
  519.  
  520.  
  521.  
  522. int kit_kmixerAsyncSetTrackDeltaS(kit_kmixerDevice* device, Uint32 voiceID,
  523.                                   Uint32 trackNum, double deltaS)
  524. {
  525.   _kit_kmixerAsyncUserdata* userdata = _kit_kmixerAsyncGetUserdata(device,voiceID);
  526.   _IF_GOTO_ERROR(userdata==UDAT_ERROR,;)
  527.  
  528.   _kit_kmixerAsyncTrack* track = _kit_kmixerAsyncGetTrack(device, userdata, trackNum);
  529.   _IF_GOTO_ERROR(track==UDAT_ERROR,;)
  530.   track->deltaS = deltaS; //changing deltaS doesn't require a lock
  531.  
  532.   /*!err*/ return  0;
  533.   _error_: return -1;
  534. }
  535.  
  536.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement