Advertisement
Kitomas

the section of kit_sdl2_kmixerVoice.c that was added as of 2023-8-31

Sep 1st, 2023
1,042
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.75 KB | None | 0 0
  1. #define _CH_INFO(a,b) (((a)<<1)|(b))
  2. //assumes input AND output samples are f32 (intermediate type is determined by the given voice)
  3. int _kit_kmixerVoiceProc(void* data){ //(this is an SDL_ThreadFunction)
  4.   _kit_kmixerVoice* voice=data;
  5.   SDL_LockMutex(voice->lock);
  6.  
  7.  
  8.   void *ibuffer=voice->bufferInput.v, *obuffer=voice->bufferOutput.v;
  9.   void *ubuffer=voice->bufferUser.v, *cbuffer=voice->bufferConvert.v;
  10.   void *userdata=voice->spec.userdata, *_stream=ubuffer;
  11.    ///
  12.   SDL_bool hasInput = voice->inputs!=NULL;
  13.   SDL_bool ustereo=voice->spec.stereo;
  14.   SDL_bool ostereo=voice->stereoOutput;
  15.    ///
  16.   SDL_AudioFormat uformat=voice->spec.format;
  17.   Uint32 frames=voice->spec.samples, ubuffer_size=voice->spec._size;
  18.  
  19.  
  20.   //convert (if necessary) input type (format) from f32
  21.   int userTypeIsF32 = uformat==AUDIO_F32;
  22.   if(userTypeIsF32) _stream=ibuffer; //input and user are identical; just reroute
  23.   else _kit_kmixerVoiceProcToType(ibuffer, ubuffer, frames,uformat,ustereo);
  24.  
  25.   //the actual user callback
  26.   voice->spec.callback(userdata, _stream, ubuffer_size, hasInput);
  27.  
  28.   //convert (if necessary) to f32 and channels, sending result to output
  29.   int sameChannels = ustereo==ostereo;
  30.   if(sameChannels){
  31.     //convert type (or just copy contents if _stream is f32)
  32.     _kit_kmixerVoiceProcFromType(_stream,obuffer, frames,uformat,ustereo);
  33.   } else if(userTypeIsF32){ //convert channels
  34.     _kit_kmixerVoiceProcChannels(_stream,obuffer, frames,_CH_INFO(ustereo,ostereo));
  35.   } else { //convert type and channels
  36.     _kit_kmixerVoiceProcFromType(_stream,cbuffer, frames,uformat,ustereo);
  37.     _kit_kmixerVoiceProcChannels(cbuffer,obuffer, frames,_CH_INFO(ustereo,ostereo));
  38.   }
  39.  
  40.  
  41.   SDL_UnlockMutex(voice->lock);
  42.   return 0;
  43. }
  44.  
  45.  
  46.  
  47.  
  48. //assumes all samples are f32
  49. //if nothing else works
  50. static inline void _kit_kmixerVoiceMixFallback(_kit_kmixerVoice* ovoice, kit_coreVector* _ivoices){
  51.   if(ovoice->lock == NULL) return; //skip in case voice was removed
  52.   SDL_LockMutex(ovoice->lock);
  53.  
  54.   Uint32 frames=ovoice->spec.samples;
  55.    //bad things would happen if input buffer is NULL
  56.   memset(ovoice->bufferInput.v, 0, (frames*sizeof(float))<<ovoice->spec.stereo);
  57.   _stereo_samples_f32* osamples=ovoice->bufferInput.s;
  58.   Uint32 samples_len=frames>>(!ovoice->spec.stereo);
  59.  
  60.   //do the mixing
  61.   _kit_kmixerVoice* ivoices=_ivoices->ptr;
  62.   Uint32 ivoices_len=_ivoices->x;
  63.   for(Uint32 vi=0; vi<ivoices_len; ++vi){
  64.     _kit_kmixerVoice* ivoice=&ivoices[vi];
  65.     if(ivoice->lock == NULL) continue; //skip in case voice was removed
  66.     SDL_LockMutex(ivoice->lock);
  67.  
  68.     _stereo_samples_f32* isamples=ivoice->bufferOutput.s;
  69.     float volL=ivoice->volL, volR=ivoice->volR;
  70.  
  71.     volL=_MN(volL,1.0f); volR=_MN(volR, 1.0f);
  72.     if(!ivoice->stereoOutput) volR=volL;
  73.  
  74.     if(volL==0 && volR==0) continue; //if volume is effectively muted, then skip the voice
  75.     else if(volL==1.0f && volR==1.0f) goto _do_not_apply_volume; //because sample*1=sample
  76.     else if((volL>=0)&&ivoice->applyVolume){
  77.       if(volR<0) volR=volL;
  78.       for(Uint32 i=0; i<samples_len; ++i){
  79.         osamples[i].l += isamples[i].l*volL;
  80.         osamples[i].r += isamples[i].r*volR;
  81.       }
  82.     } else { _do_not_apply_volume:
  83.       for(Uint32 i=0; i<samples_len; ++i){
  84.         osamples[i].l += isamples[i].l;
  85.         osamples[i].r += isamples[i].r;
  86.       }
  87.     }
  88.  
  89.     SDL_UnlockMutex(ivoice->lock);
  90.   }
  91.  
  92.   //hard clip output samples to between -1.0f and 1.0f
  93.   for(Uint32 i=0; i<samples_len; ++i){
  94.     float sampleL=osamples[i].l;
  95.     osamples[i].l=_CLMP(sampleL, -1.0f,1.0f);
  96.     float sampleR=osamples[i].r;
  97.     osamples[i].r=_CLMP(sampleR, -1.0f,1.0f);
  98.   }
  99.  
  100.   SDL_UnlockMutex(ovoice->lock);
  101. }
  102. void _kit_kmixerVoiceMix(_kit_kmixerVoice* ovoice, kit_coreVector* ivoices){
  103.   _kit_kmixerVoiceMixFallback(ovoice, ivoices);
  104. }
  105.  
  106.  
  107.  
  108.  
  109. int _kit_kmixerVoiceRebuild(kit_kmixerDevice* device){
  110.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device,SDL_TRUE),;)
  111.   _kit_kmixerVoice* raw=device->_voices.raw->ptr;
  112.   Uint32 raw_len=device->_voices.raw->x;
  113.   //trim any empty space at the end of the raw voice list
  114.   for(Uint32 i=raw_len-1; i>0; --i){
  115.     if(raw[i].lock != NULL){
  116.       _IF_GOTO_ERROR(kit_coreVectorSet(&device->_voices.raw,i+1,0,0),;)
  117.       break;
  118.     }
  119.   }
  120.   raw=device->_voices.raw->ptr;   //update raw info
  121.   raw_len=device->_voices.raw->x; //^^
  122.  
  123.   //probe current highest chain stage, to pre-set ord and chain's x to it
  124.    //(so i don't need to call kit_coreVectorSet as much)
  125.   Uint32 highestVoiceChain=0;
  126.   for(Uint32 i=0; i<raw_len; ++i){
  127.     if(raw[i].lock != NULL){
  128.       if(raw[i].chainStage > highestVoiceChain)
  129.         highestVoiceChain=raw[i].chainStage;
  130.     }
  131.   }
  132.  
  133.   //rebuild ord (and by extension chain)
  134.   kit_coreVector** ord_p=&device->_voices.ord;
  135.   _IF_GOTO_ERROR(kit_coreVectorSet(ord_p,1,1,0),;) //so new size inits to 0
  136.   _IF_GOTO_ERROR(kit_coreVectorSet(ord_p,highestVoiceChain+1,1,0),;)
  137.   _kit_kmixerVoice*** ord=(*ord_p)->ptr;
  138.  
  139.   kit_coreVector** chain_p=&device->_voices.chain;
  140.   _IF_GOTO_ERROR(kit_coreVectorSet(chain_p,1,0,0),;) //so new size inits to 0
  141.   _IF_GOTO_ERROR(kit_coreVectorSet(chain_p,highestVoiceChain+1,0,0),;)
  142.   Uint32* chain=(*chain_p)->ptr; chain[0]=0; //so voice 0 will ++ back to 1
  143.  
  144.   for(Uint32 i=0; i<raw_len; ++i){
  145.     if(raw[i].lock != NULL){
  146.       Uint32 chainStage=raw[i].chainStage; //x position in ord
  147.       Uint32 stageIndex=chain[chainStage]; //y position in ord
  148.       //check if extension of ord's y is required
  149.       if(++chain[chainStage] > (*ord_p)->y){
  150.         _IF_GOTO_ERROR(kit_coreVectorAdd(ord_p,0,1,0),;)
  151.         ord=(*ord_p)->ptr;
  152.       }
  153.       //finally, assign reference to proper place in ord
  154.       ord[chainStage][stageIndex]=&raw[i];
  155.     }
  156.   }
  157.  
  158.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device,SDL_FALSE),;)
  159.  
  160.   return 0;
  161.   _error_:
  162.   return -1;
  163. }
  164.  
  165.  
  166.  
  167.  
  168. int kit_kmixerVoiceRemove(kit_kmixerDevice* device, Uint32 voiceID){
  169.   _IF_SDLERR(device==NULL,;,"device cannot be NULL")
  170.   _IF_SDLERR((device->_magic.num&U64_MSBC)!=_DEV_MAGIC_NUM,;,"invalid device struct")
  171.   //if bit 31 is set, call is assumed to be the result of recursion
  172.   SDL_bool rootCall=(!(voiceID&0x80000000)) ? SDL_TRUE : SDL_FALSE;
  173.   voiceID&=0x7fffffff; //unset bit 31 now that rootCall is set
  174.   //only allow voice 0 to be removed when device->_closing is set
  175.   _IF_SDLERR(!voiceID && !device->_closing,;,"cannot remove device 0")
  176.  
  177.   _kit_kmixerVoice* raw=device->_voices.raw->ptr;
  178.   _kit_kmixerVoice* voice=&raw[voiceID];
  179.   if(voice->lock == NULL) return 0; //return normally if voice already removed
  180.   _IF_GOTO_ERROR(SDL_LockMutex(voice->lock),;)
  181.  
  182.   //loop through and remove any inputs the voice might have (recursive)
  183.   if(voice->inputs != NULL){
  184.     Uint32* inputs=voice->inputs->ptr;
  185.     Uint32 inputs_len=voice->inputs->x;
  186.     for(Uint32 i=0; i<inputs_len; ++i){
  187.       Uint32 index=inputs[i];
  188.       if(raw[index].lock != NULL) //bit 31 is set to indicate recursion
  189.         _IF_GOTO_ERROR(kit_kmixerVoiceRemove(device,0x80000000|index),;)
  190.     }
  191.     //(kit_coreVectorDestroy automatically sets pointer to NULL)
  192.     _IF_GOTO_ERROR(kit_coreVectorDestroy(&voice->inputs),;)
  193.     _IF_GOTO_ERROR(kit_coreVectorDestroy(&voice->inputRefs),;)
  194.   }
  195.  
  196.   //free buffers
  197.   if(voice->bufferInput.v != NULL)   SDL_free(voice->bufferInput.v);
  198.   if(voice->bufferUser.v != NULL)    SDL_free(voice->bufferUser.v);
  199.   if(voice->bufferConvert.v != NULL) SDL_free(voice->bufferConvert.v);
  200.   if(voice->bufferOutput.v != NULL)  SDL_free(voice->bufferOutput.v);
  201.  
  202.   //call the user's 'userdata removal' callback
  203.   if(voice->spec.remove!=NULL) voice->spec.remove(voice->spec.userdata);
  204.  
  205.   _IF_GOTO_ERROR(SDL_UnlockMutex(voice->lock),;)
  206.   SDL_DestroyMutex(voice->lock);
  207.   voice->lock=NULL; //this indicates that it was removed successfully
  208.  
  209.   if(rootCall){ //if this call is not the result of recursion
  210.     //trim raw, and rebuild ord and chain
  211.     _IF_GOTO_ERROR(_kit_kmixerVoiceRebuild(device),;)
  212.     //trim inputs of output voice, potentially destroying inputs if none are left
  213.     _kit_kmixerVoice* voiceO=voice->output;
  214.     _IF_SDLERR(voiceO==NULL,;,"voice->output == NULL"); //shouldn't be able to happen
  215.     _IF_GOTO_ERROR(SDL_LockMutex(voiceO->lock),;)
  216.     kit_coreVector** inputRefs_p=&voiceO->inputRefs;
  217.     _kit_kmixerVoice** inputRefs=(*inputRefs_p)->ptr;
  218.     Uint32 inputs_len=(*inputRefs_p)->x;
  219.      ///
  220.     Sint32 lastIndex=-1; //will remain -1 if inputs are completely empty
  221.     for(Uint32 i=0; i<inputs_len; ++i){
  222.       if(inputRefs[i]->lock != NULL) lastIndex=i;
  223.     }
  224.     if(lastIndex==-1){ //destroy
  225.       kit_coreVectorDestroy(&voiceO->inputs);
  226.       kit_coreVectorDestroy(inputRefs_p);
  227.     } else if(++lastIndex < inputs_len){ //only trim
  228.       _IF_GOTO_ERROR(kit_coreVectorSet(&voiceO->inputs, lastIndex,0,0),;)
  229.       _IF_GOTO_ERROR(kit_coreVectorSet(inputRefs_p, lastIndex,0,0),;)
  230.     }
  231.     _IF_GOTO_ERROR(SDL_UnlockMutex(voiceO->lock),;)
  232.   }
  233.  
  234.   return 0;
  235.   _error_:
  236.   return -1;
  237. }
  238.  
  239.  
  240.  
  241. Uint32 kit_kmixerVoiceAdd(kit_kmixerDevice* device, kit_kmixerVoiceSpec* spec,
  242.                           Uint32 outputVoiceID)
  243. {
  244.   //create voice and check device validity
  245.   Sint32 newIndex=0; //0 for error by default
  246.   _kit_kmixerVoice voice;
  247.   SDL_memset(&voice, 0, sizeof(_kit_kmixerVoice)); //just in case
  248.   _IF_SDLERR(device==NULL,;,"device cannot be NULL")
  249.   _IF_SDLERR((device->_magic.num&U64_MSBC)!=_DEV_MAGIC_NUM,;,"invalid device struct")
  250.  
  251.   //raw voice list
  252.   _kit_kmixerVoice* raw=device->_voices.raw->ptr;
  253.   Uint32 raw_len=device->_voices.raw->x;
  254.   _IF_SDLERR(outputVoiceID>=raw_len,;,"outputVoiceID > voice count")
  255.    //lock is used to check if a voice is valid
  256.   _IF_SDLERR(raw[outputVoiceID].lock==NULL,;,"output voice is nonexistent");
  257.  
  258.  
  259.   //voice0 is a pseudo-voice that acts as a device proxy
  260.   _kit_kmixerVoice* voice0=device->_voices.raw->ptr;
  261.    //<<!stereo so size is always assumed to be stereo unless specified otherwise
  262.   Uint32 voice0_size = voice0->spec._size<<(!voice0->spec.stereo);
  263.  
  264.   //set voice spec's device-oriented stuff
  265.    //(.stereo is set by the voice, but .samples is set when opening the device)
  266.   Uint32 voice_size = voice0->spec.samples<<spec->stereo;
  267.    //set voice_size to size of user buffer
  268.   switch(spec->format){
  269.   case AUDIO_F32:                SDL_FALLTHROUGH;
  270.   case AUDIO_S32: voice_size*=2; SDL_FALLTHROUGH;
  271.   case AUDIO_S16: voice_size*=2; SDL_FALLTHROUGH;
  272.   case AUDIO_U8 : spec->_size=voice_size;  break;
  273.   default: _IS_SDLERR(;,"spec's format is invalid");
  274.   }
  275.   spec->freq=voice0->spec.freq;
  276.   spec->samples=voice0->spec.samples;
  277.  
  278.  
  279.   //fill in new voice
  280.   _kit_kmixerVoice* voiceO=&raw[outputVoiceID]; //the voice to output to
  281.  
  282.   voice.lock=SDL_CreateMutex();
  283.   _IF_GOTO_ERROR(voice.lock==NULL,;)
  284.    //inputs & inputRefs is made once another voice is created,
  285.     //that outputs to this voice
  286.   voice.output=voiceO;
  287.  
  288.   voice.bufferInput.v  =SDL_malloc(voice0_size>>(!spec->stereo));
  289.   voice.bufferUser.v   =SDL_malloc(voice_size);
  290.   voice.bufferConvert.v=SDL_malloc(voice0_size);
  291.   voice.bufferOutput.v =SDL_malloc(voice0_size>>(!voiceO->spec.stereo));
  292.  
  293.   voice.spec=*spec;
  294.  
  295.    //set chain processing stage one higher,
  296.     //to ensure this voice is processed before the output
  297.   voice.chainStage=voiceO->chainStage+1;
  298.    //(voice.index is set later)
  299.  
  300.   voice.volL=1.0f;
  301.   voice.volR=(voice.spec.stereo) ? 1.0f : -1.0f;
  302.  
  303.   voice.applyVolume=SDL_TRUE;
  304.   voice.stereoOutput=voiceO->spec.stereo;
  305.  
  306.  
  307.   //add this voice's id to voiceO's inputs
  308.    //first, attempt to find an empty slot inside current raw list...
  309.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device,SDL_TRUE),;)
  310.   for(Uint32 i=0; i<raw_len; ++i){
  311.     if(raw[i].lock==NULL){
  312.       voice.index=newIndex = i;
  313.       raw[i]=voice; break;
  314.     }
  315.   }
  316.    //...and if no empty space was found, append the voice to raw
  317.   if(!newIndex){
  318.     newIndex=kit_coreVectorAppend(&device->_voices.raw, &voice, 0,0);
  319.      //(kit_coreVectorAppend will return negative on error)
  320.     _IF_GOTO_ERROR(newIndex<0,newIndex=0)
  321.   }
  322.  
  323.    //update ord with new index (append only; don't call _kit_kmixerVoiceRebuild)
  324.   kit_coreVector** ord_p=&device->_voices.ord;
  325.   _kit_kmixerVoice*** ord=(*ord_p)->ptr;
  326.   kit_coreVector** chain_p=&device->_voices.chain;
  327.   Uint32* chain=(*chain_p)->ptr;
  328.    ///
  329.   Uint32 chainStage=voice.chainStage;
  330.   _kit_kmixerVoice* voiceInAddress=&raw[newIndex];
  331.   if(chainStage>=(*ord_p)->x){ //make sure ord->x and chain->x is long enough
  332.     _IF_GOTO_ERROR(kit_coreVectorSet(ord_p,chainStage+1,0,0),;)
  333.     _IF_GOTO_ERROR(kit_coreVectorSet(chain_p,chainStage+1,0,0),;)
  334.     ord=(*ord_p)->ptr;
  335.     chain=(*chain_p)->ptr;
  336.   }
  337.   if(ord[chainStage][0]!=NULL && ord[chainStage][0]->lock!=NULL){
  338.     _IF_GOTO_ERROR(kit_coreVectorAppend(ord_p, &voiceInAddress, chainStage,0)<0,;)
  339.     ++chain[chainStage]; //++ since a new index was added to ord[chainStage]
  340.   } else { //first reference in ord[chainStage] is actually free
  341.     ord[chainStage][0]=voiceInAddress;
  342.   }
  343.   _IF_GOTO_ERROR(kit_kmixerDeviceLock(device,SDL_FALSE),;)
  344.  
  345.    //finally, add the id, as well as the voice's reference to voiceO
  346.   _IF_GOTO_ERROR(SDL_LockMutex(voiceO->lock),;)
  347.   if(voiceO->inputs!=NULL){
  348.     _IF_GOTO_ERROR(kit_coreVectorAppend(&voiceO->inputs,&newIndex,0,0)<0,;)
  349.     _IF_GOTO_ERROR(kit_coreVectorAppend(&voiceO->inputRefs,&voiceInAddress,0,0)<0,;)
  350.   } else {
  351.     voiceO->inputs=kit_coreVectorCreate(1,0,0,sizeof(Uint32),U32_STR("U4 \x00"),NULL);
  352.     _IF_GOTO_ERROR(voiceO->inputs==NULL,;)
  353.     voiceO->inputRefs=kit_coreVectorCreate(1,0,0,sizeof(_kit_kmixerVoice*),U32_STR("kVp\x00"),NULL);
  354.     _IF_GOTO_ERROR(voiceO->inputRefs==NULL,;)
  355.     ((Uint32*)voiceO->inputs->ptr)[0]=newIndex;
  356.     ((_kit_kmixerVoice**)voiceO->inputRefs->ptr)[0]=voiceInAddress;
  357.   }
  358.   _IF_GOTO_ERROR(SDL_UnlockMutex(voiceO->lock),;)
  359.  
  360.  
  361.   _error_:
  362.   if(!newIndex && voice.lock!=NULL){
  363.  
  364.   }
  365.   return newIndex;
  366. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement