diff --git a/miniaudio.h b/miniaudio.h index 821fa8a4..2aeb3e65 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -2460,8 +2460,8 @@ typedef struct ma_lpf lpf; } ma_linear_resampler; -MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler); -MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler); +MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_linear_resampler* pResampler); +MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks); MA_API ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut); @@ -38777,10 +38777,12 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes return MA_SUCCESS; } -MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler) +MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_linear_resampler* pResampler) { ma_result result; + (void)pAllocationCallbacks; + if (pResampler == NULL) { return MA_INVALID_ARGS; } @@ -38813,11 +38815,13 @@ MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pCon return MA_SUCCESS; } -MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler) +MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks) { if (pResampler == NULL) { return; } + + (void)pAllocationCallbacks; } static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma_int32 a, const ma_int32 shift) @@ -39335,14 +39339,11 @@ static ma_result ma_resampling_backend_init__linear(void* pUserData, const ma_re ma_result result; ma_linear_resampler_config linearConfig; - /* No need for a malloc for the linear resampler because we store the state inside the ma_resampler object itself. */ - (void)pAllocationCallbacks; - linearConfig = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut); linearConfig.lpfOrder = pConfig->linear.lpfOrder; linearConfig.lpfNyquistFactor = pConfig->linear.lpfNyquistFactor; - result = ma_linear_resampler_init(&linearConfig, &pResampler->state.linear); + result = ma_linear_resampler_init(&linearConfig, pAllocationCallbacks, &pResampler->state.linear); if (result != MA_SUCCESS) { return result; } @@ -39355,9 +39356,8 @@ static ma_result ma_resampling_backend_init__linear(void* pUserData, const ma_re static void ma_resampling_backend_uninit__linear(void* pUserData, ma_resampling_backend* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) { (void)pUserData; - (void)pAllocationCallbacks; - ma_linear_resampler_uninit((ma_linear_resampler*)pBackend); + ma_linear_resampler_uninit((ma_linear_resampler*)pBackend, pAllocationCallbacks); } static ma_result ma_resampling_backend_process__linear(void* pUserData, ma_resampling_backend* pBackend, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 100a81f0..184e705c 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -892,7 +892,7 @@ typedef struct small reduction in latency as it allows miniaudio to calculate the exact number of input frames to read at a time instead of having to estimate. */ - ma_uint32 (* onGetRequiredInputFrameCount)(ma_node* pNode, ma_uint32 outputFrameCount); + ma_result (* onGetRequiredInputFrameCount)(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount); /* The number of input buses. This is how many sub-buffers will be contained in the `ppFramesIn` @@ -1850,7 +1850,7 @@ typedef struct ma_engine* pEngine; /* A pointer to the engine. Set based on the value from the config. */ ma_uint32 sampleRate; /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */ ma_fader fader; - ma_resampler resampler; /* For pitch shift. May change this to ma_linear_resampler later. */ + ma_linear_resampler resampler; /* For pitch shift. */ ma_spatializer spatializer; ma_panner panner; MA_ATOMIC float pitch; @@ -5067,7 +5067,7 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde framesToProcessIn = frameCount; if (pNodeBase->vtable->onGetRequiredInputFrameCount) { - framesToProcessIn = pNodeBase->vtable->onGetRequiredInputFrameCount(pNode, framesToProcessOut); + pNodeBase->vtable->onGetRequiredInputFrameCount(pNode, framesToProcessOut, &framesToProcessIn); /* <-- It does not matter if this fails. */ } if (framesToProcessIn > pNodeBase->cachedDataCapInFramesPerBus) { framesToProcessIn = pNodeBase->cachedDataCapInFramesPerBus; @@ -12163,7 +12163,7 @@ static void ma_engine_node_update_pitch_if_required(ma_engine_node* pEngineNode) if (isUpdateRequired) { float basePitch = (float)pEngineNode->sampleRate / ma_engine_get_sample_rate(pEngineNode->pEngine); - ma_resampler_set_rate_ratio(&pEngineNode->resampler, basePitch * pEngineNode->oldPitch * pEngineNode->oldDopplerPitch); + ma_linear_resampler_set_rate_ratio(&pEngineNode->resampler, basePitch * pEngineNode->oldPitch * pEngineNode->oldDopplerPitch); } } @@ -12184,11 +12184,18 @@ static ma_bool32 ma_engine_node_is_spatialization_enabled(const ma_engine_node* static ma_uint64 ma_engine_node_get_required_input_frame_count(const ma_engine_node* pEngineNode, ma_uint64 outputFrameCount) { + ma_uint64 inputFrameCount = 0; + if (ma_engine_node_is_pitching_enabled(pEngineNode)) { - return ma_resampler_get_required_input_frame_count(&pEngineNode->resampler, outputFrameCount); + ma_result result = ma_linear_resampler_get_required_input_frame_count(&pEngineNode->resampler, outputFrameCount, &inputFrameCount); + if (result != MA_SUCCESS) { + inputFrameCount = 0; + } } else { - return outputFrameCount; /* No resampling, so 1:1. */ + inputFrameCount = outputFrameCount; /* No resampling, so 1:1. */ } + + return inputFrameCount; } static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) @@ -12272,7 +12279,7 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo ma_uint64 resampleFrameCountIn = framesAvailableIn; ma_uint64 resampleFrameCountOut = framesAvailableOut; - ma_resampler_process_pcm_frames(&pEngineNode->resampler, pRunningFramesIn, &resampleFrameCountIn, pWorkingBuffer, &resampleFrameCountOut); + ma_linear_resampler_process_pcm_frames(&pEngineNode->resampler, pRunningFramesIn, &resampleFrameCountIn, pWorkingBuffer, &resampleFrameCountOut); isWorkingBufferValid = MA_TRUE; framesJustProcessedIn = (ma_uint32)resampleFrameCountIn; @@ -12474,19 +12481,23 @@ static void ma_engine_node_process_pcm_frames__group(ma_node* pNode, const float ma_engine_node_process_pcm_frames__general((ma_engine_node*)pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut); } -static ma_uint32 ma_engine_node_get_required_input_frame_count__group(ma_node* pNode, ma_uint32 outputFrameCount) +static ma_result ma_engine_node_get_required_input_frame_count__group(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount) { - ma_uint64 result; + ma_uint64 inputFrameCount; + + MA_ASSERT(pInputFrameCount != NULL); /* Our pitch will affect this calculation. We need to update it. */ ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode); - result = ma_engine_node_get_required_input_frame_count((ma_engine_node*)pNode, outputFrameCount); - if (result > 0xFFFFFFFF) { - result = 0xFFFFFFFF; /* Will never happen because miniaudio will only ever process in relatively small chunks. */ + inputFrameCount = ma_engine_node_get_required_input_frame_count((ma_engine_node*)pNode, outputFrameCount); + if (inputFrameCount > 0xFFFFFFFF) { + inputFrameCount = 0xFFFFFFFF; /* Will never happen because miniaudio will only ever process in relatively small chunks. */ } - return (ma_uint32)result; + *pInputFrameCount = (ma_uint32)inputFrameCount; + + return MA_SUCCESS; } @@ -12623,7 +12634,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p ma_result result; ma_engine_node_heap_layout heapLayout; ma_node_config baseNodeConfig; - ma_resampler_config resamplerConfig; + ma_linear_resampler_config resamplerConfig; ma_fader_config faderConfig; ma_spatializer_config spatializerConfig; ma_panner_config pannerConfig; @@ -12680,10 +12691,10 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p */ /* We'll always do resampling first. */ - resamplerConfig = ma_resampler_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], pEngineNode->sampleRate, ma_engine_get_sample_rate(pEngineNode->pEngine), ma_resample_algorithm_linear); - resamplerConfig.linear.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ + resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], pEngineNode->sampleRate, ma_engine_get_sample_rate(pEngineNode->pEngine)); + resamplerConfig.lpfOrder = 0; /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */ - result = ma_resampler_init(&resamplerConfig, &pEngineNode->pEngine->allocationCallbacks, &pEngineNode->resampler); /* TODO: Use pre-allocation here. */ + result = ma_linear_resampler_init(&resamplerConfig, &pEngineNode->pEngine->allocationCallbacks, &pEngineNode->resampler); /* TODO: Use pre-allocation here. */ if (result != MA_SUCCESS) { goto error1; } @@ -12725,7 +12736,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p return MA_SUCCESS; error3: ma_spatializer_uninit(&pEngineNode->spatializer, NULL); /* <-- No need for allocation callbacks here because we use a preallocated heap. */ -error2: ma_resampler_uninit(&pEngineNode->resampler, &pConfig->pEngine->allocationCallbacks); /* TODO: Remove this when we have support for preallocated heaps with resamplers. */ +error2: ma_linear_resampler_uninit(&pEngineNode->resampler, &pConfig->pEngine->allocationCallbacks); /* TODO: Remove this when we have support for preallocated heaps with resamplers. */ error1: ma_node_uninit(&pEngineNode->baseNode, NULL); /* <-- No need for allocation callbacks here because we use a preallocated heap. */ error0: return result; } @@ -12770,7 +12781,7 @@ MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocati /* Now that the node has been uninitialized we can safely uninitialize the rest. */ ma_spatializer_uninit(&pEngineNode->spatializer, NULL); - ma_resampler_uninit(&pEngineNode->resampler, NULL); + ma_linear_resampler_uninit(&pEngineNode->resampler, NULL); /* Free the heap last. */ if (pEngineNode->_pHeap != NULL && pEngineNode->_ownsHeap) { @@ -14286,7 +14297,7 @@ MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, } if (pSampleRate != NULL) { - *pSampleRate = pSound->engineNode.resampler.sampleRateIn; + *pSampleRate = pSound->engineNode.resampler.config.sampleRateIn; } if (pChannelMap != NULL) {