Advertisement
Kitomas

kit_sdl2_kmixerVoice as of 2023-11-02

Nov 3rd, 2023 (edited)
666
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 42.21 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. /* example of simd stereo to mono without sse3's hadd
  6. static inline void _sse1_s_to_m(float* dst, __m128 vector){
  7.   __m128 shuffled = _mm_shuffle_ps(vector,vector, _MM_SHUFFLE(2,3,0,1));
  8.   __m128 sum = _mm_add_ps(vector,shuffled);
  9.   __m128 result = _mm_shuffle_ps(sum,sum, _MM_SHUFFLE(3,1,2,0));
  10.   _mm_storel_pi((__m64*)dst,result);
  11. }
  12. */
  13.  
  14.  
  15. //for visual clarity during ProcChannels
  16.  //(this could also just be an enum probably, but w/e)
  17. #define _M_to_M (0) //  mono->mono
  18. #define _M_to_S (1) //  mono->stereo
  19. #define _S_to_M (2) //stereo->mono
  20. #define _S_to_S (3) //stereo->stereo
  21. /* i think i need to fix this
  22. #define _MM256_SHUFFLE(c7,c6,c5,c4,c3,c2,c1,c0) \
  23.   ((_MM_SHUFFLE(c7,c6,c5,c4)<<8)|_MM_SHUFFLE(c3,c2,c1,c0)) */
  24.  
  25.  
  26.  
  27. //converts u8, i16, and i32 samples to f32 samples
  28.  //(will basically just copy input to output if input is also f32)
  29. static inline void _kit_kmixerVoiceProcFromTypeFallback(void* _dataIn, float* dataOut,
  30.                                                         Uint32 numSamples, SDL_AudioFormat typeIn)
  31. { //if nothing else works
  32.   kit_acodecPCMSamples dataIn = { .data = _dataIn };
  33.   float rawSample; //used for max(original_sample,-1) basically
  34.   switch(typeIn){
  35.   case AUDIO_U8 : for(Uint32 i=0; i<numSamples; ++i){ rawSample = (float)(dataIn.u_8[i]-0x80)*inv_i_8;
  36.                                                       dataOut[i] = (rawSample>=-1.0f)?rawSample:-1.0f; } break;
  37.   case AUDIO_S16: for(Uint32 i=0; i<numSamples; ++i){ rawSample = (float) dataIn.i16[i]      *inv_i16;
  38.                                                       dataOut[i] = (rawSample>=-1.0f)?rawSample:-1.0f; } break;
  39.   case AUDIO_S32: for(Uint32 i=0; i<numSamples; ++i){ rawSample = (float) dataIn.i32[i]      *inv_i32;
  40.                                                       dataOut[i] = (rawSample>=-1.0f)?rawSample:-1.0f; } break;
  41.   case AUDIO_F32: for(Uint32 i=0; i<numSamples; ++i){ dataOut[i] =        dataIn.f32[i];               } }
  42. }
  43. void _kit_kmixerVoiceProcFromType(void* dataIn, void* dataOut,
  44.                                   Uint32 sampleFrames, SDL_AudioFormat typeIn, SDL_bool isStereo)
  45. {
  46.   Uint32 numSamples = sampleFrames<<isStereo;
  47.   _kit_kmixerVoiceProcFromTypeFallback(dataIn,dataOut,numSamples,typeIn);
  48. }
  49.  
  50.  
  51.  
  52.  
  53. //converts f32 samples to u8, i16, and i32 samples
  54. static inline void _kit_kmixerVoiceProcToTypeFallback(float* dataIn, void* _dataOut,
  55.                                                       Uint32 numSamples, SDL_AudioFormat typeOut)
  56. { //if nothing else works
  57.   kit_acodecPCMSamples dataOut = { .data = _dataOut };
  58.   float rawSample, rawSampleB;
  59.   switch(typeOut){
  60.   case AUDIO_U8 : for(Uint32 i=0; i<numSamples; ++i){ rawSample      = dataIn[i];
  61.                                                       rawSampleB     = (rawSample>=-1.0f)?rawSample:-1.0f;
  62.                                                       dataOut.u_8[i] = (rawSampleB<=1.0f)?rawSampleB*I_8_MAX+0x80:I_8_MAX; } break;
  63.   case AUDIO_S16: for(Uint32 i=0; i<numSamples; ++i){ rawSample      = dataIn[i];
  64.                                                       rawSampleB     = (rawSample>=-1.0f)?rawSample:-1.0f;
  65.                                                       dataOut.i16[i] = (rawSampleB<=1.0f)?rawSampleB*I16_MAX:I16_MAX; } break;
  66.   case AUDIO_S32: for(Uint32 i=0; i<numSamples; ++i){ rawSample      = dataIn[i];
  67.                                                       rawSampleB     = (rawSample>=-1.0f)?rawSample:-1.0f;
  68.                                                       dataOut.i32[i] = (rawSampleB<=1.0f)?rawSampleB*I32_MAX:I32_MAX; } break;
  69.   case AUDIO_F32: for(Uint32 i=0; i<numSamples; ++i){ rawSample      = dataIn[i];
  70.                                                       rawSampleB     = (rawSample>=-1.0f)?rawSample:-1.0f;
  71.                                                       dataOut.f32[i] = (rawSampleB<=1.0f)?rawSampleB:1.0f; } }
  72. }
  73. void _kit_kmixerVoiceProcToType(void* dataIn, void* dataOut,
  74.                                 Uint32 sampleFrames, SDL_AudioFormat typeOut, SDL_bool isStereo)
  75. {
  76.   Uint32 numSamples = sampleFrames<<isStereo;
  77.   _kit_kmixerVoiceProcToTypeFallback(dataIn,dataOut,numSamples,typeOut);
  78. }
  79.  
  80.  
  81.  
  82.  
  83. //assumes samples are f32
  84. static inline void _kit_kmixerVoiceProcChannelsFallback(float* dataInM, float* dataOutM,
  85.                                                         Uint32 sampleFrames, int channelInfo)
  86. { //if nothing else works
  87.   kit_acodecPCM_F32S* dataInS  = (void*)dataInM;
  88.   kit_acodecPCM_F32S* dataOutS = (void*)dataOutM;
  89.   switch(channelInfo){
  90.   case _M_to_S: for(Uint32 i=0; i<sampleFrames; ++i){ dataOutS[i].l=dataOutS[i].r = dataInM[i]; } break;
  91.   case _S_to_M: for(Uint32 i=0; i<sampleFrames; ++i){ dataOutM[i] = (dataInS[i].l+dataInS[i].r)*0.5f; } break;
  92.   case _S_to_S: sampleFrames<<=1; SDL_FALLTHROUGH; //multiply mono by 2 to make length of stereo
  93.   case _M_to_M: for(Uint32 i=0; i<sampleFrames; ++i){ dataOutM[i] = dataInM[i]; }
  94.   }
  95. }
  96. void _kit_kmixerVoiceProcChannels(void* dataIn, void* dataOut, Uint32 sampleFrames, int channelInfo){
  97.   _kit_kmixerVoiceProcChannelsFallback(dataIn,dataOut, sampleFrames,channelInfo);
  98. }
  99.  
  100.  
  101.  
  102.  
  103. #define _CH_INFO(a,b) (((a)<<1)|(b))
  104. //assumes input AND output samples are f32 (intermediate type is determined by the given voice)
  105. int _kit_kmixerVoiceProc(void* data){ //(this is an SDL_ThreadFunction)
  106.   _kit_kmixerVoice* voice = data;
  107.   if(voice == NULL) return 1; //skip if voice is NULL
  108.   if(voice->lock == NULL) return 2; //skip if voice was removed
  109.   if(voice->output == U32_MAX) return 3; //skip if voice is voice 0
  110.   SDL_LockMutex(voice->lock);
  111.  
  112.  
  113.   void *ibuffer  = voice->bufferInput.data,  *obuffer = voice->bufferOutput.data;
  114.   void *ubuffer  = voice->bufferUser.data,   *cbuffer = voice->bufferConvert.data;
  115.   void *userdata = voice->spec.userdata,  *_stream = ubuffer;
  116.    ///
  117.   SDL_bool hasInput = voice->inputs!=NULL;
  118.   SDL_bool ustereo  = voice->spec.stereo;
  119.   SDL_bool ostereo  = voice->stereoOutput;
  120.    ///
  121.   SDL_AudioFormat uformat = voice->spec.format;
  122.   Uint32           frames = voice->spec.samples;
  123.   Uint32     ubuffer_size = voice->spec._size;
  124.  
  125.  
  126.   //convert (if necessary) input type (format) from f32
  127.   int userTypeIsF32 = uformat==AUDIO_F32;
  128.   if(userTypeIsF32) _stream = ibuffer; //input and user are identical; just reroute
  129.   else _kit_kmixerVoiceProcToType(ibuffer, ubuffer, frames,uformat,ustereo);
  130.  
  131.  
  132.   //the actual user callback
  133.   voice->spec.callback(userdata, _stream, ubuffer_size, hasInput);
  134.  
  135.  
  136.   //convert (if necessary) to f32 and channels, sending result to output
  137.   int sameChannels = ustereo==ostereo;
  138.   if(sameChannels){ //convert type (or just copy contents if _stream is f32)
  139.     _kit_kmixerVoiceProcFromType(_stream,obuffer, frames,uformat,ustereo);
  140.  
  141.   } else if(userTypeIsF32){ //convert channels
  142.     _kit_kmixerVoiceProcChannels(_stream,obuffer, frames,_CH_INFO(ustereo,ostereo));
  143.  
  144.   } else { //convert type and channels
  145.     _kit_kmixerVoiceProcFromType(_stream,cbuffer, frames,uformat,ustereo);
  146.     _kit_kmixerVoiceProcChannels(cbuffer,obuffer, frames,_CH_INFO(ustereo,ostereo));
  147.  
  148.   }
  149.  
  150.  
  151.   SDL_UnlockMutex(voice->lock);
  152.   return 0;
  153. }
  154.  
  155.  
  156.  
  157.  
  158. //assumes all samples are f32
  159. //if nothing else works
  160. static inline void _kit_kmixerVoiceMixFallback(_kit_kmixerVoice* voiceO){
  161.   kit_coreVector**  raw_p = &voiceO->device->_raw;
  162.   _kit_kmixerVoice* raw   = (*raw_p)->data;
  163.  
  164.   Uint32*              inputs      = voiceO->inputs->data;
  165.   Uint32               inputs_len  = voiceO->inputs->x;
  166.   kit_acodecPCM_F32S*  samplesO    = voiceO->bufferInput.f32s;
  167.   Uint32               samples_len = voiceO->spec.samples;
  168.  
  169.   size_t bufferSize = (samples_len*sizeof(float))<<voiceO->spec.stereo;
  170.   kit_coreMemset(voiceO->bufferInput.data, 0, bufferSize);
  171.   //so stereo volume can apply even to a mono stream
  172.    //(assuming volR is set to volL)
  173.   samples_len >>= !voiceO->spec.stereo;
  174.  
  175.  
  176.   for(Uint32 v=0; v<inputs_len; ++v){
  177.     _kit_kmixerVoice* voiceI = &raw[ inputs[v] ];
  178.     if(voiceI->lock == NULL){ inputs[v] = 0; continue; }
  179.     if(!voiceI->active) continue; //also skip if voice is inactive
  180.     SDL_LockMutex(voiceI->lock);
  181.     kit_acodecPCM_F32S* samplesI = voiceI->bufferOutput.f32s;
  182.  
  183.     float volL = CLAMP(voiceI->volL, 0.0f,1.0f);
  184.     float volR = MIN(voiceI->volR, 1.0f);
  185.     if(!voiceI->stereoOutput || volR<0) volR = volL;
  186.  
  187.     if(     volL==0.0f && volR==0.0f) continue; //volume is muted; skip
  188.     else if(volL==1.0f && volR==1.0f) goto _normal_volume; //because sample*1=sample
  189.     else if(volL>=0.0f){
  190.       for(Uint32 i=0; i<samples_len; ++i){
  191.         samplesO[i].l += samplesI[i].l*volL;
  192.         samplesO[i].r += samplesI[i].r*volR;
  193.       }
  194.  
  195.     } else { _normal_volume:
  196.       for(Uint32 i=0; i<samples_len; ++i){
  197.         samplesO[i].l += samplesI[i].l;
  198.         samplesO[i].r += samplesI[i].r;
  199.       }
  200.  
  201.     }
  202.  
  203.     SDL_UnlockMutex(voiceI->lock);
  204.   }
  205.  
  206.  
  207.   //hard clip output samples to between -1.0f and 1.0f
  208.   for(Uint32 i=0; i<samples_len; ++i){
  209.     float sampleL = samplesO[i].l;
  210.     float sampleR = samplesO[i].r;
  211.     samplesO[i].l = CLAMP(sampleL, -1.0f,1.0f);
  212.     samplesO[i].r = CLAMP(sampleR, -1.0f,1.0f);
  213.   }
  214. }
  215. //(this should only be called if the voice has inputs)
  216. int _kit_kmixerVoiceMix(void* data){ //(this is an SDL_ThreadFunction)
  217.   _kit_kmixerVoice* voiceO = data;
  218.   if(voiceO == NULL) return 1; //skip if the voice is NULL
  219.   if(voiceO->lock == NULL) return 2; //skip in case voice was removed
  220.  
  221.   SDL_LockMutex(voiceO->lock);
  222.   //don't mix if voice has no inputs...
  223.   if(voiceO->inputs == NULL){
  224.     size_t bufferSize = (voiceO->spec.samples*sizeof(float)) << voiceO->spec.stereo;
  225.     //...but still make sure the input buffer is zeroed out
  226.     kit_coreMemset(voiceO->bufferInput.data, 0, bufferSize);
  227.     SDL_UnlockMutex(voiceO->lock);
  228.     return 3;
  229.   }
  230.  
  231.   _kit_kmixerVoiceMixFallback(voiceO);
  232.  
  233.   SDL_UnlockMutex(voiceO->lock);
  234.   return 0;
  235. }
  236.  
  237.  
  238.  
  239.  
  240. //used to check whether an element in the raw voice list is valid or not
  241. SDL_bool _kit_kmixerVoiceRawUnitCallback(void* unit, Uint32 size){
  242.   _kit_kmixerVoice* voice = unit;
  243.   return voice->lock == NULL;
  244. }
  245.  
  246.  
  247.  
  248. //same thing, but with an element in ord instead of raw
  249. SDL_bool _kit_kmixerVoiceOrdUnitCallback(void* unit, Uint32 size){
  250.   _kit_kmixerVoice** voice_p = unit;
  251.   if(*voice_p == NULL) return SDL_TRUE;
  252.   return (*voice_p)->lock == NULL;
  253. }
  254.  
  255.  
  256.  
  257.  
  258. //(assumes device is locked)
  259. //should be called when voices are created, destroyed, or raw is altered in general
  260. int _kit_kmixerVoiceRebuildOrd(kit_kmixerDevice* device){
  261.   kit_coreVector* ord_new = NULL;
  262.   kit_coreVector**  ord_p = &device->_ord;
  263.   kit_coreVector**  raw_p = &device->_raw;
  264.  
  265.   _kit_kmixerVoice* raw = (*raw_p)->data;
  266.   Uint32      numVoices = (*raw_p)->x;
  267.  
  268.   Uint32  hiStageLen =    0; //ord->x
  269.   Uint32  hiStage    =    0; //ord->y
  270.   Uint32* stageLens  = NULL; //temporary space for stage lengths
  271.  
  272.  
  273.   //find highest chain stage (for ord's y axis)
  274.   for(Uint32 v=0; v<numVoices; ++v){
  275.     if(raw[v].lock == NULL) continue; //skip any removed voice
  276.     if(hiStage < raw[v].chainStage) hiStage = raw[v].chainStage;
  277.   }
  278.   ++hiStage; //should now equal ord->y
  279.  
  280.  
  281.   //find highest index of a chain stage (for ord's x axis)
  282.   _IF_SDLERR(kit_coreRealloc(&stageLens,0,hiStage*sizeof(Uint32)),;,"!stageLens")
  283.   for(Uint32 v=0; v<numVoices; ++v){
  284.     if(raw[v].lock == NULL) continue; //skip any removed voice
  285.     Uint32 stageLen = ++stageLens[raw[v].chainStage];
  286.     if(hiStageLen < stageLen) hiStageLen = stageLen;
  287.   }
  288.   SAFE_FREE(stageLens);
  289.   if(!hiStageLen) hiStageLen = 1; //vectors can't have sizes of 0
  290.  
  291.  
  292.   //create new ord vector with new dimensions
  293.   ord_new = kit_coreVectorCreate(hiStageLen,hiStage,1, sizeof(_kit_kmixerVoice*),0);
  294.   _IF_SDLERR(ord_new==NULL,;,"!ord_new")
  295.   kit_coreVectorDestroy(ord_p); //doink the old one
  296.   *ord_p = ord_new;
  297.  
  298.  
  299.   //fill ord with new references from raw
  300.   for(Uint32 v=0; v<numVoices; ++v){
  301.     if(raw[v].lock == NULL) continue; //skip any removed voice
  302.     _kit_kmixerVoice* voiceRef = &raw[v];
  303.     Uint32 chainStage = voiceRef->chainStage;
  304.     _IF_GOTO_ERROR(kit_coreVectorInsert(ord_p, &voiceRef, chainStage,0,
  305.                                         _kit_kmixerVoiceOrdUnitCallback)==U32_MAX,;)
  306.   }
  307.  
  308.  
  309.   /*!err*/ return  0;
  310.   _error_: return -1;
  311. }
  312.  
  313.  
  314.  
  315.  
  316. //(assumes device is already locked)
  317. //output voice is locked here
  318. int _kit_kmixerVoiceRemoveInput(kit_kmixerDevice* device,
  319.                                 Uint32 outputID, Uint32 inputID)
  320. {
  321.   _kit_kmixerVoice* voiceO = &_VOICE_QUERY(outputID);
  322.   Uint32* inputs     = voiceO->inputs->data;
  323.   Uint32  inputs_len = voiceO->inputs->x;
  324.  
  325.   _IF_GOTO_ERROR(SDL_LockMutex(voiceO->lock),;)
  326.  
  327.  
  328.   //remove input voice from output voice's input list
  329.   for(Uint32 v=0; v<inputs_len; ++v){
  330.     if(inputs[v] == inputID){
  331.       inputs[v] = 0; break;
  332.     }
  333.   }
  334.  
  335.  
  336.   //trim input list to make sure only active inputs are included
  337.   _IF_GOTO_ERROR(kit_coreVectorTrim(&voiceO->inputs,'x',NULL),;)
  338.   //destroy input list if all inputs have been removed
  339.   if(!voiceO->inputs->lens[0]) kit_coreVectorDestroy(&voiceO->inputs);
  340.  
  341.  
  342.   _IF_GOTO_ERROR(SDL_UnlockMutex(voiceO->lock),;)
  343.  
  344.   /*!err*/ return  0;
  345.   _error_: return -1;
  346. }
  347.  
  348.  
  349.  
  350. //(assumes device is already locked)
  351. //input and output voices are locked here
  352.  //(also, input voice's lock should be created BEFORE calling this)
  353. int _kit_kmixerVoiceAddInput(kit_kmixerDevice* device,
  354.                              Uint32 inputID, Uint32 outputID)
  355. {
  356.   //since everything relevant is locked currently, i can assign pointers
  357.    //without the risk of the data moving somewhere else by a kit_coreVectorSet or something
  358.   _kit_kmixerVoice* voiceI = &_VOICE_QUERY(inputID);
  359.   _kit_kmixerVoice* voiceO = &_VOICE_QUERY(outputID);
  360.  
  361.  
  362.   //set input voice accordingly
  363.   _IF_GOTO_ERROR(SDL_LockMutex(voiceI->lock),;)
  364.  
  365.   voiceI->output       = voiceO->index; // = outputID basically
  366.   voiceI->stereoOutput = voiceO->spec.stereo;
  367.   //set chain processing stage one higher,
  368.    //to ensure this voice is processed before the output
  369.   voiceI->chainStage   = voiceO->chainStage+1;
  370.  
  371.   _IF_GOTO_ERROR(SDL_UnlockMutex(voiceI->lock),;)
  372.  
  373.  
  374.   //create input list in output voice if it's NULL
  375.   if(voiceO->inputs == NULL){
  376.     voiceO->inputs = kit_coreVectorCreate(1,1,1, sizeof(Uint32),0);
  377.     _IF_GOTO_ERROR(voiceO->inputs==NULL,;)
  378.   }
  379.  
  380.  
  381.   //add input to the output voice's input list
  382.   _IF_GOTO_ERROR(SDL_LockMutex(voiceO->lock),;)
  383.  
  384.    //first, check to see if input is already in the list...
  385.   Uint32* inputs     = voiceO->inputs->data;
  386.   Uint32  inputs_len = voiceO->inputs->x;
  387.   SDL_bool found = SDL_FALSE;
  388.   for(Uint32 i=0; i<inputs_len; ++i){
  389.     if(inputs[i] == inputID){
  390.       found = SDL_TRUE; break;
  391.     }
  392.   }
  393.  
  394.    //...inserting only if the input was not found in the list
  395.   if(!found) _IF_GOTO_ERROR(kit_coreVectorInsert(&voiceO->inputs, &inputID, 0,0, NULL)==U32_MAX,;)
  396.  
  397.   _IF_GOTO_ERROR(SDL_UnlockMutex(voiceO->lock),;)
  398.  
  399.  
  400.   /*!err*/ return  0;
  401.   _error_: return -1;
  402. }
  403.  
  404.  
  405.  
  406.  
  407. int kit_kmixerVoiceRemove(kit_kmixerDevice* device, Uint32 voiceID){
  408.   _DEVICE_VALIDITY_CHECK(0)
  409.   //only allow voice 0 to be removed when device->_closing is set
  410.   _IF_SDLERR(!voiceID && !device->_closing,;,"cannot remove voice 0")
  411.  
  412.   //if bit 31 is set, call is assumed to be the result of recursion
  413.   SDL_bool rootCall = (!(voiceID&U32_MSb)) ? SDL_TRUE : SDL_FALSE;
  414.   voiceID &= I32_MAX; //unset bit 31 now that rootCall is set
  415.  
  416.  
  417.   kit_coreVector**   raw_p = &device->_raw;
  418.   _IF_SDLERR(voiceID>=(*raw_p)->x,;,"voiceID out of bounds")
  419.   _IF_GOTO(_VOICE_QUERY(voiceID).lock==NULL,_noerr_,;) //return normally if voice already removed
  420.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  421.  
  422.  
  423.   //loop through and remove any inputs the voice might have (recursive)
  424.   if(_VOICE_QUERY(voiceID).inputs != NULL){
  425.     //the voice's inputs vector shouldn't change, since the voice is locked,
  426.      //so it should be safe to do pointer assignment here
  427.     kit_coreVector* inputs = _VOICE_QUERY(voiceID).inputs;
  428.  
  429.     for(Uint32 i=0; i<inputs->x; ++i){
  430.       Uint32 index = VECTOR_INDEX_C(Uint32, inputs, i);
  431.       if(!index) continue; //an index of 0 indicates a voice that was already removed
  432.       if(_VOICE_QUERY(index).lock != NULL) //(bit 31 is set to indicate recursion)
  433.         _IF_GOTO_ERROR(kit_kmixerVoiceRemove(device,U32_MSb|index),;)
  434.     }
  435.  
  436.     //(kit_coreVectorDestroy automatically sets pointer to NULL)
  437.     _IF_GOTO_ERROR(kit_coreVectorDestroy(&_VOICE_QUERY(voiceID).inputs),;)
  438.   }
  439.  
  440.  
  441.   //free buffers
  442.   SAFE_FREE(_VOICE_QUERY(voiceID).bufferInput.data);
  443.   SAFE_FREE(_VOICE_QUERY(voiceID).bufferUser.data);
  444.   SAFE_FREE(_VOICE_QUERY(voiceID).bufferConvert.data);
  445.   SAFE_FREE(_VOICE_QUERY(voiceID).bufferOutput.data);
  446.  
  447.  
  448.   //call the user's 'userdata removal' callback
  449.   if(_VOICE_QUERY(voiceID).spec.remove != NULL)
  450.     _VOICE_QUERY(voiceID).spec.remove(_VOICE_QUERY(voiceID).spec.userdata);
  451.  
  452.  
  453.   //destroy lock
  454.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  455.   SDL_DestroyMutex(_VOICE_QUERY(voiceID).lock);
  456.   _VOICE_QUERY(voiceID).lock       = NULL; //a mutex of NULL indicates a removed voice
  457.   _VOICE_QUERY(voiceID).chainStage =    0; //(as to not confuse VoiceRebuildOrd)
  458.  
  459.  
  460.   if(rootCall){ //if this call is not the result of recursion
  461.     if(!device->_closing) kit_kmixerDeviceLock(device, SDL_TRUE);
  462.  
  463.     //trim raw and rebuild ord
  464.     _IF_GOTO_ERROR(kit_coreVectorTrim(raw_p,'x',_kit_kmixerVoiceRawUnitCallback),;)
  465.     _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
  466.  
  467.     //remove input from output's input list
  468.     Uint32 outputID = VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, voiceID).output;
  469.  
  470.     if(outputID != U32_MAX){ //(only if output != -1, which should only be possible for voice 0)
  471.       _IF_GOTO_ERROR(_kit_kmixerVoiceRemoveInput(device, outputID,voiceID),
  472.                      kit_kmixerDeviceLock(device, SDL_FALSE))
  473.     }
  474.  
  475.     if(!device->_closing) kit_kmixerDeviceLock(device, SDL_FALSE);
  476.   }
  477.  
  478.  
  479.   _noerr_: return  0;
  480.   _error_: return -1;
  481. }
  482.  
  483.  
  484.  
  485. Uint32 kit_kmixerVoiceAdd(kit_kmixerDevice* device, kit_kmixerVoiceSpec* vspec,
  486.                           Uint32 outputVoiceID)
  487. {
  488.   Uint32 newIndex = 0; //0 for error by default
  489.   _kit_kmixerVoice  voice  = { .lock = NULL }; //voice struct to be copied to raw
  490.   _kit_kmixerVoice* voiceI = NULL; //reference to voice inside raw
  491.  
  492.   SDL_bool inRaw   = SDL_FALSE; //set to true if successfully inserted into raw
  493.   SDL_bool success = SDL_FALSE;
  494.   SDL_bool locked  = SDL_FALSE;
  495.   _DEVICE_VALIDITY_CHECK(0)
  496.   _IF_SDLERR(vspec==NULL,;,"!vspec")
  497.  
  498.   _IF_SDLERR(vspec->callback==NULL,;,"!vspec->callback")
  499.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_TRUE)<0,;)
  500.   locked = SDL_TRUE;
  501.  
  502.   //get reference to output voice
  503.   int exists = kit_kmixerVoiceExists(device, outputVoiceID);
  504.   _IF_SDLERR(exists<0,;,"outputVoiceID out of bounds")
  505.   _IF_SDLERR(!exists,;,"output voice doesn't exist")
  506.  
  507.  
  508.   //fill in info for voice spec and the voice struct itself
  509.   _IF_GOTO_ERROR(_kit_kmixerVoiceAddFillSpec(device, vspec),;)
  510.   _IF_GOTO_ERROR(_kit_kmixerVoiceAddFillVoice(device, vspec, &voice, outputVoiceID),;)
  511.   voice.device = device; //the only thing not filled in by FillVoice
  512.  
  513.  
  514.   //add voice to raw
  515.   newIndex = kit_coreVectorInsert(&device->_raw, &voice, 0,0, _kit_kmixerVoiceRawUnitCallback);
  516.   _IF_GOTO_ERROR(newIndex==U32_MAX,;)
  517.   voiceI = &_VOICE_QUERY(newIndex);
  518.   voiceI->index = newIndex;
  519.   inRaw = SDL_TRUE;
  520.  
  521.  
  522.   //add voice to output's input list
  523.   _IF_GOTO_ERROR(_kit_kmixerVoiceAddInput(device, newIndex, outputVoiceID),;)
  524.  
  525.  
  526.   //finally, rebuild ord to reflect new state of raw
  527.   _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
  528.  
  529.   _noerr_:
  530.   success = SDL_TRUE;
  531.   _error_:
  532.   if(!success){
  533.     //the buffer pointers will be the same between voice and *voiceI,
  534.      //and they must be freed either way if this function aborts
  535.     if(!inRaw) voiceI = &voice;
  536.  
  537.     if(voiceI->lock != NULL) SDL_DestroyMutex(voiceI->lock);
  538.     kit_coreVectorDestroy(&voiceI->inputs);
  539.     SAFE_FREE(voiceI->bufferInput.data);
  540.     SAFE_FREE(voiceI->bufferUser.data);
  541.     SAFE_FREE(voiceI->bufferConvert.data);
  542.     SAFE_FREE(voiceI->bufferOutput.data);
  543.     voiceI->lock = NULL;
  544.  
  545.     //(make newIndex indicate an error again, regardless of its prev. value)
  546.     newIndex = 0;
  547.   }
  548.   if(locked) kit_kmixerDeviceLock(device, SDL_FALSE);
  549.   return newIndex;
  550. }
  551.  
  552.  
  553.  
  554.  
  555. //updates a voice's chain stage after redirecting
  556. void _kit_kmixerVoiceCascadeChainStage(kit_kmixerDevice* device, Uint32 voiceID){
  557.   Uint32 outputID = _VOICE_QUERY(voiceID).output;
  558.  
  559.   //set input voice's chain stage to one higher than the output
  560.   _VOICE_QUERY(voiceID).chainStage = _VOICE_QUERY(outputID).chainStage+1;
  561.  
  562.   //if input voice itself has inputs, call VoiceCascade on all of them
  563.    //(this should be recursive)
  564.   if(_VOICE_QUERY(voiceID).inputs != NULL){
  565.     kit_coreVector* inputs = _VOICE_QUERY(voiceID).inputs;
  566.     for(Uint32 i=0; i<inputs->x; ++i){
  567.       Uint32 input = VECTOR_INDEX_C(Uint32, inputs, i);
  568.       if(!input) continue; //skip any invalid or removed voices
  569.       _kit_kmixerVoiceCascadeChainStage(device,input);
  570.     }
  571.   }
  572. }
  573.  
  574.  
  575.  
  576. int kit_kmixerVoiceRedirect(kit_kmixerDevice* device,
  577.                             Uint32 inputVoiceID, Uint32 outputVoiceID)
  578. {
  579.   int returnStatus = 0;
  580.   SDL_bool locked = SDL_FALSE;
  581.   _DEVICE_VALIDITY_CHECK(0)
  582.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_TRUE)<0,;)
  583.   locked = SDL_TRUE;
  584.  
  585.   _IF_SDLERR(!inputVoiceID,;,"cannot redirect voice 0")
  586.  
  587.   int exists = kit_kmixerVoiceExists(device, inputVoiceID);
  588.   _IF_SDLERR(exists<0,;,"inputVoiceID out of bounds")
  589.   _IF_SDLERR(!exists,;,"input voice doesn't exist")
  590.  
  591.   exists = kit_kmixerVoiceExists(device, outputVoiceID);
  592.   _IF_SDLERR(exists<0,;,"outputVoiceID out of bounds")
  593.   _IF_SDLERR(!exists,;,"output voice doesn't exist")
  594.  
  595.   _IF_SDLERR(_VOICE_QUERY(outputVoiceID).output==inputVoiceID,;,"output can't be circular")
  596.  
  597.  
  598.   //disconnect from the old output, before connecting to the new output
  599.   Uint32 outputVoiceID_old = _VOICE_QUERY(inputVoiceID).output;
  600.   _IF_GOTO_ERROR(_kit_kmixerVoiceRemoveInput(device, outputVoiceID_old, inputVoiceID),;)
  601.   _IF_GOTO_ERROR(_kit_kmixerVoiceAddInput(device, inputVoiceID, outputVoiceID),;)
  602.  
  603.  
  604.   //update every chainStage value up the voice chain,
  605.    //to accomodate the stage of the new output
  606.   _kit_kmixerVoiceCascadeChainStage(device,inputVoiceID);
  607.  
  608.  
  609.   //update ord to reflect changes
  610.   _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
  611.  
  612.  
  613.   _noerr_: ++returnStatus;
  614.   _error_: --returnStatus;
  615.   if(locked && kit_kmixerDeviceLock(device, SDL_FALSE)<0) returnStatus = -1;
  616.   return returnStatus;
  617. }
  618.  
  619.  
  620.  
  621. int kit_kmixerVoiceExists(kit_kmixerDevice* device, Uint32 voiceID){
  622.   _DEVICE_VALIDITY_CHECK(0)
  623.   _IF_SDLERR(voiceID>=device->_raw->x,;,"voiceID out of bounds")
  624.   _noerr_: return _VOICE_QUERY(voiceID).lock != NULL;
  625.   _error_: return -1;
  626. }
  627.  
  628.  
  629.  
  630.  
  631. Uint32 kit_kmixerVoiceGetNumInputs(kit_kmixerDevice* device, Uint32 voiceID){
  632.   _VOICE_CHECK(voiceID)
  633.   if(_VOICE_QUERY(voiceID).inputs == NULL) return 0;
  634.   /*!err*/ return _VOICE_QUERY(voiceID).inputs->x;
  635.   _error_: return U32_MAX;
  636. }
  637.  
  638.  
  639.  
  640. kit_coreVector* kit_kmixerVoiceGetInputs(kit_kmixerDevice* device, Uint32 voiceID){
  641.   kit_coreVector* inputs = NULL;
  642.   _VOICE_CHECK(voiceID)
  643.  
  644.   _IF_SDLERR(_VOICE_QUERY(voiceID).inputs==NULL,;,"no inputs found")
  645.   inputs = kit_coreVectorCopy(_VOICE_QUERY(voiceID).inputs);
  646.  
  647.   _error_:
  648.   return inputs;
  649. }
  650.  
  651.  
  652.  
  653. Uint32 kit_kmixerVoiceGetOutput(kit_kmixerDevice* device, Uint32 voiceID){
  654.   _VOICE_CHECK(voiceID)
  655.  
  656.   _IF_SDLERR(_VOICE_QUERY(voiceID).output==U32_MAX,;,"voice 0 has no output!")
  657.  
  658.   /*!err*/ return _VOICE_QUERY(voiceID).output;
  659.   _error_: return U32_MAX;
  660. }
  661.  
  662.  
  663.  
  664. SDL_bool* kit_kmixerVoiceGetActiveRef(kit_kmixerDevice* device, Uint32 voiceID){
  665.   _VOICE_CHECK(voiceID)
  666.   /*!err*/ return &_VOICE_QUERY(voiceID).active;
  667.   _error_: return NULL;
  668. }
  669.  
  670.  
  671.  
  672. int kit_kmixerVoiceGetActive(kit_kmixerDevice* device, Uint32 voiceID){
  673.   _VOICE_CHECK(voiceID)
  674.   /*!err*/ return _VOICE_QUERY(voiceID).active;
  675.   _error_: return -1;
  676. }
  677.  
  678.  
  679.  
  680. int kit_kmixerVoiceSetActive(kit_kmixerDevice* device, Uint32 voiceID, SDL_bool isActive){
  681.   _VOICE_CHECK(voiceID)
  682.  
  683.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  684.  
  685.   _VOICE_QUERY(voiceID).active = isActive;
  686.  
  687.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  688.  
  689.   /*!err*/ return  0;
  690.   _error_: return -1;
  691. }
  692.  
  693.  
  694.  
  695. void _kit_kmixerVoiceCascadeActive(kit_kmixerDevice* device, Uint32 voiceID, SDL_bool isActive){
  696.   _VOICE_QUERY(voiceID).active = isActive;
  697.  
  698.   //recursively set the active state on all input voices (if there are any)
  699.   if(_VOICE_QUERY(voiceID).inputs != NULL){
  700.     //it should be safe to dereference inputs here, since the whole device
  701.      //should be locked at this point
  702.     Uint32* inputs     = _VOICE_QUERY(voiceID).inputs->data;
  703.     Uint32  inputs_len = _VOICE_QUERY(voiceID).inputs->x;
  704.     for(Uint32 i=0; i<inputs_len; ++i){
  705.       if(!inputs[i]) continue; //skip any invalid or removed voices
  706.       _kit_kmixerVoiceCascadeActive(device,inputs[i], isActive);
  707.     }
  708.   }
  709. }
  710.  
  711.  
  712.  
  713. int kit_kmixerVoiceSetActiveChain(kit_kmixerDevice* device, Uint32 voiceID, SDL_bool isActive){
  714.   int returnStatus = 0;
  715.   SDL_bool locked = SDL_FALSE;
  716.   _DEVICE_VALIDITY_CHECK(0)
  717.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_TRUE)<0,;)
  718.   locked = SDL_TRUE;
  719.  
  720.   //now that the device is locked, CascadeActive can safely be called,
  721.    //(much like CascadeChainStage)
  722.   _kit_kmixerVoiceCascadeActive(device, voiceID, isActive);
  723.  
  724.   _noerr_: ++returnStatus;
  725.   _error_: --returnStatus;
  726.   if(locked && kit_kmixerDeviceLock(device, SDL_FALSE)<0) returnStatus = -1;
  727.   return returnStatus;
  728. }
  729.  
  730.  
  731.  
  732.  
  733. Uint32 kit_kmixerVoiceGetChainStage(kit_kmixerDevice* device, Uint32 voiceID){
  734.   _VOICE_CHECK(voiceID)
  735.   /*!err*/ return _VOICE_QUERY(voiceID).chainStage;
  736.   _error_: return U32_MAX;
  737. }
  738.  
  739.  
  740.  
  741.  
  742. kit_kmixerVoiceSpec kit_kmixerVoiceGetSpec(kit_kmixerDevice* device, Uint32 voiceID){
  743.   kit_kmixerVoiceSpec vspec = {0};
  744.   _VOICE_CHECK(voiceID)
  745.  
  746.   vspec = _VOICE_QUERY(voiceID).spec;
  747.  
  748.   _error_:
  749.   return vspec;
  750. }
  751.  
  752.  
  753.  
  754. kit_kmixerVoiceSpec* kit_kmixerVoiceGetSpecRef(kit_kmixerDevice* device, Uint32 voiceID){
  755.   _VOICE_CHECK(voiceID)
  756.   /*!err*/ return &_VOICE_QUERY(voiceID).spec;
  757.   _error_: return NULL;
  758. }
  759.  
  760.  
  761.  
  762. void* kit_kmixerVoiceGetSpecUserdata(kit_kmixerDevice* device, Uint32 voiceID){
  763.   _IF_SDLERR(!voiceID,;,"voice 0 has no userdata")
  764.   _VOICE_CHECK(voiceID)
  765.   /*!err*/ return _VOICE_QUERY(voiceID).spec.userdata;
  766.   _error_: return NULL;
  767. }
  768.  
  769.  
  770.  
  771. int kit_kmixerVoiceSetSpecRemove(kit_kmixerDevice* device, Uint32 voiceID,
  772.                                  kit_kmixerVoiceRemoveCallback remove)
  773. {
  774.   _VOICE_CHECK(voiceID)
  775.  
  776.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  777.  
  778.   _VOICE_QUERY(voiceID).spec.remove = remove;
  779.  
  780.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  781.  
  782.   /*!err*/ return  0;
  783.   _error_: return -1;
  784. }
  785.  
  786.  
  787.  
  788. int kit_kmixerVoiceSetSpecCallback(kit_kmixerDevice* device, Uint32 voiceID,
  789.                                    kit_kmixerVoiceCallback callback)
  790. {
  791.   //(remove and userdata can be NULL, but the voice callback itself cannot)
  792.   _IF_SDLERR(callback==NULL,;,"!callback")
  793.   _VOICE_CHECK(voiceID)
  794.  
  795.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  796.  
  797.   _VOICE_QUERY(voiceID).spec.callback = callback;
  798.  
  799.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  800.  
  801.   /*!err*/ return  0;
  802.   _error_: return -1;
  803. }
  804.  
  805.  
  806.  
  807. int kit_kmixerVoiceSetSpecUserdata(kit_kmixerDevice* device, Uint32 voiceID, void* userdata){
  808.   _VOICE_CHECK(voiceID)
  809.  
  810.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  811.  
  812.   _VOICE_QUERY(voiceID).spec.userdata = userdata;
  813.  
  814.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  815.  
  816.   /*!err*/ return  0;
  817.   _error_: return -1;
  818. }
  819.  
  820.  
  821.  
  822.  
  823. float kit_kmixerVoiceGetVolL(kit_kmixerDevice* device, Uint32 voiceID){
  824.   _VOICE_CHECK(voiceID)
  825.   /*!err*/ return _VOICE_QUERY(voiceID).volL;
  826.   _error_: return NAN;
  827. }
  828.  
  829.  
  830.  
  831. float kit_kmixerVoiceGetVolR(kit_kmixerDevice* device, Uint32 voiceID){
  832.   _VOICE_CHECK(voiceID)
  833.   /*!err*/ return _VOICE_QUERY(voiceID).volR;
  834.   _error_: return NAN;
  835. }
  836.  
  837.  
  838.  
  839. int kit_kmixerVoiceSetVolL(kit_kmixerDevice* device, Uint32 voiceID, float volL){
  840.   _IF_SDLERR(volL<0,;,"volL must be >=0")
  841.   _VOICE_CHECK(voiceID)
  842.  
  843.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  844.  
  845.   _VOICE_QUERY(voiceID).volL = volL;
  846.  
  847.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  848.  
  849.   /*!err*/ return  0;
  850.   _error_: return -1;
  851. }
  852.  
  853.  
  854.  
  855. int kit_kmixerVoiceSetVolR(kit_kmixerDevice* device, Uint32 voiceID, float volR){
  856.   _IF_SDLERR(volR<0,;,"volR must be >=0")
  857.   _VOICE_CHECK(voiceID)
  858.  
  859.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  860.  
  861.   _VOICE_QUERY(voiceID).volR = volR;
  862.  
  863.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  864.  
  865.   /*!err*/ return  0;
  866.   _error_: return -1;
  867. }
  868.  
  869.  
  870.  
  871. int kit_kmixerVoiceSetVolume(kit_kmixerDevice* device, Uint32 voiceID, float volL, float volR){
  872.   _IF_SDLERR(volL<0,;,"volL must be >=0")
  873.   _IF_SDLERR(volR<0,;,"volR must be >=0")
  874.   _VOICE_CHECK(voiceID)
  875.  
  876.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  877.  
  878.   _VOICE_QUERY(voiceID).volL = volL;
  879.   _VOICE_QUERY(voiceID).volR = volR;
  880.  
  881.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  882.  
  883.   /*!err*/ return  0;
  884.   _error_: return -1;
  885. }
  886.  
  887.  
  888.  
  889. int kit_kmixerVoiceSetPan(kit_kmixerDevice* device, Uint32 voiceID, float pan){
  890.   _IF_SDLERR(!NORMALIZED(pan),;,"pan must be -1.0f -> 1.0f")
  891.   _VOICE_CHECK(voiceID)
  892.   _IF_SDLERR(_VOICE_QUERY(voiceID).spec.stereo,;,"voice cannot be mono")
  893.  
  894.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  895.  
  896.   //for example, if pan = -0.6f, volL and volR would be 1.0f and 0.4f respectively
  897.   _VOICE_QUERY(voiceID).volL = MIN(1.0f+pan, 1.0f);
  898.   _VOICE_QUERY(voiceID).volR = MIN(1.0f-pan, 1.0f);
  899.  
  900.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  901.  
  902.   /*!err*/ return  0;
  903.   _error_: return -1;
  904. }
  905.  
  906.  
  907.  
  908.  
  909. int kit_kmixerVoiceUnlock(kit_kmixerDevice* device, Uint32 voiceID){
  910.   _IF_SDLERR(!voiceID,;,"cannot unlock voice 0")
  911.   _VOICE_CHECK(voiceID)
  912.  
  913.   _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
  914.  
  915.   /*!err*/ return  0;
  916.   _error_: return -1;
  917. }
  918.  
  919.  
  920.  
  921. int kit_kmixerVoiceLock(kit_kmixerDevice* device, Uint32 voiceID){
  922.   _IF_SDLERR(!voiceID,;,"cannot lock voice 0")
  923.   _VOICE_CHECK(voiceID)
  924.  
  925.   _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
  926.  
  927.   /*!err*/ return  0;
  928.   _error_: return -1;
  929. }
  930.  
  931.  
  932.  
  933.  
  934. #if defined(_KIT_KMIXER_DEBUG) || defined(_KIT_ALL_DEBUG)
  935. void _kit_kmixerVoice_TestCallback(void* userdata, void* _stream, int size, SDL_bool hasInput){
  936. }
  937. /*
  938. because kmixer compiles with -O3, i get this error if i attempt to compile the test:
  939. "warning:  may be used uninitialized in this function [-Wmaybe-uninitialized]|"
  940. i have very little doubt that this is a bug, so i can't do much about it other than
  941. turn down optimization for this specific function
  942. */
  943. //(for some reason, it started working again after i added some seemingly
  944.  //unrelated stuff, so i'll comment this out for now)
  945. //__attribute__((optimize("-O0")))
  946. int kit_kmixerVoice_Test(){
  947.   float bufferInputA[16], bufferUserA[16], bufferConvertA[16], bufferOutputA[16];
  948.   float bufferInputB[16], bufferUserB[16], bufferConvertB[16], bufferOutputB[16];
  949.   float bufferInputC[16], bufferUserC[16], bufferConvertC[16], bufferOutputC[16];
  950.  
  951.  
  952.   _kit_kmixerVoice voiceA={
  953.     .spec={
  954.       .callback = _kit_kmixerVoice_TestCallback,
  955.       .userdata = NULL,
  956.       .freq     = 44100,
  957.       ._size    = 16*sizeof(float),
  958.       .stereo   = SDL_FALSE,
  959.       .samples  = 16,
  960.       .format   = AUDIO_F32
  961.     },
  962.  
  963.     .bufferInput   = { .data=bufferInputA   },
  964.     .bufferUser    = { .data=bufferUserA    },
  965.     .bufferConvert = { .data=bufferConvertA },
  966.     .bufferOutput  = { .data=bufferOutputA  },
  967.  
  968.     .inputs = NULL,
  969.     .lock   = NULL,
  970.  
  971.     .chainStage = 2,
  972.     .index      = 3,
  973.  
  974.     .volL = 1.0f,
  975.     .volR = 1.0f,
  976.  
  977.     .stereoOutput = SDL_FALSE,
  978.   };
  979.  
  980.   _kit_kmixerVoice voiceB={
  981.     .spec={
  982.       .callback = _kit_kmixerVoice_TestCallback,
  983.       .userdata = NULL,
  984.       .freq     = 44100,
  985.       ._size    = 16*sizeof(float),
  986.       .stereo   = SDL_FALSE,
  987.       .samples  = 16,
  988.       .format   = AUDIO_F32
  989.     },
  990.  
  991.     .bufferInput   = { .data=bufferInputB   },
  992.     .bufferUser    = { .data=bufferUserB    },
  993.     .bufferConvert = { .data=bufferConvertB },
  994.     .bufferOutput  = { .data=bufferOutputB  },
  995.  
  996.     .inputs = NULL,
  997.     .lock   = NULL,
  998.  
  999.     .chainStage = 2,
  1000.     .index      = 2,
  1001.  
  1002.     .volL = 1.0f,
  1003.     .volR = 1.0f,
  1004.  
  1005.     .stereoOutput = SDL_FALSE,
  1006.   };
  1007.  
  1008.   _kit_kmixerVoice voiceC={
  1009.     .spec={
  1010.       .callback = _kit_kmixerVoice_TestCallback,
  1011.       .userdata = NULL,
  1012.       .freq     = 44100,
  1013.       ._size    = 16*sizeof(float),
  1014.       .stereo   = SDL_FALSE,
  1015.       .samples  = 16,
  1016.       .format   = AUDIO_F32
  1017.     },
  1018.  
  1019.     .bufferInput   = { .data=bufferInputC   },
  1020.     .bufferUser    = { .data=bufferUserC    },
  1021.     .bufferConvert = { .data=bufferConvertC },
  1022.     .bufferOutput  = { .data=bufferOutputC  },
  1023.  
  1024.     .inputs = NULL,
  1025.     .lock   = NULL,
  1026.  
  1027.     .chainStage = 1,
  1028.     .index      = 1,
  1029.  
  1030.     .volL = 1.0f,
  1031.     .volR = 1.0f,
  1032.  
  1033.     .stereoOutput = SDL_FALSE,
  1034.   };
  1035.  
  1036.  
  1037.   //example streams
  1038.   Uint8  u_8_A[16]={0x00,0x3F,0x10,0x80,0xFF,0x4E,0x24,0x6D,0x21,0xFE,0xED,0x86,0x3A,0xAB,0xDA,0x4C};
  1039.   Sint16 i16_A[16]={-32768,13106,-16384,6553,32767,2553,-26214,25937,22337,-13102,9553,-32467,-9830,0,-19661,-22938};
  1040.   Sint32 i32_A[16]={-2147483648,2147483647,2,547760950,-978102134,-1901782676,973752665,-2054956051,-1793070550,2100284199,1386177656,-70287364,-799099289,-594127329,1025429360,-570645197};
  1041.   float  f32_A[16]={ 0.8,-0.2, 0.0,-0.6,-0.6, 0.4, 1.0, 2.0, 0.6, 0.9, 0.8, 0.3, 0.6,-1.4,-0.1, 0.1};
  1042.   float  f32_B[16]={-0.1,-0.4, 0.1, 0.3,-0.6, 0.6, 0.6,-0.6,-0.1, 0.2,-0.2, 0.8, 0.4, 0.8, 0.4, 0.7};
  1043.  
  1044.  
  1045.   //test to and from type conversion
  1046.    //u_8
  1047.   SDL_memcpy(voiceA.bufferUser.u_8, u_8_A, 16*sizeof(Uint8));
  1048.   _kit_kmixerVoiceProcFromType(voiceA.bufferUser.u_8,voiceA.bufferConvert.f32, 16,AUDIO_U8,SDL_FALSE);
  1049.   _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.u_8, 16,AUDIO_U8,SDL_FALSE);
  1050.   for(Uint32 i=0; i<16; ++i){
  1051.     if(voiceA.bufferUser.u_8[i] != MAX(u_8_A[i],1)){
  1052.       SDL_SetError("u_8 type conv. (%u:%X!=%X)",
  1053.         i, voiceA.bufferUser.u_8[i], MAX(u_8_A[i],1) ); return -999;
  1054.     }
  1055.   }
  1056.    //i16
  1057.   SDL_memcpy(voiceA.bufferUser.i16, i16_A, 16*sizeof(Sint16));
  1058.   _kit_kmixerVoiceProcFromType(voiceA.bufferUser.i16,voiceA.bufferConvert.f32, 16,AUDIO_S16,SDL_FALSE);
  1059.   _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.i16, 16,AUDIO_S16,SDL_FALSE);
  1060.   for(Uint32 i=0; i<16; ++i){
  1061.     if(voiceA.bufferUser.i16[i] != MAX(i16_A[i],-32767)){
  1062.       SDL_SetError("i16 type conv. (%u:%i!=%i)",
  1063.         i, voiceA.bufferUser.i16[i], MAX(i16_A[i],-32767) ); return -999;
  1064.     }
  1065.   }
  1066.    //i32 (products of conversion are actually approximations with a max error of 64)
  1067.   SDL_memcpy(voiceA.bufferUser.i32, i32_A, 16*sizeof(Sint32));
  1068.   _kit_kmixerVoiceProcFromType(voiceA.bufferUser.i32,voiceA.bufferConvert.f32, 16,AUDIO_S32,SDL_FALSE);
  1069.   _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.i32, 16,AUDIO_S32,SDL_FALSE);
  1070.   for(Uint32 i=0; i<16; ++i){
  1071.     if((voiceA.bufferUser.i32[i] < (MAX(i32_A[i],-2147483647)-64)) &&
  1072.        (voiceA.bufferUser.i32[i] > (MAX(i32_A[i],-2147483647)+64)))
  1073.     {
  1074.       SDL_SetError("i32 type conv. (%u:%i!=%i)",
  1075.         i, voiceA.bufferUser.i32[i], MAX(i32_A[i],-2147483647) ); return -999;
  1076.     }
  1077.   }
  1078.    //f32
  1079.   SDL_memcpy(voiceA.bufferUser.f32, f32_A, 16*sizeof(float));
  1080.   _kit_kmixerVoiceProcFromType(voiceA.bufferUser.f32,voiceA.bufferConvert.f32, 16,AUDIO_F32,SDL_FALSE);
  1081.   _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.f32, 16,AUDIO_F32,SDL_FALSE);
  1082.   for(Uint32 i=0; i<16; ++i){
  1083.     if(voiceA.bufferUser.f32[i] != CLAMP(f32_A[i], -1.0f,1.0f)){
  1084.       SDL_SetError("f32 type conv. (%u:%.1f!=%.1f)",
  1085.         i, voiceA.bufferUser.f32[i], CLAMP(f32_A[i], -1.0f,1.0f) ); return -999;
  1086.     }
  1087.   }
  1088.  
  1089.  
  1090.   //test channel conversion
  1091.    //  mono-stereo
  1092.   _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32s, 8,_M_to_S);
  1093.   for(Uint32 i=0; i<16; i+=2){
  1094.     //kit_coreLog("%2u: %9f, %9f",i, voiceA.bufferConvert.m[i], voiceA.bufferConvert.m[i+1]);
  1095.     if(voiceA.bufferConvert.f32[i] != voiceA.bufferConvert.f32[i+1]){
  1096.       SDL_SetError("mn.->st. convert (%u:%.1f!=%.1f)",
  1097.         i, voiceA.bufferConvert.f32[i], voiceA.bufferConvert.f32[i+1] ); return -999;
  1098.     }
  1099.   }
  1100.    //stereo-mono
  1101.   _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32,  8,_S_to_M);
  1102.   for(Uint32 i=0; i<16; i+=2){
  1103.     //kit_coreLog("%2u: %9f,%9f -> %9f",i, f32_A[i],f32_A[i+1], voiceA.bufferConvert.m[i>>1]);
  1104.     if(voiceA.bufferConvert.f32[i>>1] != (f32_A[i]+f32_A[i+1])*.5f){
  1105.       SDL_SetError("st.->mn. convert (%u:%.1f!=%.1f)",
  1106.         i, voiceA.bufferConvert.f32[i>>1], (f32_A[i]+f32_A[i+1])*.5f ); return -999;
  1107.     }
  1108.   }
  1109.    //stereo-stereo
  1110.   _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32s,  8,_S_to_S);
  1111.   for(Uint32 i=0; i<16; ++i){
  1112.     //kit_coreLog("%2u: %9f",i, voiceA.bufferConvert.m[i]);
  1113.     if(voiceA.bufferConvert.f32[i] != f32_A[i]){
  1114.       SDL_SetError("st.->st. convert (%u:%.1f!=%.1f)",
  1115.         i, voiceA.bufferConvert.f32[i], f32_A[i] ); return -999;
  1116.     }
  1117.   }
  1118.    //  mono-mono
  1119.   _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32, 16,_M_to_M);
  1120.   for(Uint32 i=0; i<16; ++i){
  1121.     //kit_coreLog("%2u: %9f",i, voiceA.bufferConvert.m[i]);
  1122.     if(voiceA.bufferConvert.f32[i] != f32_A[i]){
  1123.       SDL_SetError("mn.->mn. convert (%u:%.1f!=%.1f)",
  1124.         i, voiceA.bufferConvert.f32[i], f32_A[i] ); return -999;
  1125.     }
  1126.   }
  1127.  
  1128.  
  1129.   //test VoiceProc itself here
  1130.  
  1131.  
  1132.   //test mixing (might want to add in other volume settings at some point)
  1133.   voiceA.lock=SDL_CreateMutex();
  1134.   voiceB.lock=SDL_CreateMutex();
  1135.   voiceC.lock=SDL_CreateMutex();
  1136.   kit_coreVector* ivoices=kit_coreVectorCreate(2,0,0, sizeof(_kit_kmixerVoice),0);
  1137.   if(voiceA.lock==NULL || voiceB.lock==NULL || voiceC.lock==NULL || ivoices==NULL){
  1138.     if(voiceA.lock != NULL) SDL_DestroyMutex(voiceA.lock);
  1139.     if(voiceB.lock != NULL) SDL_DestroyMutex(voiceB.lock);
  1140.     if(voiceC.lock != NULL) SDL_DestroyMutex(voiceC.lock);
  1141.     if(ivoices != NULL) kit_coreVectorDestroy(&ivoices);
  1142.   }
  1143.  
  1144.   SDL_memcpy(voiceA.bufferOutput.f32, f32_A, 16*sizeof(float));
  1145.   SDL_memcpy(voiceB.bufferOutput.f32, f32_B, 16*sizeof(float));
  1146.   _kit_kmixerVoice _ivoices[2]={voiceA,voiceB};
  1147.   memcpy(ivoices->data, _ivoices, sizeof(_kit_kmixerVoice)*2);
  1148.    //mono, 1.0,1.0
  1149.   //_kit_kmixerVoiceMix(&voiceC);
  1150.   for(Uint32 i=0; i<16; ++i){
  1151.     float mixed=voiceC.bufferInput.f32[i];
  1152.     float real=CLAMP(voiceA.bufferOutput.f32[i]+voiceB.bufferOutput.f32[i], -1.0f,1.0f);
  1153.     if(mixed != real){ SDL_SetError("mn. mixing (%u:%.1f!=%.1f)",
  1154.                          i, mixed, real ); return -999;
  1155.     }
  1156.   }
  1157.    //stereo, 1.0,1.0
  1158.   voiceA.stereoOutput=SDL_TRUE;
  1159.   voiceB.stereoOutput=SDL_TRUE;
  1160.   voiceA.spec.samples=8;
  1161.   voiceB.spec.samples=8;
  1162.   voiceC.spec.samples=8;
  1163.   //_kit_kmixerVoiceMix(&voiceC);
  1164.   for(Uint32 i=0; i<16; ++i){
  1165.     float mixed=voiceC.bufferInput.f32[i];
  1166.     float real=CLAMP(voiceA.bufferOutput.f32[i]+voiceB.bufferOutput.f32[i], -1.0f,1.0f);
  1167.     if(mixed != real){ SDL_SetError("st. mixing (%u:%.1f!=%.1f)",
  1168.                          i, mixed, real ); return -999;
  1169.     }
  1170.   }
  1171.  
  1172.   if(voiceA.lock != NULL) SDL_DestroyMutex(voiceA.lock);
  1173.   if(voiceB.lock != NULL) SDL_DestroyMutex(voiceB.lock);
  1174.   if(voiceC.lock != NULL) SDL_DestroyMutex(voiceC.lock);
  1175.   if(ivoices != NULL) kit_coreVectorDestroy(&ivoices);
  1176.  
  1177.  
  1178.   //test adding and removing possibly
  1179.  
  1180.  
  1181.   //kit_coreLog("sizeof(_kit_kmixerVoice)=%u",(unsigned int)sizeof(_kit_kmixerVoice));
  1182.  
  1183.  
  1184.   return 0;
  1185. }
  1186. void kit_kmixerVoicePrintRawOrd(kit_kmixerDevice* device){
  1187.   kit_coreVector** raw_p = &device->_raw;
  1188.   kit_coreVector** ord_p = &device->_ord;
  1189.   Uint32 rawLen = (*raw_p)->x;
  1190.   Uint32 ordLen = (*ord_p)->x;
  1191.   Uint32 maxStage = (*ord_p)->y-1;
  1192.   _kit_kmixerVoice* raw = (*raw_p)->data;
  1193.   _kit_kmixerVoice** ord = (*ord_p)->data;
  1194.  
  1195.  
  1196.   printf("\n~~~ RAW ~~~\n");
  1197.   for(Uint32 v=0; v<rawLen; ++v){
  1198.     _kit_kmixerVoice* voice = &raw[v];
  1199.     printf("--- %02u/%02u (%p) ---\n", v, rawLen-1, voice);
  1200.     if(voice->lock == NULL){ printf("  (REMOVED)\n"); continue; }
  1201.     Uint32 numInputs = 0,  *inputs = NULL;
  1202.     if(voice->inputs != NULL){
  1203.       numInputs = voice->inputs->x;
  1204.          inputs = voice->inputs->data;
  1205.     }
  1206.  
  1207.     printf("  voice%u->inputs     = %p: ",v, voice->inputs);
  1208.     if(inputs != NULL){
  1209.       printf("{\n    ");
  1210.       for(Uint32 i=0; i<numInputs; ++i){
  1211.         if(inputs[i]!=0) printf("%02u, ",inputs[i]);
  1212.         else printf("RM, "); //removed voice
  1213.         if((i+1)==numInputs) printf("\n");
  1214.         else if((i%5)==4) printf("\n    ");
  1215.       }
  1216.       printf("  }\n");
  1217.     } else printf("(NULL)\n");
  1218.  
  1219.     printf("  voice%u->output     = %2i\n",v, voice->output);
  1220.     printf("  voice%u->chainStage = %2u\n",v, voice->chainStage);
  1221.     printf("  voice%u->active     = %s\n", v, boolstr[voice->active]);
  1222.     printf("  voice%u->spec       = {\n",  v);
  1223.     printf("    .remove   = %p\n",voice->spec.remove);
  1224.     printf("    .callback = %p\n",voice->spec.callback);
  1225.     printf("    .userdata = %p\n",voice->spec.userdata);
  1226.     printf("    .freq     = %i\n",voice->spec.freq);
  1227.     printf("    ._size    = %u\n",voice->spec._size);
  1228.     printf("    .stereo   = %s\n",boolstr[voice->spec.stereo]);
  1229.     printf("    .samples  = %u\n",voice->spec.samples);
  1230.     printf("    .format   = %X\n",voice->spec.format);
  1231.     printf("  }\n");
  1232.  
  1233.     printf("\n");
  1234.   }
  1235.  
  1236.  
  1237.   printf("\n~~~ ORD ~~~\n");
  1238.   for(Uint32 yi=maxStage; yi!=U32_MAX; --yi){
  1239.     printf("stage %02u:  ", yi);
  1240.     for(Uint32 xi=0; xi<ordLen; ++xi){
  1241.       _kit_kmixerVoice* voice = ord[xi + yi*ordLen];
  1242.  
  1243.       if(voice == NULL) printf("NL, ");
  1244.       else if(voice->lock == NULL) printf("RM, ");
  1245.       else printf("%02u, ",voice->index);
  1246.     }
  1247.     printf("\n");
  1248.   }
  1249.   printf("\n");
  1250.  
  1251. }
  1252. #else
  1253. int kit_kmixerVoice_Test(){
  1254.   SDL_SetError("!defined(_KIT_KMIXER_DEBUG)");
  1255.   return 999;
  1256. }
  1257. void kit_kmixerVoicePrintRawOrd(kit_kmixerDevice* device){}
  1258. #endif
  1259.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement