Advertisement
Kitomas

_kit_kmixerAsyncPrivate.h as of 2023-10-20

Oct 20th, 2023
737
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.26 KB | None | 0 0
  1. #ifndef _KIT_KMIXERASYNCPRIVATE_H
  2. #define _KIT_KMIXERASYNCPRIVATE_H
  3.  
  4.  
  5. #include "../../include/kit_sdl2/kit_core.h"
  6.  
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10.  
  11.  
  12.  
  13.  
  14. typedef enum _udata_types {
  15.   type_UDAT = 0x54414455, // = "UDAT"
  16.   type_TRCK = 0x4B435254, // = "TRCK"
  17. } _udata_types;
  18.  
  19.  
  20.  
  21.  
  22. typedef struct _kit_kmixerAsyncTrack { //88B
  23.   //type, pan, ..., stopOnMute are identical to that of AsyncUserdata,
  24.    //so they can be casted and used interchangably
  25.   _udata_types         type; // = "TRCK"
  26.   float                 pan; //the current pan of the track; -1.0f -> 1.0f (applied AFTER volume)
  27.   kit_acodecPCM_F32S volume; //left and right channel volumes; 0.0f -> 1.0f (.r ignored if mono)
  28.   kit_acodecPCM_F32S  delta; //determines the rate at which volume changes each sample (.r ignored if mono)
  29.   SDL_bool       stopOnMute; //'deactivate track when volume or speed reaches 0?'
  30.  
  31.   SDL_bool           linear; //use linear interpolation if true, nearest-neighbor if false
  32.   _kit_kmixerVoice*   voice; //a reference to the track's voice
  33.  
  34.   kit_acodecPCM*        pcm; //the actual audio data (this should be NULL if the track is inactive)
  35.   Uint64*   deviceTimeStamp; //a pointer to the device callback's timeStamp (read-only)
  36.   Uint64          timeStamp; //result of SDL_GetTicks64() called at time of queueing an audio clip
  37.   double           position; //sample position, including fraction
  38.   kit_acodecPCM_F32S prevSample; //the value of the previous sample; used for interpolation
  39.  
  40.   float               speed; //what amount to increment position by every sample
  41.   float              deltaS; //what number to apply to speed every sample
  42.  
  43.   Uint32           rawIndex; //the voice's index inside the device's raw voice list
  44.   Uint16              loops; //number of times to loop before deactivating clip (-1 for endless loop)
  45.   Uint16         _padding16;
  46. } _kit_kmixerAsyncTrack;
  47.  
  48.  
  49.  
  50. //this should be contiguous with the AsyncTrack(s)
  51. typedef struct _kit_kmixerAsyncUserdata { //48B
  52.   _udata_types         type; // = "UDAT"
  53.   float                 pan; //the current pan of the main voice; -1.0f -> 1.0f (applied AFTER volume)
  54.   kit_acodecPCM_F32S volume; //left and right channel volumes; 0.0f -> 1.0f (.r ignored if mono)
  55.   kit_acodecPCM_F32S  delta; //determines the rate at which volume changes each sample (.r ignored if mono)
  56.   SDL_bool       stopOnMute; //'stop all tracks when main voice's volume reaches 0?'
  57.  
  58.   Uint32          numTracks; //number of total tracks that can play at once
  59.   _kit_kmixerVoice*   voice; //a reference to the main voice's actual voice struct
  60.  
  61.   _kit_kmixerAsyncTrack* tracks; //array of track structs of length numTracks
  62. } _kit_kmixerAsyncUserdata;
  63.  
  64.  
  65.  
  66.  
  67. /* LOOP CHECK */
  68. #define _mono_0 dst[i] = 0;
  69.  
  70. #define _stereo_0 dst[i].l = 0,  dst[i].r = 0;
  71.  
  72. #define _loop_check(_dst_0) {                                              \
  73.   if(pcm == NULL){ _dst_0; continue; } /*0 for silent sample if inactive*/ \
  74.   if(position >= loopEnd){ /*clip finished loop*/                          \
  75.     if(!loops){ pcm = NULL; _dst_0; continue; } /*mark track as inactive*/ \
  76.     if(loops != -1) --loops; /*decrement loops unless infinite*/           \
  77.     position -= (Uint64)position; /*pos %= 1*/                             \
  78.     position += loopStart; /*new_pos = loopStart + old_pos%1*/             \
  79.   } else if(position<0){ /*clip has yet to play*/                          \
  80.     if(position < -speed){                                                 \
  81.       position += speed; /*step forward position by current speed*/        \
  82.       _dst_0; continue; /*0 for silent sample*/                            \
  83.     } else { /*if position >= -speed, the clip should start next sample*/  \
  84.       position = 1; /*make sure the clip starts at 1*/                     \
  85.       continue;                                                            \
  86.     }                                                                      \
  87.   }                                                                        }
  88.  
  89.  
  90.  
  91. /* SAMPLE */
  92. static inline float _mono_nearest(float* src, double position, float prevSample){
  93.   Uint64 positionRound = (Uint64)(position+0.5);
  94.   if(positionRound >= position) return src[positionRound];
  95.   else                          return prevSample;
  96. }
  97.  
  98. static inline kit_acodecPCM_F32S _stereo_nearest(kit_acodecPCM_F32S* src, double position,
  99.                                                  kit_acodecPCM_F32S prevSample)
  100. {
  101.   Uint64 positionRound = (Uint64)(position+0.5);
  102.   if(positionRound >= position){
  103.     kit_acodecPCM_F32S smp;
  104.     smp.l = src[positionRound].l;
  105.     smp.r = src[positionRound].r;
  106.     return smp;
  107.   } else {
  108.     return prevSample;
  109.   }
  110. }
  111.  
  112.  
  113. static inline float _mono_linear(float* src, double position, float prevSample){
  114.   Uint64 intPosition = (Uint64)position;
  115.   double modPosition = position - intPosition; // = position % 1
  116.  
  117.   //modPosition is used as a percentage value for lerp
  118.   float smpOut = LERP2(prevSample, src[++intPosition], modPosition);
  119.  
  120.   return smpOut;
  121. }
  122.  
  123. static inline kit_acodecPCM_F32S _stereo_linear(kit_acodecPCM_F32S* src, double position,
  124.                                                 kit_acodecPCM_F32S prevSample)
  125. {
  126.   Uint64 intPosition = (Uint64)position;
  127.   double modPosition = position - intPosition; // = position % 1
  128.   kit_acodecPCM_F32S nextSample = src[++intPosition];
  129.  
  130.   //modPosition is used as a percentage value for lerp
  131.   kit_acodecPCM_F32S smpOut;
  132.   smpOut.l = LERP2(prevSample.l, nextSample.l, modPosition);
  133.   smpOut.r = LERP2(prevSample.r, nextSample.r, modPosition);
  134.  
  135.   return smpOut;
  136. }
  137.  
  138.  
  139.  
  140. /* VOLUME */
  141. static inline float _mono_volume(float sample, _kit_kmixerAsyncTrack* track){
  142.   return sample * track->volume.l;
  143. }
  144.  
  145. static inline kit_acodecPCM_F32S _stereo_volume(kit_acodecPCM_F32S sample,
  146.                                                 _kit_kmixerAsyncTrack* track)
  147. {
  148.   sample.l *= track->volume.l;
  149.   sample.r *= track->volume.r;
  150.   return sample;
  151. }
  152.  
  153.  
  154.  
  155. /* CLAMP */
  156. static inline float _mono_clamp(float sample){
  157.   return CLAMP(sample, -1.0f,1.0f);
  158. }
  159.  
  160. static inline kit_acodecPCM_F32S _stereo_clamp(kit_acodecPCM_F32S sample){
  161.   sample.l = CLAMP(sample.l, -1.0f,1.0f);
  162.   sample.r = CLAMP(sample.r, -1.0f,1.0f);
  163.   return sample;
  164. }
  165.  
  166.  
  167.  
  168. /* PAN */
  169. static inline kit_acodecPCM_F32S _apply_pan(kit_acodecPCM_F32S smp, float pan){
  170.   //(i think this is how audacity does it...)
  171.   pan = CLAMP(pan, -1.0f,1.0f);
  172.   if(pan < 0){
  173.     smp.l += smp.r*(-pan);
  174.     smp.r *= 1.0f+pan;
  175.   } else if(pan > 0){
  176.     smp.r += smp.l*pan;
  177.     smp.l *= 1.0f-pan;
  178.   }
  179.   return smp;
  180. }
  181.  
  182.  
  183.  
  184. /* DELTAVOL */
  185. static inline void _mono_deltaVol(_kit_kmixerAsyncTrack* track){
  186.   track->volume.l += track->delta.l;
  187.   track->volume.l  = CLAMP(track->volume.l, 0.0f,1.0f);
  188. }
  189.  
  190. static inline void _stereo_deltaVol(_kit_kmixerAsyncTrack* track){
  191.   _mono_deltaVol(track); //for volume.l and delta.l
  192.   track->volume.r += track->delta.r;
  193.   track->volume.r  = CLAMP(track->volume.r, 0.0f,1.0f);
  194. }
  195.  
  196.  
  197.  
  198. /* SPEED */ //(using a define for this is unnecessary)
  199. //#define _apply_speed position += speed;
  200.  
  201.  
  202.  
  203. /* DELTAS */ //(using a define for this is unnecessary)
  204. //#define _apply_deltaS speed = MAX(speed+track->deltaS,0);
  205.  
  206.  
  207.  
  208. /* LOOP FLOW */
  209. /* loop flow order:
  210.     _loop_check(_<m/s>_0)
  211.     _<m/s>_<nearest,linear>()
  212.     _<m/s>_volume()
  213.     _<m/s>_clamp()
  214.     _apply_pan() (stereo only!)
  215.     prevSample = src[(Uint64)position]
  216.     _<m/s>_deltaVol(track)
  217.     position += speed;
  218.     speed += track->deltaS;
  219.     if(speed < 0) speed = 0;
  220.     (repeat) */
  221.  
  222. #define _stereo_iteration(_interpolation_mode) {                            \
  223.   _loop_check(_stereo_0)                                                    \
  224.   kit_acodecPCM_F32S sample = _interpolation_mode(src,position,prevSample); \
  225.   sample = _stereo_clamp(_stereo_volume(sample,track));                     \
  226.   dst[i] = _apply_pan(sample,pan);                                          \
  227.   prevSample = src[(Uint64)position];                                       \
  228.   _stereo_deltaVol(track);                                                  \
  229.   position += speed;                                                        \
  230.   speed += track->deltaS;                                                   \
  231.   if(speed < 0) speed = 0;                                                  }
  232.  
  233. #define _mono_iteration(_interpolation_mode) {                 \
  234.   _loop_check(_mono_0)                                         \
  235.   float sample = _interpolation_mode(src,position,prevSample); \
  236.   dst[i] = _mono_clamp(_mono_volume(sample,track));            \
  237.   prevSample = src[(Uint64)position];                          \
  238.   _mono_deltaVol(track);                                       \
  239.   position += speed;                                           \
  240.   speed += track->deltaS;                                      \
  241.   if(speed < 0) speed = 0;                                     }
  242.  
  243.  
  244.  
  245.  
  246. static inline void _deactivate_track_if(int condition, _kit_kmixerAsyncTrack* track){
  247.   if(condition){
  248.     track->pcm = NULL;
  249.     _kit_kmixerVoice* voice = track->voice;
  250.     if(voice==NULL || voice->lock==NULL) return;
  251.     kit_kmixerVoiceSetActive(voice->device, voice->index, SDL_FALSE);
  252.   }
  253. }
  254.  
  255.  
  256.  
  257.  
  258. #ifdef __cplusplus
  259. }
  260. #endif
  261.  
  262. #endif /* _KIT_KMIXERASYNCPRIVATE_H */
  263.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement