Advertisement
Kitomas

kit_sdl2_kmixerVoice.c as of 2023-10-12

Oct 12th, 2023
815
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 38.73 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.   samples_len >>= !voiceO->spec.stereo;
  173.  
  174.  
  175.   for(Uint32 v=0; v<inputs_len; ++v){
  176.     _kit_kmixerVoice* voiceI = &raw[ inputs[v] ];
  177.     if(voiceI->lock == NULL){ inputs[v] = 0; continue; }
  178.     SDL_LockMutex(voiceI->lock);
  179.     kit_acodecPCM_F32S* samplesI = voiceI->bufferOutput.f32s;
  180.  
  181.     float volL = CLAMP(voiceI->volL, 0.0f,1.0f);
  182.     float volR = MIN(voiceI->volR, 1.0f);
  183.     if(!voiceI->stereoOutput || volR<0) volR = volL;
  184.  
  185.     if(     volL==0.0f && volR==0.0f) continue; //volume is muted; skip
  186.     else if(volL==1.0f && volR==1.0f) goto _normal_volume; //because sample*1=sample
  187.     else if(volL>=0.0f){
  188.       for(Uint32 i=0; i<samples_len; ++i){
  189.         samplesO[i].l += samplesI[i].l*volL;
  190.         samplesO[i].r += samplesI[i].r*volR;
  191.       }
  192.  
  193.     } else { _normal_volume:
  194.       for(Uint32 i=0; i<samples_len; ++i){
  195.         samplesO[i].l += samplesI[i].l;
  196.         samplesO[i].r += samplesI[i].r;
  197.       }
  198.  
  199.     }
  200.  
  201.     SDL_UnlockMutex(voiceI->lock);
  202.   }
  203.  
  204.  
  205.   //hard clip output samples to between -1.0f and 1.0f
  206.   for(Uint32 i=0; i<samples_len; ++i){
  207.     float sampleL = samplesO[i].l;
  208.     float sampleR = samplesO[i].r;
  209.     samplesO[i].l = CLAMP(sampleL, -1.0f,1.0f);
  210.     samplesO[i].r = CLAMP(sampleR, -1.0f,1.0f);
  211.   }
  212. }
  213. //(this should only be called if the voice has inputs)
  214. int _kit_kmixerVoiceMix(void* data){ //(this is an SDL_ThreadFunction)
  215.   _kit_kmixerVoice* voiceO = data;
  216.   if(voiceO == NULL) return 1; //skip if the voice is NULL
  217.   if(voiceO->lock == NULL) return 2; //skip in case voice was removed
  218.  
  219.   SDL_LockMutex(voiceO->lock);
  220.   //don't mix if voice has no inputs...
  221.   if(voiceO->inputs == NULL){
  222.     size_t bufferSize = (voiceO->spec.samples*sizeof(float)) << voiceO->spec.stereo;
  223.     //...but still make sure the input buffer is zeroed out
  224.     kit_coreMemset(voiceO->bufferInput.data, 0, bufferSize);
  225.     SDL_UnlockMutex(voiceO->lock);
  226.     return 3;
  227.   }
  228.  
  229.   _kit_kmixerVoiceMixFallback(voiceO);
  230.  
  231.   SDL_UnlockMutex(voiceO->lock);
  232.   return 0;
  233. }
  234.  
  235.  
  236.  
  237.  
  238. ///used to check whether an element in the raw voice list is valid or not
  239. SDL_bool _kit_kmixerVoiceRawUnitCallback(void* unit, Uint32 size){
  240.   _kit_kmixerVoice* voice = unit;
  241.   return voice->lock == NULL;
  242. }
  243.  
  244.  
  245.  
  246. //same thing, but with an element in ord instead of raw
  247. SDL_bool _kit_kmixerVoiceOrdUnitCallback(void* unit, Uint32 size){
  248.   _kit_kmixerVoice** voice_p = unit;
  249.   if(*voice_p == NULL) return SDL_TRUE;
  250.   return (*voice_p)->lock == NULL;
  251. }
  252.  
  253.  
  254.  
  255.  
  256. //should be called when voices are created, destroyed, or altered
  257. int _kit_kmixerVoiceRebuildOrd(kit_kmixerDevice* device){
  258.   kit_coreVector* ord_new = NULL;
  259.   kit_coreVector**  ord_p = &device->_ord;
  260.   kit_coreVector**  raw_p = &device->_raw;
  261.  
  262.   _kit_kmixerVoice* raw = (*raw_p)->data;
  263.   Uint32      numVoices = (*raw_p)->x;
  264.  
  265.   Uint32  hiStageLen =    0; //ord->x
  266.   Uint32  hiStage    =    0; //ord->y
  267.   Uint32* stageLens  = NULL; //temporary space for stage lengths
  268.  
  269.  
  270.   //find highest chain stage (for ord's y axis)
  271.   for(Uint32 v=0; v<numVoices; ++v){
  272.     if(raw[v].lock == NULL) continue; //skip any removed voice
  273.     if(hiStage < raw[v].chainStage) hiStage = raw[v].chainStage;
  274.   }
  275.   ++hiStage; //should now equal ord->y
  276.  
  277.  
  278.   //find highest index of a chain stage (for ord's x axis)
  279.   _IF_SDLERR(kit_coreRealloc(&stageLens,0,hiStage*sizeof(Uint32)),;,"!stageLens")
  280.   for(Uint32 v=0; v<numVoices; ++v){
  281.     if(raw[v].lock == NULL) continue; //skip any removed voice
  282.     Uint32 stageLen = ++stageLens[raw[v].chainStage];
  283.     if(hiStageLen < stageLen) hiStageLen = stageLen;
  284.   }
  285.   SAFE_FREE(stageLens);
  286.   if(!hiStageLen) hiStageLen = 1; //vectors can't have sizes of 0
  287.  
  288.  
  289.   //create new ord vector with new dimensions
  290.   ord_new = kit_coreVectorCreate(hiStageLen,hiStage,1, sizeof(_kit_kmixerVoice*),0);
  291.   _IF_SDLERR(ord_new==NULL,;,"!ord_new")
  292.   kit_coreVectorDestroy(ord_p); //doink the old one
  293.   *ord_p = ord_new;
  294.  
  295.  
  296.   //fill ord with new references from raw
  297.   for(Uint32 v=0; v<numVoices; ++v){
  298.     if(raw[v].lock == NULL) continue; //skip any removed voice
  299.     _kit_kmixerVoice* voiceRef = &raw[v];
  300.     Uint32 chainStage = voiceRef->chainStage;
  301.     _IF_GOTO_ERROR(kit_coreVectorInsert(ord_p, &voiceRef, chainStage,0,
  302.                                         _kit_kmixerVoiceOrdUnitCallback)==U32_MAX,;)
  303.   }
  304.  
  305.  
  306.   /*!err*/ return  0;
  307.   _error_: return -1;
  308. }
  309.  
  310.  
  311.  
  312.  
  313. //assumes device is already locked
  314. int _kit_kmixerVoiceRemoveInput(kit_kmixerDevice* device,
  315.                                 Uint32 outputID, Uint32 inputID)
  316. {
  317.   kit_coreVector**   raw_p = &device->_raw;
  318.   _kit_kmixerVoice* voiceO = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, outputID);
  319.   Uint32* inputs     = voiceO->inputs->data;
  320.   Uint32  inputs_len = voiceO->inputs->x;
  321.  
  322.   _IF_GOTO_ERROR(SDL_LockMutex(voiceO->lock),;)
  323.  
  324.  
  325.   //remove input voice from output voice's input list
  326.   for(Uint32 v=0; v<inputs_len; ++v){
  327.     if(inputs[v] == inputID){
  328.       inputs[v] = 0; break;
  329.     }
  330.   }
  331.  
  332.  
  333.   //trim input list to make sure only active inputs are included
  334.   _IF_GOTO_ERROR(kit_coreVectorTrim(&voiceO->inputs,'x',NULL),;)
  335.   //destroy input list if all inputs have been removed
  336.   if(!voiceO->inputs->lens[0]) kit_coreVectorDestroy(&voiceO->inputs);
  337.  
  338.  
  339.   _IF_GOTO_ERROR(SDL_UnlockMutex(voiceO->lock),;)
  340.  
  341.   /*!err*/ return  0;
  342.   _error_: return -1;
  343. }
  344.  
  345.  
  346.  
  347. //device, input voice and output voice are locked here
  348.  //(also, input voice's lock should be created before calling this)
  349. int _kit_kmixerVoiceAddInput(kit_kmixerDevice* device,
  350.                              Uint32 inputID, Uint32 outputID)
  351. {
  352.   kit_coreVector**   raw_p = &device->_raw;
  353.   _kit_kmixerVoice* voiceI = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, inputID);
  354.   _kit_kmixerVoice* voiceO = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, outputID);
  355.  
  356.  
  357.   //set input voice accordingly
  358.   _IF_GOTO_ERROR(SDL_LockMutex(voiceI->lock),;)
  359.  
  360.   voiceI->output       = voiceO->index; // = outputID basically
  361.   //set chain processing stage one higher,
  362.    //to ensure this voice is processed before the output
  363.   voiceI->chainStage   = voiceO->chainStage+1;
  364.   voiceI->stereoOutput = voiceO->spec.stereo;
  365.  
  366.   _IF_GOTO_ERROR(SDL_UnlockMutex(voiceI->lock),;)
  367.  
  368.  
  369.   //create input list in output voice if it's NULL
  370.   if(voiceO->inputs == NULL){
  371.     voiceO->inputs = kit_coreVectorCreate(1,1,1, sizeof(Uint32),0);
  372.     _IF_GOTO_ERROR(voiceO->inputs==NULL,;)
  373.   }
  374.  
  375.  
  376.   //add input to the output voice's input list
  377.   _IF_GOTO_ERROR(SDL_LockMutex(voiceO->lock),;)
  378.  
  379.    //first, check to see if input is already in the list...
  380.   Uint32* inputs     = voiceO->inputs->data;
  381.   Uint32  inputs_len = voiceO->inputs->x;
  382.   SDL_bool found = SDL_FALSE;
  383.   for(Uint32 i=0; i<inputs_len; ++i){
  384.     if(inputs[i] == inputID){
  385.       found = SDL_TRUE; break;
  386.     }
  387.   }
  388.  
  389.    //...inserting only if the input was not found in the list
  390.   if(!found) _IF_GOTO_ERROR(kit_coreVectorInsert(&voiceO->inputs, &inputID, 0,0, NULL)==U32_MAX,;)
  391.  
  392.   _IF_GOTO_ERROR(SDL_UnlockMutex(voiceO->lock),;)
  393.  
  394.  
  395.   /*!err*/ return  0;
  396.   _error_: return -1;
  397. }
  398.  
  399.  
  400.  
  401.  
  402. int kit_kmixerVoiceRemove(kit_kmixerDevice* device, Uint32 voiceID){
  403.   _DEVICE_VALIDITY_CHECK(0)
  404.   //only allow voice 0 to be removed when device->_closing is set
  405.   _IF_SDLERR(!voiceID && !device->_closing,;,"cannot remove voice 0")
  406.  
  407.   //if bit 31 is set, call is assumed to be the result of recursion
  408.   SDL_bool rootCall = (!(voiceID&U32_MSb)) ? SDL_TRUE : SDL_FALSE;
  409.   voiceID &= I32_MAX; //unset bit 31 now that rootCall is set
  410.  
  411.  
  412.   kit_coreVector**   raw_p = &device->_raw;
  413.   _IF_SDLERR(voiceID>=(*raw_p)->x,;,"voiceID out of bounds")
  414.   _kit_kmixerVoice* voiceI = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, voiceID);
  415.   _IF_GOTO(voiceI->lock==NULL,_noerr_,;) //return normally if voice already removed
  416.   _IF_GOTO_ERROR(SDL_LockMutex(voiceI->lock),;)
  417.  
  418.  
  419.   //loop through and remove any inputs the voice might have (recursive)
  420.   if(voiceI->inputs != NULL){
  421.     Uint32*    inputs     = voiceI->inputs->data;
  422.     Uint32     inputs_len = voiceI->inputs->x;
  423.     _kit_kmixerVoice* raw = (*raw_p)->data;
  424.  
  425.     for(Uint32 i=0; i<inputs_len; ++i){
  426.       Uint32 index = inputs[i];
  427.       if(!index) continue; //an index of 0 indicates a voice that was already removed
  428.       if(raw[index].lock != NULL) //(bit 31 is set to indicate recursion)
  429.         _IF_GOTO_ERROR(kit_kmixerVoiceRemove(device,U32_MSb|index),;)
  430.     }
  431.  
  432.     //(kit_coreVectorDestroy automatically sets pointer to NULL)
  433.     _IF_GOTO_ERROR(kit_coreVectorDestroy(&voiceI->inputs),;)
  434.   }
  435.  
  436.  
  437.   //free buffers
  438.   SAFE_FREE(voiceI->bufferInput.data);
  439.   SAFE_FREE(voiceI->bufferUser.data);
  440.   SAFE_FREE(voiceI->bufferConvert.data);
  441.   SAFE_FREE(voiceI->bufferOutput.data);
  442.  
  443.  
  444.   //call the user's 'userdata removal' callback
  445.   if(voiceI->spec.remove != NULL) voiceI->spec.remove(voiceI->spec.userdata);
  446.  
  447.  
  448.   //destroy lock
  449.   _IF_GOTO_ERROR(SDL_UnlockMutex(voiceI->lock),;)
  450.   SDL_DestroyMutex(voiceI->lock);
  451.   voiceI->lock       = NULL; //a mutex of NULL indicates a removed voice
  452.   voiceI->chainStage =    0; //(as to not confuse VoiceRebuildOrd)
  453.  
  454.  
  455.   if(rootCall){ //if this call is not the result of recursion
  456.     if(!device->_closing) kit_kmixerDeviceLock(device, SDL_TRUE);
  457.  
  458.     //trim raw and rebuild ord
  459.     _IF_GOTO_ERROR(kit_coreVectorTrim(raw_p,'x',_kit_kmixerVoiceRawUnitCallback),;)
  460.     _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
  461.  
  462.     //remove input from output's input list
  463.     Uint32 outputID = VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, voiceID).output;
  464.  
  465.     if(outputID != U32_MAX){ //(only if output != -1, which should only be possible for voice 0)
  466.       _IF_GOTO_ERROR(_kit_kmixerVoiceRemoveInput(device, outputID,voiceID),
  467.                      kit_kmixerDeviceLock(device, SDL_FALSE))
  468.     }
  469.  
  470.     if(!device->_closing) kit_kmixerDeviceLock(device, SDL_FALSE);
  471.   }
  472.  
  473.  
  474.   _noerr_: return  0;
  475.   _error_: return -1;
  476. }
  477.  
  478.  
  479.  
  480. Uint32 kit_kmixerVoiceAdd(kit_kmixerDevice* device, kit_kmixerVoiceSpec* vspec,
  481.                           Uint32 outputVoiceID)
  482. {
  483.   Uint32 newIndex = 0; //0 for error by default
  484.   _kit_kmixerVoice  voice  = { .lock = NULL }; //voice struct to be copied to raw
  485.   _kit_kmixerVoice* voiceI = NULL; //reference to voice inside raw
  486.  
  487.   SDL_bool inRaw   = SDL_FALSE; //set to true if successfully inserted into raw
  488.   SDL_bool success = SDL_FALSE;
  489.   SDL_bool locked  = SDL_FALSE;
  490.   _DEVICE_VALIDITY_CHECK(0)
  491.   _IF_SDLERR(vspec==NULL,;,"!vspec")
  492.  
  493.   _IF_SDLERR(vspec->callback==NULL,;,"!vspec->callback")
  494.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_TRUE)<0,;)
  495.   locked = SDL_TRUE;
  496.  
  497.   //get reference to output voice
  498.   kit_coreVector** raw_p = &device->_raw;
  499.   _IF_SDLERR(outputVoiceID>I32_MAX,;,"outputVoiceID < 0")
  500.   _IF_SDLERR(outputVoiceID>=(*raw_p)->x,;,"outputVoiceID out of bounds")
  501.   _kit_kmixerVoice* voiceO = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, outputVoiceID);
  502.   _IF_SDLERR(voiceO->lock==NULL,;,"output voice is nonexistent")
  503.  
  504.  
  505.   //fill in info for voice spec and the voice struct itself
  506.   _IF_GOTO_ERROR(_kit_kmixerVoiceAddFillSpec(device, vspec),;)
  507.   _IF_GOTO_ERROR(_kit_kmixerVoiceAddFillVoice(vspec, voiceO, &voice),;)
  508.   voice.device = device; //the only thing not filled in by FillVoice
  509.  
  510.  
  511.   //add voice to raw
  512.   newIndex = kit_coreVectorInsert(raw_p, &voice, 0,0, _kit_kmixerVoiceRawUnitCallback);
  513.   _IF_GOTO_ERROR(newIndex==U32_MAX,;)
  514.   voiceI = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, newIndex);
  515.   voiceI->index = newIndex;
  516.   inRaw = SDL_TRUE;
  517.  
  518.  
  519.   //add voice to output's input list
  520.   _IF_GOTO_ERROR(_kit_kmixerVoiceAddInput(device, newIndex, outputVoiceID),;)
  521.  
  522.  
  523.   //finally, rebuild ord to reflect new state of raw
  524.   _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
  525.  
  526.   _noerr_:
  527.   success = SDL_TRUE;
  528.   _error_:
  529.   if(!success){
  530.     if(!inRaw) voiceI = &voice;
  531.  
  532.     if(voiceI->lock != NULL) SDL_DestroyMutex(voiceI->lock);
  533.     kit_coreVectorDestroy(&voiceI->inputs);
  534.     SAFE_FREE(voiceI->bufferInput.data);
  535.     SAFE_FREE(voiceI->bufferUser.data);
  536.     SAFE_FREE(voiceI->bufferConvert.data);
  537.     SAFE_FREE(voiceI->bufferOutput.data);
  538.     voiceI->lock = NULL;
  539.  
  540.     //(make newIndex indicate an error again, regardless of its prev. value)
  541.     newIndex = 0;
  542.   }
  543.   if(locked) kit_kmixerDeviceLock(device, SDL_FALSE);
  544.   return newIndex;
  545. }
  546.  
  547.  
  548.  
  549.  
  550. //updates a voice's chain stage after redirecting
  551. void _kit_kmixerVoiceCascadeChainStage(kit_kmixerDevice* device, Uint32 voiceID){
  552.   _kit_kmixerVoice* raw = device->_raw->data;
  553.   _kit_kmixerVoice* voiceI = &raw[voiceID];
  554.   _kit_kmixerVoice* voiceO = &raw[voiceI->output];
  555.  
  556.   //set input voice's chain stage to one higher than the output
  557.   voiceI->chainStage = voiceO->chainStage+1;
  558.  
  559.   //if input voice itself has inputs, call VoiceCascade on all of them
  560.    //(this should be recursive)
  561.   if(voiceI->inputs != NULL){
  562.     Uint32* inputs     = voiceI->inputs->data;
  563.     Uint32  inputs_len = voiceI->inputs->x;
  564.     for(Uint32 i=0; i<inputs_len; ++i){
  565.       if(!inputs[i]) continue; //skip any invalid or removed voice
  566.       _kit_kmixerVoiceCascadeChainStage(device,inputs[i]);
  567.     }
  568.   }
  569. }
  570.  
  571.  
  572.  
  573. int kit_kmixerVoiceRedirect(kit_kmixerDevice* device,
  574.                             Uint32 inputVoiceID, Uint32 outputVoiceID)
  575. {
  576.   int returnStatus = 0;
  577.   SDL_bool locked = SDL_FALSE;
  578.   _DEVICE_VALIDITY_CHECK(0)
  579.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_TRUE)<0,;)
  580.   locked = SDL_TRUE;
  581.  
  582.   kit_coreVector** raw_p = &device->_raw;
  583.   _IF_SDLERR(!inputVoiceID,;,"cannot redirect voice 0")
  584.   _IF_SDLERR( inputVoiceID>I32_MAX,;,"inputVoiceID < 0")
  585.   _IF_SDLERR(outputVoiceID>I32_MAX,;,"outputVoiceID < 0")
  586.   _IF_SDLERR( inputVoiceID>=(*raw_p)->x,;,"inputVoiceID out of bounds")
  587.   _IF_SDLERR(outputVoiceID>=(*raw_p)->x,;,"outputVoiceID out of bounds")
  588.   _kit_kmixerVoice* voiceI = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, inputVoiceID);
  589.   _kit_kmixerVoice* voiceO = &VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, outputVoiceID);
  590.   _IF_SDLERR(voiceI->lock==NULL,;,"input voice is nonexistent")
  591.   _IF_SDLERR(voiceO->lock==NULL,;,"output voice is nonexistent")
  592.   _IF_SDLERR(voiceO->output==inputVoiceID,;,"output can't be circular")
  593.   Uint32 outputVoiceID_old = voiceI->output;
  594.  
  595.  
  596.   //disconnect from the old output, before connecting to the new output
  597.   _IF_GOTO_ERROR(_kit_kmixerVoiceRemoveInput(device, outputVoiceID_old, inputVoiceID),;)
  598.   _IF_GOTO_ERROR(_kit_kmixerVoiceAddInput(device, inputVoiceID, outputVoiceID),;)
  599.  
  600.  
  601.   //update every chainStage value up the voice chain,
  602.    //to accomodate the stage of the new output
  603.   _kit_kmixerVoiceCascadeChainStage(device,inputVoiceID);
  604.  
  605.  
  606.   //update ord to reflect changes
  607.   _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
  608.  
  609.  
  610.   _noerr_: ++returnStatus;
  611.   _error_: --returnStatus;
  612.   if(locked) _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_FALSE)<0,;)
  613.   return returnStatus;
  614. }
  615.  
  616.  
  617.  
  618.  
  619. _kit_kmixerVoice* _kit_kmixerVoiceQuery(kit_kmixerDevice* device, Uint32 voiceID, SDL_bool lock){
  620.   _kit_kmixerVoice* voice;
  621.   _IF_SDLERR(device==NULL,;,"device cannot be NULL")
  622.   _IF_SDLERR(device->_magic.num!=_DEV_MAGIC_NUM,;,"invalid device struct")
  623.  
  624.   _IF_SDLERR(voiceID>=device->_raw->x,;,"voiceID out of bounds")
  625.   voice = &VECTOR_INDEX_C(_kit_kmixerVoice, device->_raw, voiceID);
  626.   if(lock && SDL_LockMutex(voice->lock)<0) voice = NULL;
  627.  
  628.   _error_:
  629.   return voice;
  630. }
  631.  
  632.  
  633.  
  634.  
  635. Uint32 kit_kmixerVoiceGetNumInputs(kit_kmixerDevice* device, Uint32 voiceID){
  636.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_FALSE);
  637.   _IF_GOTO_ERROR(voice==NULL,;)
  638.   if(voice->inputs == NULL) return 0;
  639.   /*!err*/ return voice->inputs->x;
  640.   _error_: return U32_MAX;
  641. }
  642.  
  643.  
  644.  
  645. kit_coreVector* kit_kmixerVoiceGetInputs(kit_kmixerDevice* device, Uint32 voiceID){
  646.   kit_coreVector* inputs = NULL;
  647.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_FALSE);
  648.   _IF_GOTO_ERROR(voice==NULL,;)
  649.  
  650.   _IF_SDLERR(voice->inputs==NULL,;,"no inputs found")
  651.   inputs = kit_coreVectorCopy(voice->inputs);
  652.  
  653.   _error_:
  654.   return inputs;
  655. }
  656.  
  657.  
  658.  
  659. Uint32 kit_kmixerVoiceGetOutput(kit_kmixerDevice* device, Uint32 voiceID){
  660.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_FALSE);
  661.   _IF_GOTO_ERROR(voice==NULL,;)
  662.   _IF_SDLERR(voice->output==U32_MAX,;,"voice 0 has no output!")
  663.   /*!err*/ return voice->output;
  664.   _error_: return U32_MAX;
  665. }
  666.  
  667.  
  668.  
  669.  
  670. Uint32 kit_kmixerVoiceGetTimeStamp(kit_kmixerDevice* device, Uint32 voiceID){
  671.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_FALSE);
  672.   _IF_GOTO_ERROR(voice==NULL,;)
  673.   /*!err*/ return voice->timeStamp;
  674.   _error_: return U32_MAX;
  675. }
  676.  
  677.  
  678.  
  679. Uint32 kit_kmixerVoiceGetChainStage(kit_kmixerDevice* device, Uint32 voiceID){
  680.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_FALSE);
  681.   _IF_GOTO_ERROR(voice==NULL,;)
  682.   /*!err*/ return voice->chainStage;
  683.   _error_: return U32_MAX;
  684. }
  685.  
  686.  
  687.  
  688.  
  689. kit_kmixerVoiceSpec kit_kmixerVoiceGetSpec(kit_kmixerDevice* device, Uint32 voiceID){
  690.   kit_kmixerVoiceSpec vspec = {0};
  691.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_FALSE);
  692.   _IF_GOTO_ERROR(voice==NULL,;)
  693.  
  694.   vspec = voice->spec;
  695.  
  696.   _error_:
  697.   return vspec;
  698. }
  699.  
  700.  
  701.  
  702. int kit_kmixerVoiceSetSpecRemove(kit_kmixerDevice* device, Uint32 voiceID,
  703.                                  kit_kmixerVoiceRemoveCallback remove)
  704. {
  705.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_TRUE);
  706.   _IF_GOTO_ERROR(voice==NULL,;)
  707.  
  708.   voice->spec.remove = remove;
  709.  
  710.   _IF_GOTO_ERROR(SDL_UnlockMutex(voice->lock)<0,;)
  711.   /*!err*/ return  0;
  712.   _error_: return -1;
  713. }
  714.  
  715.  
  716.  
  717. int kit_kmixerVoiceSetSpecCallback(kit_kmixerDevice* device, Uint32 voiceID,
  718.                                    kit_kmixerVoiceCallback callback)
  719. {
  720.   //(remove and userdata can be NULL, but the voice callback itself cannot)
  721.   _IF_SDLERR(callback==NULL,;,"!callback")
  722.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_TRUE);
  723.   _IF_GOTO_ERROR(voice==NULL,;)
  724.  
  725.   voice->spec.callback = callback;
  726.  
  727.   _IF_GOTO_ERROR(SDL_UnlockMutex(voice->lock)<0,;)
  728.   /*!err*/ return  0;
  729.   _error_: return -1;
  730. }
  731.  
  732.  
  733.  
  734. int kit_kmixerVoiceSetSpecUserdata(kit_kmixerDevice* device, Uint32 voiceID, void* userdata){
  735.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_TRUE);
  736.   _IF_GOTO_ERROR(voice==NULL,;)
  737.  
  738.   voice->spec.userdata = userdata;
  739.  
  740.   _IF_GOTO_ERROR(SDL_UnlockMutex(voice->lock)<0,;)
  741.   /*!err*/ return  0;
  742.   _error_: return -1;
  743. }
  744.  
  745.  
  746.  
  747.  
  748. float kit_kmixerVoiceGetVolL(kit_kmixerDevice* device, Uint32 voiceID){
  749.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_FALSE);
  750.   _IF_GOTO_ERROR(voice==NULL,;)
  751.   /*!err*/ return voice->volL;
  752.   _error_: return NAN;
  753. }
  754.  
  755.  
  756.  
  757. float kit_kmixerVoiceGetVolR(kit_kmixerDevice* device, Uint32 voiceID){
  758.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_FALSE);
  759.   _IF_GOTO_ERROR(voice==NULL,;)
  760.   /*!err*/ return voice->volR;
  761.   _error_: return NAN;
  762. }
  763.  
  764.  
  765.  
  766. int kit_kmixerVoiceSetVolL(kit_kmixerDevice* device, Uint32 voiceID, float volL){
  767.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_TRUE);
  768.   _IF_GOTO_ERROR(voice==NULL,;)
  769.  
  770.   voice->volL = volL;
  771.  
  772.   _IF_GOTO_ERROR(SDL_UnlockMutex(voice->lock)<0,;)
  773.   /*!err*/ return  0;
  774.   _error_: return -1;
  775. }
  776.  
  777.  
  778.  
  779. int kit_kmixerVoiceSetVolR(kit_kmixerDevice* device, Uint32 voiceID, float volR){
  780.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_TRUE);
  781.   _IF_GOTO_ERROR(voice==NULL,;)
  782.  
  783.   voice->volR = volR;
  784.  
  785.   _IF_GOTO_ERROR(SDL_UnlockMutex(voice->lock)<0,;)
  786.   /*!err*/ return  0;
  787.   _error_: return -1;
  788. }
  789.  
  790.  
  791.  
  792. int kit_kmixerVoiceSetVolume(kit_kmixerDevice* device, Uint32 voiceID, float volL, float volR){
  793.   _kit_kmixerVoice* voice = _kit_kmixerVoiceQuery(device, voiceID, SDL_TRUE);
  794.   _IF_GOTO_ERROR(voice==NULL,;)
  795.  
  796.   voice->volL = volL;
  797.   voice->volR = volR;
  798.  
  799.   _IF_GOTO_ERROR(SDL_UnlockMutex(voice->lock)<0,;)
  800.   /*!err*/ return  0;
  801.   _error_: return -1;
  802. }
  803.  
  804.  
  805.  
  806.  
  807. #if defined(_KIT_KMIXER_DEBUG) || defined(_KIT_ALL_DEBUG)
  808. void _kit_kmixerVoice_TestCallback(void* userdata, void* _stream, int size, SDL_bool hasInput){
  809. }
  810. /*
  811. because kmixer compiles with -O3, i get this error if i attempt to compile the test:
  812. "warning:  may be used uninitialized in this function [-Wmaybe-uninitialized]|"
  813. i have very little doubt that this is a bug, so i can't do much about it other than
  814. turn down optimization for this specific function
  815. */
  816. //(for some reason, it started working again after i added some seemingly
  817.  //unrelated stuff, so i'll comment this out for now)
  818. //__attribute__((optimize("-O0")))
  819. int kit_kmixerVoice_Test(){
  820.   float bufferInputA[16], bufferUserA[16], bufferConvertA[16], bufferOutputA[16];
  821.   float bufferInputB[16], bufferUserB[16], bufferConvertB[16], bufferOutputB[16];
  822.   float bufferInputC[16], bufferUserC[16], bufferConvertC[16], bufferOutputC[16];
  823.  
  824.  
  825.   _kit_kmixerVoice voiceA={
  826.     .spec={
  827.       .callback = _kit_kmixerVoice_TestCallback,
  828.       .userdata = NULL,
  829.       .freq     = 44100,
  830.       ._size    = 16*sizeof(float),
  831.       .stereo   = SDL_FALSE,
  832.       .samples  = 16,
  833.       .format   = AUDIO_F32
  834.     },
  835.  
  836.     .bufferInput   = { .data=bufferInputA   },
  837.     .bufferUser    = { .data=bufferUserA    },
  838.     .bufferConvert = { .data=bufferConvertA },
  839.     .bufferOutput  = { .data=bufferOutputA  },
  840.  
  841.     .inputs = NULL,
  842.     .lock   = NULL,
  843.  
  844.     .chainStage = 2,
  845.     .index      = 3,
  846.  
  847.     .volL = 1.0f,
  848.     .volR = 1.0f,
  849.  
  850.     .stereoOutput = SDL_FALSE,
  851.   };
  852.  
  853.   _kit_kmixerVoice voiceB={
  854.     .spec={
  855.       .callback = _kit_kmixerVoice_TestCallback,
  856.       .userdata = NULL,
  857.       .freq     = 44100,
  858.       ._size    = 16*sizeof(float),
  859.       .stereo   = SDL_FALSE,
  860.       .samples  = 16,
  861.       .format   = AUDIO_F32
  862.     },
  863.  
  864.     .bufferInput   = { .data=bufferInputB   },
  865.     .bufferUser    = { .data=bufferUserB    },
  866.     .bufferConvert = { .data=bufferConvertB },
  867.     .bufferOutput  = { .data=bufferOutputB  },
  868.  
  869.     .inputs = NULL,
  870.     .lock   = NULL,
  871.  
  872.     .chainStage = 2,
  873.     .index      = 2,
  874.  
  875.     .volL = 1.0f,
  876.     .volR = 1.0f,
  877.  
  878.     .stereoOutput = SDL_FALSE,
  879.   };
  880.  
  881.   _kit_kmixerVoice voiceC={
  882.     .spec={
  883.       .callback = _kit_kmixerVoice_TestCallback,
  884.       .userdata = NULL,
  885.       .freq     = 44100,
  886.       ._size    = 16*sizeof(float),
  887.       .stereo   = SDL_FALSE,
  888.       .samples  = 16,
  889.       .format   = AUDIO_F32
  890.     },
  891.  
  892.     .bufferInput   = { .data=bufferInputC   },
  893.     .bufferUser    = { .data=bufferUserC    },
  894.     .bufferConvert = { .data=bufferConvertC },
  895.     .bufferOutput  = { .data=bufferOutputC  },
  896.  
  897.     .inputs = NULL,
  898.     .lock   = NULL,
  899.  
  900.     .chainStage = 1,
  901.     .index      = 1,
  902.  
  903.     .volL = 1.0f,
  904.     .volR = 1.0f,
  905.  
  906.     .stereoOutput = SDL_FALSE,
  907.   };
  908.  
  909.  
  910.   //example streams
  911.   Uint8  u_8_A[16]={0x00,0x3F,0x10,0x80,0xFF,0x4E,0x24,0x6D,0x21,0xFE,0xED,0x86,0x3A,0xAB,0xDA,0x4C};
  912.   Sint16 i16_A[16]={-32768,13106,-16384,6553,32767,2553,-26214,25937,22337,-13102,9553,-32467,-9830,0,-19661,-22938};
  913.   Sint32 i32_A[16]={-2147483648,2147483647,2,547760950,-978102134,-1901782676,973752665,-2054956051,-1793070550,2100284199,1386177656,-70287364,-799099289,-594127329,1025429360,-570645197};
  914.   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};
  915.   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};
  916.  
  917.  
  918.   //test to and from type conversion
  919.    //u_8
  920.   SDL_memcpy(voiceA.bufferUser.u_8, u_8_A, 16*sizeof(Uint8));
  921.   _kit_kmixerVoiceProcFromType(voiceA.bufferUser.u_8,voiceA.bufferConvert.f32, 16,AUDIO_U8,SDL_FALSE);
  922.   _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.u_8, 16,AUDIO_U8,SDL_FALSE);
  923.   for(Uint32 i=0; i<16; ++i){
  924.     if(voiceA.bufferUser.u_8[i] != MAX(u_8_A[i],1)){
  925.       SDL_SetError("u_8 type conv. (%u:%X!=%X)",
  926.         i, voiceA.bufferUser.u_8[i], MAX(u_8_A[i],1) ); return -999;
  927.     }
  928.   }
  929.    //i16
  930.   SDL_memcpy(voiceA.bufferUser.i16, i16_A, 16*sizeof(Sint16));
  931.   _kit_kmixerVoiceProcFromType(voiceA.bufferUser.i16,voiceA.bufferConvert.f32, 16,AUDIO_S16,SDL_FALSE);
  932.   _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.i16, 16,AUDIO_S16,SDL_FALSE);
  933.   for(Uint32 i=0; i<16; ++i){
  934.     if(voiceA.bufferUser.i16[i] != MAX(i16_A[i],-32767)){
  935.       SDL_SetError("i16 type conv. (%u:%i!=%i)",
  936.         i, voiceA.bufferUser.i16[i], MAX(i16_A[i],-32767) ); return -999;
  937.     }
  938.   }
  939.    //i32 (products of conversion are actually approximations with a max error of 64)
  940.   SDL_memcpy(voiceA.bufferUser.i32, i32_A, 16*sizeof(Sint32));
  941.   _kit_kmixerVoiceProcFromType(voiceA.bufferUser.i32,voiceA.bufferConvert.f32, 16,AUDIO_S32,SDL_FALSE);
  942.   _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.i32, 16,AUDIO_S32,SDL_FALSE);
  943.   for(Uint32 i=0; i<16; ++i){
  944.     if((voiceA.bufferUser.i32[i] < (MAX(i32_A[i],-2147483647)-64)) &&
  945.        (voiceA.bufferUser.i32[i] > (MAX(i32_A[i],-2147483647)+64)))
  946.     {
  947.       SDL_SetError("i32 type conv. (%u:%i!=%i)",
  948.         i, voiceA.bufferUser.i32[i], MAX(i32_A[i],-2147483647) ); return -999;
  949.     }
  950.   }
  951.    //f32
  952.   SDL_memcpy(voiceA.bufferUser.f32, f32_A, 16*sizeof(float));
  953.   _kit_kmixerVoiceProcFromType(voiceA.bufferUser.f32,voiceA.bufferConvert.f32, 16,AUDIO_F32,SDL_FALSE);
  954.   _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.f32, 16,AUDIO_F32,SDL_FALSE);
  955.   for(Uint32 i=0; i<16; ++i){
  956.     if(voiceA.bufferUser.f32[i] != CLAMP(f32_A[i], -1.0f,1.0f)){
  957.       SDL_SetError("f32 type conv. (%u:%.1f!=%.1f)",
  958.         i, voiceA.bufferUser.f32[i], CLAMP(f32_A[i], -1.0f,1.0f) ); return -999;
  959.     }
  960.   }
  961.  
  962.  
  963.   //test channel conversion
  964.    //  mono-stereo
  965.   _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32s, 8,_M_to_S);
  966.   for(Uint32 i=0; i<16; i+=2){
  967.     //kit_coreLog("%2u: %9f, %9f",i, voiceA.bufferConvert.m[i], voiceA.bufferConvert.m[i+1]);
  968.     if(voiceA.bufferConvert.f32[i] != voiceA.bufferConvert.f32[i+1]){
  969.       SDL_SetError("mn.->st. convert (%u:%.1f!=%.1f)",
  970.         i, voiceA.bufferConvert.f32[i], voiceA.bufferConvert.f32[i+1] ); return -999;
  971.     }
  972.   }
  973.    //stereo-mono
  974.   _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32,  8,_S_to_M);
  975.   for(Uint32 i=0; i<16; i+=2){
  976.     //kit_coreLog("%2u: %9f,%9f -> %9f",i, f32_A[i],f32_A[i+1], voiceA.bufferConvert.m[i>>1]);
  977.     if(voiceA.bufferConvert.f32[i>>1] != (f32_A[i]+f32_A[i+1])*.5f){
  978.       SDL_SetError("st.->mn. convert (%u:%.1f!=%.1f)",
  979.         i, voiceA.bufferConvert.f32[i>>1], (f32_A[i]+f32_A[i+1])*.5f ); return -999;
  980.     }
  981.   }
  982.    //stereo-stereo
  983.   _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32s,  8,_S_to_S);
  984.   for(Uint32 i=0; i<16; ++i){
  985.     //kit_coreLog("%2u: %9f",i, voiceA.bufferConvert.m[i]);
  986.     if(voiceA.bufferConvert.f32[i] != f32_A[i]){
  987.       SDL_SetError("st.->st. convert (%u:%.1f!=%.1f)",
  988.         i, voiceA.bufferConvert.f32[i], f32_A[i] ); return -999;
  989.     }
  990.   }
  991.    //  mono-mono
  992.   _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32, 16,_M_to_M);
  993.   for(Uint32 i=0; i<16; ++i){
  994.     //kit_coreLog("%2u: %9f",i, voiceA.bufferConvert.m[i]);
  995.     if(voiceA.bufferConvert.f32[i] != f32_A[i]){
  996.       SDL_SetError("mn.->mn. convert (%u:%.1f!=%.1f)",
  997.         i, voiceA.bufferConvert.f32[i], f32_A[i] ); return -999;
  998.     }
  999.   }
  1000.  
  1001.  
  1002.   //test VoiceProc itself here
  1003.  
  1004.  
  1005.   //test mixing (might want to add in other volume settings at some point)
  1006.   voiceA.lock=SDL_CreateMutex();
  1007.   voiceB.lock=SDL_CreateMutex();
  1008.   voiceC.lock=SDL_CreateMutex();
  1009.   kit_coreVector* ivoices=kit_coreVectorCreate(2,0,0, sizeof(_kit_kmixerVoice),0);
  1010.   if(voiceA.lock==NULL || voiceB.lock==NULL || voiceC.lock==NULL || ivoices==NULL){
  1011.     if(voiceA.lock != NULL) SDL_DestroyMutex(voiceA.lock);
  1012.     if(voiceB.lock != NULL) SDL_DestroyMutex(voiceB.lock);
  1013.     if(voiceC.lock != NULL) SDL_DestroyMutex(voiceC.lock);
  1014.     if(ivoices != NULL) kit_coreVectorDestroy(&ivoices);
  1015.   }
  1016.  
  1017.   SDL_memcpy(voiceA.bufferOutput.f32, f32_A, 16*sizeof(float));
  1018.   SDL_memcpy(voiceB.bufferOutput.f32, f32_B, 16*sizeof(float));
  1019.   _kit_kmixerVoice _ivoices[2]={voiceA,voiceB};
  1020.   memcpy(ivoices->data, _ivoices, sizeof(_kit_kmixerVoice)*2);
  1021.    //mono, 1.0,1.0
  1022.   //_kit_kmixerVoiceMix(&voiceC);
  1023.   for(Uint32 i=0; i<16; ++i){
  1024.     float mixed=voiceC.bufferInput.f32[i];
  1025.     float real=CLAMP(voiceA.bufferOutput.f32[i]+voiceB.bufferOutput.f32[i], -1.0f,1.0f);
  1026.     if(mixed != real){ SDL_SetError("mn. mixing (%u:%.1f!=%.1f)",
  1027.                          i, mixed, real ); return -999;
  1028.     }
  1029.   }
  1030.    //stereo, 1.0,1.0
  1031.   voiceA.stereoOutput=SDL_TRUE;
  1032.   voiceB.stereoOutput=SDL_TRUE;
  1033.   voiceA.spec.samples=8;
  1034.   voiceB.spec.samples=8;
  1035.   voiceC.spec.samples=8;
  1036.   //_kit_kmixerVoiceMix(&voiceC);
  1037.   for(Uint32 i=0; i<16; ++i){
  1038.     float mixed=voiceC.bufferInput.f32[i];
  1039.     float real=CLAMP(voiceA.bufferOutput.f32[i]+voiceB.bufferOutput.f32[i], -1.0f,1.0f);
  1040.     if(mixed != real){ SDL_SetError("st. mixing (%u:%.1f!=%.1f)",
  1041.                          i, mixed, real ); return -999;
  1042.     }
  1043.   }
  1044.  
  1045.   if(voiceA.lock != NULL) SDL_DestroyMutex(voiceA.lock);
  1046.   if(voiceB.lock != NULL) SDL_DestroyMutex(voiceB.lock);
  1047.   if(voiceC.lock != NULL) SDL_DestroyMutex(voiceC.lock);
  1048.   if(ivoices != NULL) kit_coreVectorDestroy(&ivoices);
  1049.  
  1050.  
  1051.   //test adding and removing possibly
  1052.  
  1053.  
  1054.   //kit_coreLog("sizeof(_kit_kmixerVoice)=%u",(unsigned int)sizeof(_kit_kmixerVoice));
  1055.  
  1056.  
  1057.   return 0;
  1058. }
  1059. void kit_kmixerVoicePrintRawOrd(kit_kmixerDevice* device){
  1060.   kit_coreVector** raw_p = &device->_raw;
  1061.   kit_coreVector** ord_p = &device->_ord;
  1062.   Uint32 rawLen = (*raw_p)->x;
  1063.   Uint32 ordLen = (*ord_p)->x;
  1064.   Uint32 maxStage = (*ord_p)->y-1;
  1065.   _kit_kmixerVoice* raw = (*raw_p)->data;
  1066.   _kit_kmixerVoice** ord = (*ord_p)->data;
  1067.  
  1068.  
  1069.   printf("\n~~~ RAW ~~~\n");
  1070.   for(Uint32 v=0; v<rawLen; ++v){
  1071.     _kit_kmixerVoice* voice = &raw[v];
  1072.     printf("--- %02u/%02u (%p) ---\n", v, rawLen-1, voice);
  1073.     if(voice->lock == NULL){ printf("  (REMOVED)\n"); continue; }
  1074.     Uint32 numInputs = 0,  *inputs = NULL;
  1075.     if(voice->inputs != NULL){
  1076.       numInputs = voice->inputs->x;
  1077.          inputs = voice->inputs->data;
  1078.     }
  1079.  
  1080.     printf("  voice%u->inputs     = %p: ",v, voice->inputs);
  1081.     if(inputs != NULL){
  1082.       printf("{\n    ");
  1083.       for(Uint32 i=0; i<numInputs; ++i){
  1084.         if(inputs[i]!=0) printf("%02u, ",inputs[i]);
  1085.         else printf("RM, "); //removed voice
  1086.         if((i+1)==numInputs) printf("\n");
  1087.         else if((i%5)==4) printf("\n    ");
  1088.       }
  1089.       printf("  }\n");
  1090.     } else printf("(NULL)\n");
  1091.  
  1092.     printf("  voice%u->output     = %2i\n",v, voice->output);
  1093.     printf("  voice%u->chainStage = %2u\n",v, voice->chainStage);
  1094.     printf("  voice%u->timeStamp  = %u\n",v,  voice->timeStamp);
  1095.  
  1096.     printf("\n");
  1097.   }
  1098.  
  1099.  
  1100.   printf("\n~~~ ORD ~~~\n");
  1101.   for(Uint32 yi=maxStage; yi!=U32_MAX; --yi){
  1102.     printf("stage %02u:  ", yi);
  1103.     for(Uint32 xi=0; xi<ordLen; ++xi){
  1104.       _kit_kmixerVoice* voice = ord[xi + yi*ordLen];
  1105.  
  1106.       if(voice == NULL) printf("NL, ");
  1107.       else if(voice->lock == NULL) printf("RM, ");
  1108.       else printf("%02u, ",voice->index);
  1109.     }
  1110.     printf("\n");
  1111.   }
  1112.   printf("\n");
  1113.  
  1114. }
  1115. #else
  1116. int kit_kmixerVoice_Test(){
  1117.   SDL_SetError("!defined(_KIT_KMIXER_DEBUG)");
  1118.   return 999;
  1119. }
  1120. void kit_kmixerVoicePrintRawOrd(kit_kmixerDevice* device){}
  1121. #endif
  1122.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement