Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "../include/kit_sdl2/kit_kmixer.h"
- #include "../_private/include/_kit_privmacro.h"
- #include "../_private/include/_kit_kmixerAllPrivate.h"
- /* example of simd stereo to mono without sse3's hadd
- static inline void _sse1_s_to_m(float* dst, __m128 vector){
- __m128 shuffled = _mm_shuffle_ps(vector,vector, _MM_SHUFFLE(2,3,0,1));
- __m128 sum = _mm_add_ps(vector,shuffled);
- __m128 result = _mm_shuffle_ps(sum,sum, _MM_SHUFFLE(3,1,2,0));
- _mm_storel_pi((__m64*)dst,result);
- }
- */
- //for visual clarity during ProcChannels
- //(this could also just be an enum probably, but w/e)
- #define _M_to_M (0) // mono->mono
- #define _M_to_S (1) // mono->stereo
- #define _S_to_M (2) //stereo->mono
- #define _S_to_S (3) //stereo->stereo
- /* i think i need to fix this
- #define _MM256_SHUFFLE(c7,c6,c5,c4,c3,c2,c1,c0) \
- ((_MM_SHUFFLE(c7,c6,c5,c4)<<8)|_MM_SHUFFLE(c3,c2,c1,c0)) */
- //converts u8, i16, and i32 samples to f32 samples
- //(will basically just copy input to output if input is also f32)
- static inline void _kit_kmixerVoiceProcFromTypeFallback(void* _dataIn, float* dataOut,
- Uint32 numSamples, SDL_AudioFormat typeIn)
- { //if nothing else works
- kit_acodecPCMSamples dataIn = { .data = _dataIn };
- float rawSample; //used for max(original_sample,-1) basically
- switch(typeIn){
- case AUDIO_U8 : for(Uint32 i=0; i<numSamples; ++i){ rawSample = (float)(dataIn.u_8[i]-0x80)*inv_i_8;
- dataOut[i] = (rawSample>=-1.0f)?rawSample:-1.0f; } break;
- case AUDIO_S16: for(Uint32 i=0; i<numSamples; ++i){ rawSample = (float) dataIn.i16[i] *inv_i16;
- dataOut[i] = (rawSample>=-1.0f)?rawSample:-1.0f; } break;
- case AUDIO_S32: for(Uint32 i=0; i<numSamples; ++i){ rawSample = (float) dataIn.i32[i] *inv_i32;
- dataOut[i] = (rawSample>=-1.0f)?rawSample:-1.0f; } break;
- case AUDIO_F32: for(Uint32 i=0; i<numSamples; ++i){ dataOut[i] = dataIn.f32[i]; } }
- }
- void _kit_kmixerVoiceProcFromType(void* dataIn, void* dataOut,
- Uint32 sampleFrames, SDL_AudioFormat typeIn, SDL_bool isStereo)
- {
- Uint32 numSamples = sampleFrames<<isStereo;
- _kit_kmixerVoiceProcFromTypeFallback(dataIn,dataOut,numSamples,typeIn);
- }
- //converts f32 samples to u8, i16, and i32 samples
- static inline void _kit_kmixerVoiceProcToTypeFallback(float* dataIn, void* _dataOut,
- Uint32 numSamples, SDL_AudioFormat typeOut)
- { //if nothing else works
- kit_acodecPCMSamples dataOut = { .data = _dataOut };
- float rawSample, rawSampleB;
- switch(typeOut){
- case AUDIO_U8 : for(Uint32 i=0; i<numSamples; ++i){ rawSample = dataIn[i];
- rawSampleB = (rawSample>=-1.0f)?rawSample:-1.0f;
- dataOut.u_8[i] = (rawSampleB<=1.0f)?rawSampleB*I_8_MAX+0x80:I_8_MAX; } break;
- case AUDIO_S16: for(Uint32 i=0; i<numSamples; ++i){ rawSample = dataIn[i];
- rawSampleB = (rawSample>=-1.0f)?rawSample:-1.0f;
- dataOut.i16[i] = (rawSampleB<=1.0f)?rawSampleB*I16_MAX:I16_MAX; } break;
- case AUDIO_S32: for(Uint32 i=0; i<numSamples; ++i){ rawSample = dataIn[i];
- rawSampleB = (rawSample>=-1.0f)?rawSample:-1.0f;
- dataOut.i32[i] = (rawSampleB<=1.0f)?rawSampleB*I32_MAX:I32_MAX; } break;
- case AUDIO_F32: for(Uint32 i=0; i<numSamples; ++i){ rawSample = dataIn[i];
- rawSampleB = (rawSample>=-1.0f)?rawSample:-1.0f;
- dataOut.f32[i] = (rawSampleB<=1.0f)?rawSampleB:1.0f; } }
- }
- void _kit_kmixerVoiceProcToType(void* dataIn, void* dataOut,
- Uint32 sampleFrames, SDL_AudioFormat typeOut, SDL_bool isStereo)
- {
- Uint32 numSamples = sampleFrames<<isStereo;
- _kit_kmixerVoiceProcToTypeFallback(dataIn,dataOut,numSamples,typeOut);
- }
- //assumes samples are f32
- static inline void _kit_kmixerVoiceProcChannelsFallback(float* dataInM, float* dataOutM,
- Uint32 sampleFrames, int channelInfo)
- { //if nothing else works
- kit_acodecPCM_F32S* dataInS = (void*)dataInM;
- kit_acodecPCM_F32S* dataOutS = (void*)dataOutM;
- switch(channelInfo){
- case _M_to_S: for(Uint32 i=0; i<sampleFrames; ++i){ dataOutS[i].l=dataOutS[i].r = dataInM[i]; } break;
- case _S_to_M: for(Uint32 i=0; i<sampleFrames; ++i){ dataOutM[i] = (dataInS[i].l+dataInS[i].r)*0.5f; } break;
- case _S_to_S: sampleFrames<<=1; SDL_FALLTHROUGH; //multiply mono by 2 to make length of stereo
- case _M_to_M: for(Uint32 i=0; i<sampleFrames; ++i){ dataOutM[i] = dataInM[i]; }
- }
- }
- void _kit_kmixerVoiceProcChannels(void* dataIn, void* dataOut, Uint32 sampleFrames, int channelInfo){
- _kit_kmixerVoiceProcChannelsFallback(dataIn,dataOut, sampleFrames,channelInfo);
- }
- #define _CH_INFO(a,b) (((a)<<1)|(b))
- //assumes input AND output samples are f32 (intermediate type is determined by the given voice)
- int _kit_kmixerVoiceProc(void* data){ //(this is an SDL_ThreadFunction)
- _kit_kmixerVoice* voice = data;
- if(voice == NULL) return 1; //skip if voice is NULL
- if(voice->lock == NULL) return 2; //skip if voice was removed
- if(voice->output == U32_MAX) return 3; //skip if voice is voice 0
- SDL_LockMutex(voice->lock);
- void *ibuffer = voice->bufferInput.data, *obuffer = voice->bufferOutput.data;
- void *ubuffer = voice->bufferUser.data, *cbuffer = voice->bufferConvert.data;
- void *userdata = voice->spec.userdata, *_stream = ubuffer;
- ///
- SDL_bool hasInput = voice->inputs!=NULL;
- SDL_bool ustereo = voice->spec.stereo;
- SDL_bool ostereo = voice->stereoOutput;
- ///
- SDL_AudioFormat uformat = voice->spec.format;
- Uint32 frames = voice->spec.samples;
- Uint32 ubuffer_size = voice->spec._size;
- //convert (if necessary) input type (format) from f32
- int userTypeIsF32 = uformat==AUDIO_F32;
- if(userTypeIsF32) _stream = ibuffer; //input and user are identical; just reroute
- else _kit_kmixerVoiceProcToType(ibuffer, ubuffer, frames,uformat,ustereo);
- //the actual user callback
- voice->spec.callback(userdata, _stream, ubuffer_size, hasInput);
- //convert (if necessary) to f32 and channels, sending result to output
- int sameChannels = ustereo==ostereo;
- if(sameChannels){ //convert type (or just copy contents if _stream is f32)
- _kit_kmixerVoiceProcFromType(_stream,obuffer, frames,uformat,ustereo);
- } else if(userTypeIsF32){ //convert channels
- _kit_kmixerVoiceProcChannels(_stream,obuffer, frames,_CH_INFO(ustereo,ostereo));
- } else { //convert type and channels
- _kit_kmixerVoiceProcFromType(_stream,cbuffer, frames,uformat,ustereo);
- _kit_kmixerVoiceProcChannels(cbuffer,obuffer, frames,_CH_INFO(ustereo,ostereo));
- }
- SDL_UnlockMutex(voice->lock);
- return 0;
- }
- //assumes all samples are f32
- //if nothing else works
- static inline void _kit_kmixerVoiceMixFallback(_kit_kmixerVoice* voiceO){
- kit_coreVector** raw_p = &voiceO->device->_raw;
- _kit_kmixerVoice* raw = (*raw_p)->data;
- Uint32* inputs = voiceO->inputs->data;
- Uint32 inputs_len = voiceO->inputs->x;
- kit_acodecPCM_F32S* samplesO = voiceO->bufferInput.f32s;
- Uint32 samples_len = voiceO->spec.samples;
- size_t bufferSize = (samples_len*sizeof(float))<<voiceO->spec.stereo;
- kit_coreMemset(voiceO->bufferInput.data, 0, bufferSize);
- //so stereo volume can apply even to a mono stream
- //(assuming volR is set to volL)
- samples_len >>= !voiceO->spec.stereo;
- for(Uint32 v=0; v<inputs_len; ++v){
- _kit_kmixerVoice* voiceI = &raw[ inputs[v] ];
- if(voiceI->lock == NULL){ inputs[v] = 0; continue; }
- if(!voiceI->active) continue; //also skip if voice is inactive
- SDL_LockMutex(voiceI->lock);
- kit_acodecPCM_F32S* samplesI = voiceI->bufferOutput.f32s;
- float volL = CLAMP(voiceI->volL, 0.0f,1.0f);
- float volR = MIN(voiceI->volR, 1.0f);
- if(!voiceI->stereoOutput || volR<0) volR = volL;
- if( volL==0.0f && volR==0.0f) continue; //volume is muted; skip
- else if(volL==1.0f && volR==1.0f) goto _normal_volume; //because sample*1=sample
- else if(volL>=0.0f){
- for(Uint32 i=0; i<samples_len; ++i){
- samplesO[i].l += samplesI[i].l*volL;
- samplesO[i].r += samplesI[i].r*volR;
- }
- } else { _normal_volume:
- for(Uint32 i=0; i<samples_len; ++i){
- samplesO[i].l += samplesI[i].l;
- samplesO[i].r += samplesI[i].r;
- }
- }
- SDL_UnlockMutex(voiceI->lock);
- }
- //hard clip output samples to between -1.0f and 1.0f
- for(Uint32 i=0; i<samples_len; ++i){
- float sampleL = samplesO[i].l;
- float sampleR = samplesO[i].r;
- samplesO[i].l = CLAMP(sampleL, -1.0f,1.0f);
- samplesO[i].r = CLAMP(sampleR, -1.0f,1.0f);
- }
- }
- //(this should only be called if the voice has inputs)
- int _kit_kmixerVoiceMix(void* data){ //(this is an SDL_ThreadFunction)
- _kit_kmixerVoice* voiceO = data;
- if(voiceO == NULL) return 1; //skip if the voice is NULL
- if(voiceO->lock == NULL) return 2; //skip in case voice was removed
- SDL_LockMutex(voiceO->lock);
- //don't mix if voice has no inputs...
- if(voiceO->inputs == NULL){
- size_t bufferSize = (voiceO->spec.samples*sizeof(float)) << voiceO->spec.stereo;
- //...but still make sure the input buffer is zeroed out
- kit_coreMemset(voiceO->bufferInput.data, 0, bufferSize);
- SDL_UnlockMutex(voiceO->lock);
- return 3;
- }
- _kit_kmixerVoiceMixFallback(voiceO);
- SDL_UnlockMutex(voiceO->lock);
- return 0;
- }
- //used to check whether an element in the raw voice list is valid or not
- SDL_bool _kit_kmixerVoiceRawUnitCallback(void* unit, Uint32 size){
- _kit_kmixerVoice* voice = unit;
- return voice->lock == NULL;
- }
- //same thing, but with an element in ord instead of raw
- SDL_bool _kit_kmixerVoiceOrdUnitCallback(void* unit, Uint32 size){
- _kit_kmixerVoice** voice_p = unit;
- if(*voice_p == NULL) return SDL_TRUE;
- return (*voice_p)->lock == NULL;
- }
- //(assumes device is locked)
- //should be called when voices are created, destroyed, or raw is altered in general
- int _kit_kmixerVoiceRebuildOrd(kit_kmixerDevice* device){
- kit_coreVector* ord_new = NULL;
- kit_coreVector** ord_p = &device->_ord;
- kit_coreVector** raw_p = &device->_raw;
- _kit_kmixerVoice* raw = (*raw_p)->data;
- Uint32 numVoices = (*raw_p)->x;
- Uint32 hiStageLen = 0; //ord->x
- Uint32 hiStage = 0; //ord->y
- Uint32* stageLens = NULL; //temporary space for stage lengths
- //find highest chain stage (for ord's y axis)
- for(Uint32 v=0; v<numVoices; ++v){
- if(raw[v].lock == NULL) continue; //skip any removed voice
- if(hiStage < raw[v].chainStage) hiStage = raw[v].chainStage;
- }
- ++hiStage; //should now equal ord->y
- //find highest index of a chain stage (for ord's x axis)
- _IF_SDLERR(kit_coreRealloc(&stageLens,0,hiStage*sizeof(Uint32)),;,"!stageLens")
- for(Uint32 v=0; v<numVoices; ++v){
- if(raw[v].lock == NULL) continue; //skip any removed voice
- Uint32 stageLen = ++stageLens[raw[v].chainStage];
- if(hiStageLen < stageLen) hiStageLen = stageLen;
- }
- SAFE_FREE(stageLens);
- if(!hiStageLen) hiStageLen = 1; //vectors can't have sizes of 0
- //create new ord vector with new dimensions
- ord_new = kit_coreVectorCreate(hiStageLen,hiStage,1, sizeof(_kit_kmixerVoice*),0);
- _IF_SDLERR(ord_new==NULL,;,"!ord_new")
- kit_coreVectorDestroy(ord_p); //doink the old one
- *ord_p = ord_new;
- //fill ord with new references from raw
- for(Uint32 v=0; v<numVoices; ++v){
- if(raw[v].lock == NULL) continue; //skip any removed voice
- _kit_kmixerVoice* voiceRef = &raw[v];
- Uint32 chainStage = voiceRef->chainStage;
- _IF_GOTO_ERROR(kit_coreVectorInsert(ord_p, &voiceRef, chainStage,0,
- _kit_kmixerVoiceOrdUnitCallback)==U32_MAX,;)
- }
- /*!err*/ return 0;
- _error_: return -1;
- }
- //(assumes device is already locked)
- //output voice is locked here
- int _kit_kmixerVoiceRemoveInput(kit_kmixerDevice* device,
- Uint32 outputID, Uint32 inputID)
- {
- _kit_kmixerVoice* voiceO = &_VOICE_QUERY(outputID);
- Uint32* inputs = voiceO->inputs->data;
- Uint32 inputs_len = voiceO->inputs->x;
- _IF_GOTO_ERROR(SDL_LockMutex(voiceO->lock),;)
- //remove input voice from output voice's input list
- for(Uint32 v=0; v<inputs_len; ++v){
- if(inputs[v] == inputID){
- inputs[v] = 0; break;
- }
- }
- //trim input list to make sure only active inputs are included
- _IF_GOTO_ERROR(kit_coreVectorTrim(&voiceO->inputs,'x',NULL),;)
- //destroy input list if all inputs have been removed
- if(!voiceO->inputs->lens[0]) kit_coreVectorDestroy(&voiceO->inputs);
- _IF_GOTO_ERROR(SDL_UnlockMutex(voiceO->lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- //(assumes device is already locked)
- //input and output voices are locked here
- //(also, input voice's lock should be created BEFORE calling this)
- int _kit_kmixerVoiceAddInput(kit_kmixerDevice* device,
- Uint32 inputID, Uint32 outputID)
- {
- //since everything relevant is locked currently, i can assign pointers
- //without the risk of the data moving somewhere else by a kit_coreVectorSet or something
- _kit_kmixerVoice* voiceI = &_VOICE_QUERY(inputID);
- _kit_kmixerVoice* voiceO = &_VOICE_QUERY(outputID);
- //set input voice accordingly
- _IF_GOTO_ERROR(SDL_LockMutex(voiceI->lock),;)
- voiceI->output = voiceO->index; // = outputID basically
- voiceI->stereoOutput = voiceO->spec.stereo;
- //set chain processing stage one higher,
- //to ensure this voice is processed before the output
- voiceI->chainStage = voiceO->chainStage+1;
- _IF_GOTO_ERROR(SDL_UnlockMutex(voiceI->lock),;)
- //create input list in output voice if it's NULL
- if(voiceO->inputs == NULL){
- voiceO->inputs = kit_coreVectorCreate(1,1,1, sizeof(Uint32),0);
- _IF_GOTO_ERROR(voiceO->inputs==NULL,;)
- }
- //add input to the output voice's input list
- _IF_GOTO_ERROR(SDL_LockMutex(voiceO->lock),;)
- //first, check to see if input is already in the list...
- Uint32* inputs = voiceO->inputs->data;
- Uint32 inputs_len = voiceO->inputs->x;
- SDL_bool found = SDL_FALSE;
- for(Uint32 i=0; i<inputs_len; ++i){
- if(inputs[i] == inputID){
- found = SDL_TRUE; break;
- }
- }
- //...inserting only if the input was not found in the list
- if(!found) _IF_GOTO_ERROR(kit_coreVectorInsert(&voiceO->inputs, &inputID, 0,0, NULL)==U32_MAX,;)
- _IF_GOTO_ERROR(SDL_UnlockMutex(voiceO->lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_kmixerVoiceRemove(kit_kmixerDevice* device, Uint32 voiceID){
- _DEVICE_VALIDITY_CHECK(0)
- //only allow voice 0 to be removed when device->_closing is set
- _IF_SDLERR(!voiceID && !device->_closing,;,"cannot remove voice 0")
- //if bit 31 is set, call is assumed to be the result of recursion
- SDL_bool rootCall = (!(voiceID&U32_MSb)) ? SDL_TRUE : SDL_FALSE;
- voiceID &= I32_MAX; //unset bit 31 now that rootCall is set
- kit_coreVector** raw_p = &device->_raw;
- _IF_SDLERR(voiceID>=(*raw_p)->x,;,"voiceID out of bounds")
- _IF_GOTO(_VOICE_QUERY(voiceID).lock==NULL,_noerr_,;) //return normally if voice already removed
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- //loop through and remove any inputs the voice might have (recursive)
- if(_VOICE_QUERY(voiceID).inputs != NULL){
- //the voice's inputs vector shouldn't change, since the voice is locked,
- //so it should be safe to do pointer assignment here
- kit_coreVector* inputs = _VOICE_QUERY(voiceID).inputs;
- for(Uint32 i=0; i<inputs->x; ++i){
- Uint32 index = VECTOR_INDEX_C(Uint32, inputs, i);
- if(!index) continue; //an index of 0 indicates a voice that was already removed
- if(_VOICE_QUERY(index).lock != NULL) //(bit 31 is set to indicate recursion)
- _IF_GOTO_ERROR(kit_kmixerVoiceRemove(device,U32_MSb|index),;)
- }
- //(kit_coreVectorDestroy automatically sets pointer to NULL)
- _IF_GOTO_ERROR(kit_coreVectorDestroy(&_VOICE_QUERY(voiceID).inputs),;)
- }
- //free buffers
- SAFE_FREE(_VOICE_QUERY(voiceID).bufferInput.data);
- SAFE_FREE(_VOICE_QUERY(voiceID).bufferUser.data);
- SAFE_FREE(_VOICE_QUERY(voiceID).bufferConvert.data);
- SAFE_FREE(_VOICE_QUERY(voiceID).bufferOutput.data);
- //call the user's 'userdata removal' callback
- if(_VOICE_QUERY(voiceID).spec.remove != NULL)
- _VOICE_QUERY(voiceID).spec.remove(_VOICE_QUERY(voiceID).spec.userdata);
- //destroy lock
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- SDL_DestroyMutex(_VOICE_QUERY(voiceID).lock);
- _VOICE_QUERY(voiceID).lock = NULL; //a mutex of NULL indicates a removed voice
- _VOICE_QUERY(voiceID).chainStage = 0; //(as to not confuse VoiceRebuildOrd)
- if(rootCall){ //if this call is not the result of recursion
- if(!device->_closing) kit_kmixerDeviceLock(device, SDL_TRUE);
- //trim raw and rebuild ord
- _IF_GOTO_ERROR(kit_coreVectorTrim(raw_p,'x',_kit_kmixerVoiceRawUnitCallback),;)
- _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
- //remove input from output's input list
- Uint32 outputID = VECTOR_INDEX_C(_kit_kmixerVoice, *raw_p, voiceID).output;
- if(outputID != U32_MAX){ //(only if output != -1, which should only be possible for voice 0)
- _IF_GOTO_ERROR(_kit_kmixerVoiceRemoveInput(device, outputID,voiceID),
- kit_kmixerDeviceLock(device, SDL_FALSE))
- }
- if(!device->_closing) kit_kmixerDeviceLock(device, SDL_FALSE);
- }
- _noerr_: return 0;
- _error_: return -1;
- }
- Uint32 kit_kmixerVoiceAdd(kit_kmixerDevice* device, kit_kmixerVoiceSpec* vspec,
- Uint32 outputVoiceID)
- {
- Uint32 newIndex = 0; //0 for error by default
- _kit_kmixerVoice voice = { .lock = NULL }; //voice struct to be copied to raw
- _kit_kmixerVoice* voiceI = NULL; //reference to voice inside raw
- SDL_bool inRaw = SDL_FALSE; //set to true if successfully inserted into raw
- SDL_bool success = SDL_FALSE;
- SDL_bool locked = SDL_FALSE;
- _DEVICE_VALIDITY_CHECK(0)
- _IF_SDLERR(vspec==NULL,;,"!vspec")
- _IF_SDLERR(vspec->callback==NULL,;,"!vspec->callback")
- _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_TRUE)<0,;)
- locked = SDL_TRUE;
- //get reference to output voice
- int exists = kit_kmixerVoiceExists(device, outputVoiceID);
- _IF_SDLERR(exists<0,;,"outputVoiceID out of bounds")
- _IF_SDLERR(!exists,;,"output voice doesn't exist")
- //fill in info for voice spec and the voice struct itself
- _IF_GOTO_ERROR(_kit_kmixerVoiceAddFillSpec(device, vspec),;)
- _IF_GOTO_ERROR(_kit_kmixerVoiceAddFillVoice(device, vspec, &voice, outputVoiceID),;)
- voice.device = device; //the only thing not filled in by FillVoice
- //add voice to raw
- newIndex = kit_coreVectorInsert(&device->_raw, &voice, 0,0, _kit_kmixerVoiceRawUnitCallback);
- _IF_GOTO_ERROR(newIndex==U32_MAX,;)
- voiceI = &_VOICE_QUERY(newIndex);
- voiceI->index = newIndex;
- inRaw = SDL_TRUE;
- //add voice to output's input list
- _IF_GOTO_ERROR(_kit_kmixerVoiceAddInput(device, newIndex, outputVoiceID),;)
- //finally, rebuild ord to reflect new state of raw
- _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
- _noerr_:
- success = SDL_TRUE;
- _error_:
- if(!success){
- //the buffer pointers will be the same between voice and *voiceI,
- //and they must be freed either way if this function aborts
- if(!inRaw) voiceI = &voice;
- if(voiceI->lock != NULL) SDL_DestroyMutex(voiceI->lock);
- kit_coreVectorDestroy(&voiceI->inputs);
- SAFE_FREE(voiceI->bufferInput.data);
- SAFE_FREE(voiceI->bufferUser.data);
- SAFE_FREE(voiceI->bufferConvert.data);
- SAFE_FREE(voiceI->bufferOutput.data);
- voiceI->lock = NULL;
- //(make newIndex indicate an error again, regardless of its prev. value)
- newIndex = 0;
- }
- if(locked) kit_kmixerDeviceLock(device, SDL_FALSE);
- return newIndex;
- }
- //updates a voice's chain stage after redirecting
- void _kit_kmixerVoiceCascadeChainStage(kit_kmixerDevice* device, Uint32 voiceID){
- Uint32 outputID = _VOICE_QUERY(voiceID).output;
- //set input voice's chain stage to one higher than the output
- _VOICE_QUERY(voiceID).chainStage = _VOICE_QUERY(outputID).chainStage+1;
- //if input voice itself has inputs, call VoiceCascade on all of them
- //(this should be recursive)
- if(_VOICE_QUERY(voiceID).inputs != NULL){
- kit_coreVector* inputs = _VOICE_QUERY(voiceID).inputs;
- for(Uint32 i=0; i<inputs->x; ++i){
- Uint32 input = VECTOR_INDEX_C(Uint32, inputs, i);
- if(!input) continue; //skip any invalid or removed voices
- _kit_kmixerVoiceCascadeChainStage(device,input);
- }
- }
- }
- int kit_kmixerVoiceRedirect(kit_kmixerDevice* device,
- Uint32 inputVoiceID, Uint32 outputVoiceID)
- {
- int returnStatus = 0;
- SDL_bool locked = SDL_FALSE;
- _DEVICE_VALIDITY_CHECK(0)
- _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_TRUE)<0,;)
- locked = SDL_TRUE;
- _IF_SDLERR(!inputVoiceID,;,"cannot redirect voice 0")
- int exists = kit_kmixerVoiceExists(device, inputVoiceID);
- _IF_SDLERR(exists<0,;,"inputVoiceID out of bounds")
- _IF_SDLERR(!exists,;,"input voice doesn't exist")
- exists = kit_kmixerVoiceExists(device, outputVoiceID);
- _IF_SDLERR(exists<0,;,"outputVoiceID out of bounds")
- _IF_SDLERR(!exists,;,"output voice doesn't exist")
- _IF_SDLERR(_VOICE_QUERY(outputVoiceID).output==inputVoiceID,;,"output can't be circular")
- //disconnect from the old output, before connecting to the new output
- Uint32 outputVoiceID_old = _VOICE_QUERY(inputVoiceID).output;
- _IF_GOTO_ERROR(_kit_kmixerVoiceRemoveInput(device, outputVoiceID_old, inputVoiceID),;)
- _IF_GOTO_ERROR(_kit_kmixerVoiceAddInput(device, inputVoiceID, outputVoiceID),;)
- //update every chainStage value up the voice chain,
- //to accomodate the stage of the new output
- _kit_kmixerVoiceCascadeChainStage(device,inputVoiceID);
- //update ord to reflect changes
- _IF_GOTO_ERROR(_kit_kmixerVoiceRebuildOrd(device),;)
- _noerr_: ++returnStatus;
- _error_: --returnStatus;
- if(locked && kit_kmixerDeviceLock(device, SDL_FALSE)<0) returnStatus = -1;
- return returnStatus;
- }
- int kit_kmixerVoiceExists(kit_kmixerDevice* device, Uint32 voiceID){
- _DEVICE_VALIDITY_CHECK(0)
- _IF_SDLERR(voiceID>=device->_raw->x,;,"voiceID out of bounds")
- _noerr_: return _VOICE_QUERY(voiceID).lock != NULL;
- _error_: return -1;
- }
- Uint32 kit_kmixerVoiceGetNumInputs(kit_kmixerDevice* device, Uint32 voiceID){
- _VOICE_CHECK(voiceID)
- if(_VOICE_QUERY(voiceID).inputs == NULL) return 0;
- /*!err*/ return _VOICE_QUERY(voiceID).inputs->x;
- _error_: return U32_MAX;
- }
- kit_coreVector* kit_kmixerVoiceGetInputs(kit_kmixerDevice* device, Uint32 voiceID){
- kit_coreVector* inputs = NULL;
- _VOICE_CHECK(voiceID)
- _IF_SDLERR(_VOICE_QUERY(voiceID).inputs==NULL,;,"no inputs found")
- inputs = kit_coreVectorCopy(_VOICE_QUERY(voiceID).inputs);
- _error_:
- return inputs;
- }
- Uint32 kit_kmixerVoiceGetOutput(kit_kmixerDevice* device, Uint32 voiceID){
- _VOICE_CHECK(voiceID)
- _IF_SDLERR(_VOICE_QUERY(voiceID).output==U32_MAX,;,"voice 0 has no output!")
- /*!err*/ return _VOICE_QUERY(voiceID).output;
- _error_: return U32_MAX;
- }
- SDL_bool* kit_kmixerVoiceGetActiveRef(kit_kmixerDevice* device, Uint32 voiceID){
- _VOICE_CHECK(voiceID)
- /*!err*/ return &_VOICE_QUERY(voiceID).active;
- _error_: return NULL;
- }
- int kit_kmixerVoiceGetActive(kit_kmixerDevice* device, Uint32 voiceID){
- _VOICE_CHECK(voiceID)
- /*!err*/ return _VOICE_QUERY(voiceID).active;
- _error_: return -1;
- }
- int kit_kmixerVoiceSetActive(kit_kmixerDevice* device, Uint32 voiceID, SDL_bool isActive){
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- _VOICE_QUERY(voiceID).active = isActive;
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- void _kit_kmixerVoiceCascadeActive(kit_kmixerDevice* device, Uint32 voiceID, SDL_bool isActive){
- _VOICE_QUERY(voiceID).active = isActive;
- //recursively set the active state on all input voices (if there are any)
- if(_VOICE_QUERY(voiceID).inputs != NULL){
- //it should be safe to dereference inputs here, since the whole device
- //should be locked at this point
- Uint32* inputs = _VOICE_QUERY(voiceID).inputs->data;
- Uint32 inputs_len = _VOICE_QUERY(voiceID).inputs->x;
- for(Uint32 i=0; i<inputs_len; ++i){
- if(!inputs[i]) continue; //skip any invalid or removed voices
- _kit_kmixerVoiceCascadeActive(device,inputs[i], isActive);
- }
- }
- }
- int kit_kmixerVoiceSetActiveChain(kit_kmixerDevice* device, Uint32 voiceID, SDL_bool isActive){
- int returnStatus = 0;
- SDL_bool locked = SDL_FALSE;
- _DEVICE_VALIDITY_CHECK(0)
- _IF_GOTO_ERROR(kit_kmixerDeviceLock(device, SDL_TRUE)<0,;)
- locked = SDL_TRUE;
- //now that the device is locked, CascadeActive can safely be called,
- //(much like CascadeChainStage)
- _kit_kmixerVoiceCascadeActive(device, voiceID, isActive);
- _noerr_: ++returnStatus;
- _error_: --returnStatus;
- if(locked && kit_kmixerDeviceLock(device, SDL_FALSE)<0) returnStatus = -1;
- return returnStatus;
- }
- Uint32 kit_kmixerVoiceGetChainStage(kit_kmixerDevice* device, Uint32 voiceID){
- _VOICE_CHECK(voiceID)
- /*!err*/ return _VOICE_QUERY(voiceID).chainStage;
- _error_: return U32_MAX;
- }
- kit_kmixerVoiceSpec kit_kmixerVoiceGetSpec(kit_kmixerDevice* device, Uint32 voiceID){
- kit_kmixerVoiceSpec vspec = {0};
- _VOICE_CHECK(voiceID)
- vspec = _VOICE_QUERY(voiceID).spec;
- _error_:
- return vspec;
- }
- kit_kmixerVoiceSpec* kit_kmixerVoiceGetSpecRef(kit_kmixerDevice* device, Uint32 voiceID){
- _VOICE_CHECK(voiceID)
- /*!err*/ return &_VOICE_QUERY(voiceID).spec;
- _error_: return NULL;
- }
- void* kit_kmixerVoiceGetSpecUserdata(kit_kmixerDevice* device, Uint32 voiceID){
- _IF_SDLERR(!voiceID,;,"voice 0 has no userdata")
- _VOICE_CHECK(voiceID)
- /*!err*/ return _VOICE_QUERY(voiceID).spec.userdata;
- _error_: return NULL;
- }
- int kit_kmixerVoiceSetSpecRemove(kit_kmixerDevice* device, Uint32 voiceID,
- kit_kmixerVoiceRemoveCallback remove)
- {
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- _VOICE_QUERY(voiceID).spec.remove = remove;
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_kmixerVoiceSetSpecCallback(kit_kmixerDevice* device, Uint32 voiceID,
- kit_kmixerVoiceCallback callback)
- {
- //(remove and userdata can be NULL, but the voice callback itself cannot)
- _IF_SDLERR(callback==NULL,;,"!callback")
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- _VOICE_QUERY(voiceID).spec.callback = callback;
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_kmixerVoiceSetSpecUserdata(kit_kmixerDevice* device, Uint32 voiceID, void* userdata){
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- _VOICE_QUERY(voiceID).spec.userdata = userdata;
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- float kit_kmixerVoiceGetVolL(kit_kmixerDevice* device, Uint32 voiceID){
- _VOICE_CHECK(voiceID)
- /*!err*/ return _VOICE_QUERY(voiceID).volL;
- _error_: return NAN;
- }
- float kit_kmixerVoiceGetVolR(kit_kmixerDevice* device, Uint32 voiceID){
- _VOICE_CHECK(voiceID)
- /*!err*/ return _VOICE_QUERY(voiceID).volR;
- _error_: return NAN;
- }
- int kit_kmixerVoiceSetVolL(kit_kmixerDevice* device, Uint32 voiceID, float volL){
- _IF_SDLERR(volL<0,;,"volL must be >=0")
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- _VOICE_QUERY(voiceID).volL = volL;
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_kmixerVoiceSetVolR(kit_kmixerDevice* device, Uint32 voiceID, float volR){
- _IF_SDLERR(volR<0,;,"volR must be >=0")
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- _VOICE_QUERY(voiceID).volR = volR;
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_kmixerVoiceSetVolume(kit_kmixerDevice* device, Uint32 voiceID, float volL, float volR){
- _IF_SDLERR(volL<0,;,"volL must be >=0")
- _IF_SDLERR(volR<0,;,"volR must be >=0")
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- _VOICE_QUERY(voiceID).volL = volL;
- _VOICE_QUERY(voiceID).volR = volR;
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_kmixerVoiceSetPan(kit_kmixerDevice* device, Uint32 voiceID, float pan){
- _IF_SDLERR(!NORMALIZED(pan),;,"pan must be -1.0f -> 1.0f")
- _VOICE_CHECK(voiceID)
- _IF_SDLERR(_VOICE_QUERY(voiceID).spec.stereo,;,"voice cannot be mono")
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- //for example, if pan = -0.6f, volL and volR would be 1.0f and 0.4f respectively
- _VOICE_QUERY(voiceID).volL = MIN(1.0f+pan, 1.0f);
- _VOICE_QUERY(voiceID).volR = MIN(1.0f-pan, 1.0f);
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_kmixerVoiceUnlock(kit_kmixerDevice* device, Uint32 voiceID){
- _IF_SDLERR(!voiceID,;,"cannot unlock voice 0")
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_UnlockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_kmixerVoiceLock(kit_kmixerDevice* device, Uint32 voiceID){
- _IF_SDLERR(!voiceID,;,"cannot lock voice 0")
- _VOICE_CHECK(voiceID)
- _IF_GOTO_ERROR(SDL_LockMutex(_VOICE_QUERY(voiceID).lock),;)
- /*!err*/ return 0;
- _error_: return -1;
- }
- #if defined(_KIT_KMIXER_DEBUG) || defined(_KIT_ALL_DEBUG)
- void _kit_kmixerVoice_TestCallback(void* userdata, void* _stream, int size, SDL_bool hasInput){
- }
- /*
- because kmixer compiles with -O3, i get this error if i attempt to compile the test:
- "warning: may be used uninitialized in this function [-Wmaybe-uninitialized]|"
- i have very little doubt that this is a bug, so i can't do much about it other than
- turn down optimization for this specific function
- */
- //(for some reason, it started working again after i added some seemingly
- //unrelated stuff, so i'll comment this out for now)
- //__attribute__((optimize("-O0")))
- int kit_kmixerVoice_Test(){
- float bufferInputA[16], bufferUserA[16], bufferConvertA[16], bufferOutputA[16];
- float bufferInputB[16], bufferUserB[16], bufferConvertB[16], bufferOutputB[16];
- float bufferInputC[16], bufferUserC[16], bufferConvertC[16], bufferOutputC[16];
- _kit_kmixerVoice voiceA={
- .spec={
- .callback = _kit_kmixerVoice_TestCallback,
- .userdata = NULL,
- .freq = 44100,
- ._size = 16*sizeof(float),
- .stereo = SDL_FALSE,
- .samples = 16,
- .format = AUDIO_F32
- },
- .bufferInput = { .data=bufferInputA },
- .bufferUser = { .data=bufferUserA },
- .bufferConvert = { .data=bufferConvertA },
- .bufferOutput = { .data=bufferOutputA },
- .inputs = NULL,
- .lock = NULL,
- .chainStage = 2,
- .index = 3,
- .volL = 1.0f,
- .volR = 1.0f,
- .stereoOutput = SDL_FALSE,
- };
- _kit_kmixerVoice voiceB={
- .spec={
- .callback = _kit_kmixerVoice_TestCallback,
- .userdata = NULL,
- .freq = 44100,
- ._size = 16*sizeof(float),
- .stereo = SDL_FALSE,
- .samples = 16,
- .format = AUDIO_F32
- },
- .bufferInput = { .data=bufferInputB },
- .bufferUser = { .data=bufferUserB },
- .bufferConvert = { .data=bufferConvertB },
- .bufferOutput = { .data=bufferOutputB },
- .inputs = NULL,
- .lock = NULL,
- .chainStage = 2,
- .index = 2,
- .volL = 1.0f,
- .volR = 1.0f,
- .stereoOutput = SDL_FALSE,
- };
- _kit_kmixerVoice voiceC={
- .spec={
- .callback = _kit_kmixerVoice_TestCallback,
- .userdata = NULL,
- .freq = 44100,
- ._size = 16*sizeof(float),
- .stereo = SDL_FALSE,
- .samples = 16,
- .format = AUDIO_F32
- },
- .bufferInput = { .data=bufferInputC },
- .bufferUser = { .data=bufferUserC },
- .bufferConvert = { .data=bufferConvertC },
- .bufferOutput = { .data=bufferOutputC },
- .inputs = NULL,
- .lock = NULL,
- .chainStage = 1,
- .index = 1,
- .volL = 1.0f,
- .volR = 1.0f,
- .stereoOutput = SDL_FALSE,
- };
- //example streams
- Uint8 u_8_A[16]={0x00,0x3F,0x10,0x80,0xFF,0x4E,0x24,0x6D,0x21,0xFE,0xED,0x86,0x3A,0xAB,0xDA,0x4C};
- Sint16 i16_A[16]={-32768,13106,-16384,6553,32767,2553,-26214,25937,22337,-13102,9553,-32467,-9830,0,-19661,-22938};
- Sint32 i32_A[16]={-2147483648,2147483647,2,547760950,-978102134,-1901782676,973752665,-2054956051,-1793070550,2100284199,1386177656,-70287364,-799099289,-594127329,1025429360,-570645197};
- 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};
- 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};
- //test to and from type conversion
- //u_8
- SDL_memcpy(voiceA.bufferUser.u_8, u_8_A, 16*sizeof(Uint8));
- _kit_kmixerVoiceProcFromType(voiceA.bufferUser.u_8,voiceA.bufferConvert.f32, 16,AUDIO_U8,SDL_FALSE);
- _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.u_8, 16,AUDIO_U8,SDL_FALSE);
- for(Uint32 i=0; i<16; ++i){
- if(voiceA.bufferUser.u_8[i] != MAX(u_8_A[i],1)){
- SDL_SetError("u_8 type conv. (%u:%X!=%X)",
- i, voiceA.bufferUser.u_8[i], MAX(u_8_A[i],1) ); return -999;
- }
- }
- //i16
- SDL_memcpy(voiceA.bufferUser.i16, i16_A, 16*sizeof(Sint16));
- _kit_kmixerVoiceProcFromType(voiceA.bufferUser.i16,voiceA.bufferConvert.f32, 16,AUDIO_S16,SDL_FALSE);
- _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.i16, 16,AUDIO_S16,SDL_FALSE);
- for(Uint32 i=0; i<16; ++i){
- if(voiceA.bufferUser.i16[i] != MAX(i16_A[i],-32767)){
- SDL_SetError("i16 type conv. (%u:%i!=%i)",
- i, voiceA.bufferUser.i16[i], MAX(i16_A[i],-32767) ); return -999;
- }
- }
- //i32 (products of conversion are actually approximations with a max error of 64)
- SDL_memcpy(voiceA.bufferUser.i32, i32_A, 16*sizeof(Sint32));
- _kit_kmixerVoiceProcFromType(voiceA.bufferUser.i32,voiceA.bufferConvert.f32, 16,AUDIO_S32,SDL_FALSE);
- _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.i32, 16,AUDIO_S32,SDL_FALSE);
- for(Uint32 i=0; i<16; ++i){
- if((voiceA.bufferUser.i32[i] < (MAX(i32_A[i],-2147483647)-64)) &&
- (voiceA.bufferUser.i32[i] > (MAX(i32_A[i],-2147483647)+64)))
- {
- SDL_SetError("i32 type conv. (%u:%i!=%i)",
- i, voiceA.bufferUser.i32[i], MAX(i32_A[i],-2147483647) ); return -999;
- }
- }
- //f32
- SDL_memcpy(voiceA.bufferUser.f32, f32_A, 16*sizeof(float));
- _kit_kmixerVoiceProcFromType(voiceA.bufferUser.f32,voiceA.bufferConvert.f32, 16,AUDIO_F32,SDL_FALSE);
- _kit_kmixerVoiceProcToType(voiceA.bufferConvert.f32,voiceA.bufferUser.f32, 16,AUDIO_F32,SDL_FALSE);
- for(Uint32 i=0; i<16; ++i){
- if(voiceA.bufferUser.f32[i] != CLAMP(f32_A[i], -1.0f,1.0f)){
- SDL_SetError("f32 type conv. (%u:%.1f!=%.1f)",
- i, voiceA.bufferUser.f32[i], CLAMP(f32_A[i], -1.0f,1.0f) ); return -999;
- }
- }
- //test channel conversion
- // mono-stereo
- _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32s, 8,_M_to_S);
- for(Uint32 i=0; i<16; i+=2){
- //kit_coreLog("%2u: %9f, %9f",i, voiceA.bufferConvert.m[i], voiceA.bufferConvert.m[i+1]);
- if(voiceA.bufferConvert.f32[i] != voiceA.bufferConvert.f32[i+1]){
- SDL_SetError("mn.->st. convert (%u:%.1f!=%.1f)",
- i, voiceA.bufferConvert.f32[i], voiceA.bufferConvert.f32[i+1] ); return -999;
- }
- }
- //stereo-mono
- _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32, 8,_S_to_M);
- for(Uint32 i=0; i<16; i+=2){
- //kit_coreLog("%2u: %9f,%9f -> %9f",i, f32_A[i],f32_A[i+1], voiceA.bufferConvert.m[i>>1]);
- if(voiceA.bufferConvert.f32[i>>1] != (f32_A[i]+f32_A[i+1])*.5f){
- SDL_SetError("st.->mn. convert (%u:%.1f!=%.1f)",
- i, voiceA.bufferConvert.f32[i>>1], (f32_A[i]+f32_A[i+1])*.5f ); return -999;
- }
- }
- //stereo-stereo
- _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32s, 8,_S_to_S);
- for(Uint32 i=0; i<16; ++i){
- //kit_coreLog("%2u: %9f",i, voiceA.bufferConvert.m[i]);
- if(voiceA.bufferConvert.f32[i] != f32_A[i]){
- SDL_SetError("st.->st. convert (%u:%.1f!=%.1f)",
- i, voiceA.bufferConvert.f32[i], f32_A[i] ); return -999;
- }
- }
- // mono-mono
- _kit_kmixerVoiceProcChannels(f32_A, voiceA.bufferConvert.f32, 16,_M_to_M);
- for(Uint32 i=0; i<16; ++i){
- //kit_coreLog("%2u: %9f",i, voiceA.bufferConvert.m[i]);
- if(voiceA.bufferConvert.f32[i] != f32_A[i]){
- SDL_SetError("mn.->mn. convert (%u:%.1f!=%.1f)",
- i, voiceA.bufferConvert.f32[i], f32_A[i] ); return -999;
- }
- }
- //test VoiceProc itself here
- //test mixing (might want to add in other volume settings at some point)
- voiceA.lock=SDL_CreateMutex();
- voiceB.lock=SDL_CreateMutex();
- voiceC.lock=SDL_CreateMutex();
- kit_coreVector* ivoices=kit_coreVectorCreate(2,0,0, sizeof(_kit_kmixerVoice),0);
- if(voiceA.lock==NULL || voiceB.lock==NULL || voiceC.lock==NULL || ivoices==NULL){
- if(voiceA.lock != NULL) SDL_DestroyMutex(voiceA.lock);
- if(voiceB.lock != NULL) SDL_DestroyMutex(voiceB.lock);
- if(voiceC.lock != NULL) SDL_DestroyMutex(voiceC.lock);
- if(ivoices != NULL) kit_coreVectorDestroy(&ivoices);
- }
- SDL_memcpy(voiceA.bufferOutput.f32, f32_A, 16*sizeof(float));
- SDL_memcpy(voiceB.bufferOutput.f32, f32_B, 16*sizeof(float));
- _kit_kmixerVoice _ivoices[2]={voiceA,voiceB};
- memcpy(ivoices->data, _ivoices, sizeof(_kit_kmixerVoice)*2);
- //mono, 1.0,1.0
- //_kit_kmixerVoiceMix(&voiceC);
- for(Uint32 i=0; i<16; ++i){
- float mixed=voiceC.bufferInput.f32[i];
- float real=CLAMP(voiceA.bufferOutput.f32[i]+voiceB.bufferOutput.f32[i], -1.0f,1.0f);
- if(mixed != real){ SDL_SetError("mn. mixing (%u:%.1f!=%.1f)",
- i, mixed, real ); return -999;
- }
- }
- //stereo, 1.0,1.0
- voiceA.stereoOutput=SDL_TRUE;
- voiceB.stereoOutput=SDL_TRUE;
- voiceA.spec.samples=8;
- voiceB.spec.samples=8;
- voiceC.spec.samples=8;
- //_kit_kmixerVoiceMix(&voiceC);
- for(Uint32 i=0; i<16; ++i){
- float mixed=voiceC.bufferInput.f32[i];
- float real=CLAMP(voiceA.bufferOutput.f32[i]+voiceB.bufferOutput.f32[i], -1.0f,1.0f);
- if(mixed != real){ SDL_SetError("st. mixing (%u:%.1f!=%.1f)",
- i, mixed, real ); return -999;
- }
- }
- if(voiceA.lock != NULL) SDL_DestroyMutex(voiceA.lock);
- if(voiceB.lock != NULL) SDL_DestroyMutex(voiceB.lock);
- if(voiceC.lock != NULL) SDL_DestroyMutex(voiceC.lock);
- if(ivoices != NULL) kit_coreVectorDestroy(&ivoices);
- //test adding and removing possibly
- //kit_coreLog("sizeof(_kit_kmixerVoice)=%u",(unsigned int)sizeof(_kit_kmixerVoice));
- return 0;
- }
- void kit_kmixerVoicePrintRawOrd(kit_kmixerDevice* device){
- kit_coreVector** raw_p = &device->_raw;
- kit_coreVector** ord_p = &device->_ord;
- Uint32 rawLen = (*raw_p)->x;
- Uint32 ordLen = (*ord_p)->x;
- Uint32 maxStage = (*ord_p)->y-1;
- _kit_kmixerVoice* raw = (*raw_p)->data;
- _kit_kmixerVoice** ord = (*ord_p)->data;
- printf("\n~~~ RAW ~~~\n");
- for(Uint32 v=0; v<rawLen; ++v){
- _kit_kmixerVoice* voice = &raw[v];
- printf("--- %02u/%02u (%p) ---\n", v, rawLen-1, voice);
- if(voice->lock == NULL){ printf(" (REMOVED)\n"); continue; }
- Uint32 numInputs = 0, *inputs = NULL;
- if(voice->inputs != NULL){
- numInputs = voice->inputs->x;
- inputs = voice->inputs->data;
- }
- printf(" voice%u->inputs = %p: ",v, voice->inputs);
- if(inputs != NULL){
- printf("{\n ");
- for(Uint32 i=0; i<numInputs; ++i){
- if(inputs[i]!=0) printf("%02u, ",inputs[i]);
- else printf("RM, "); //removed voice
- if((i+1)==numInputs) printf("\n");
- else if((i%5)==4) printf("\n ");
- }
- printf(" }\n");
- } else printf("(NULL)\n");
- printf(" voice%u->output = %2i\n",v, voice->output);
- printf(" voice%u->chainStage = %2u\n",v, voice->chainStage);
- printf(" voice%u->active = %s\n", v, boolstr[voice->active]);
- printf(" voice%u->spec = {\n", v);
- printf(" .remove = %p\n",voice->spec.remove);
- printf(" .callback = %p\n",voice->spec.callback);
- printf(" .userdata = %p\n",voice->spec.userdata);
- printf(" .freq = %i\n",voice->spec.freq);
- printf(" ._size = %u\n",voice->spec._size);
- printf(" .stereo = %s\n",boolstr[voice->spec.stereo]);
- printf(" .samples = %u\n",voice->spec.samples);
- printf(" .format = %X\n",voice->spec.format);
- printf(" }\n");
- printf("\n");
- }
- printf("\n~~~ ORD ~~~\n");
- for(Uint32 yi=maxStage; yi!=U32_MAX; --yi){
- printf("stage %02u: ", yi);
- for(Uint32 xi=0; xi<ordLen; ++xi){
- _kit_kmixerVoice* voice = ord[xi + yi*ordLen];
- if(voice == NULL) printf("NL, ");
- else if(voice->lock == NULL) printf("RM, ");
- else printf("%02u, ",voice->index);
- }
- printf("\n");
- }
- printf("\n");
- }
- #else
- int kit_kmixerVoice_Test(){
- SDL_SetError("!defined(_KIT_KMIXER_DEBUG)");
- return 999;
- }
- void kit_kmixerVoicePrintRawOrd(kit_kmixerDevice* device){}
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement