Commit 3fd7af72 authored by David Reid's avatar David Reid

Fix some issues with resampling in the engine.

parent 562b0ffe
...@@ -2460,8 +2460,8 @@ typedef struct ...@@ -2460,8 +2460,8 @@ typedef struct
ma_lpf lpf; ma_lpf lpf;
} ma_linear_resampler; } ma_linear_resampler;
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_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);
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_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(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); 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 ...@@ -38777,10 +38777,12 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes
return MA_SUCCESS; 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; ma_result result;
(void)pAllocationCallbacks;
if (pResampler == NULL) { if (pResampler == NULL) {
return MA_INVALID_ARGS; return MA_INVALID_ARGS;
} }
...@@ -38813,11 +38815,13 @@ MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pCon ...@@ -38813,11 +38815,13 @@ MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pCon
return MA_SUCCESS; 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) { if (pResampler == NULL) {
return; 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) 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 ...@@ -39335,14 +39339,11 @@ static ma_result ma_resampling_backend_init__linear(void* pUserData, const ma_re
ma_result result; ma_result result;
ma_linear_resampler_config linearConfig; 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 = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut);
linearConfig.lpfOrder = pConfig->linear.lpfOrder; linearConfig.lpfOrder = pConfig->linear.lpfOrder;
linearConfig.lpfNyquistFactor = pConfig->linear.lpfNyquistFactor; 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) { if (result != MA_SUCCESS) {
return result; return result;
} }
...@@ -39355,9 +39356,8 @@ static ma_result ma_resampling_backend_init__linear(void* pUserData, const ma_re ...@@ -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) static void ma_resampling_backend_uninit__linear(void* pUserData, ma_resampling_backend* pBackend, const ma_allocation_callbacks* pAllocationCallbacks)
{ {
(void)pUserData; (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) 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)
...@@ -892,7 +892,7 @@ typedef struct ...@@ -892,7 +892,7 @@ typedef struct
small reduction in latency as it allows miniaudio to calculate the exact number of input frames 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. 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` The number of input buses. This is how many sub-buffers will be contained in the `ppFramesIn`
...@@ -1850,7 +1850,7 @@ typedef struct ...@@ -1850,7 +1850,7 @@ typedef struct
ma_engine* pEngine; /* A pointer to the engine. Set based on the value from the config. */ 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_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_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_spatializer spatializer;
ma_panner panner; ma_panner panner;
MA_ATOMIC float pitch; MA_ATOMIC float pitch;
...@@ -5067,7 +5067,7 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde ...@@ -5067,7 +5067,7 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde
framesToProcessIn = frameCount; framesToProcessIn = frameCount;
if (pNodeBase->vtable->onGetRequiredInputFrameCount) { 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) { if (framesToProcessIn > pNodeBase->cachedDataCapInFramesPerBus) {
framesToProcessIn = pNodeBase->cachedDataCapInFramesPerBus; framesToProcessIn = pNodeBase->cachedDataCapInFramesPerBus;
...@@ -12163,7 +12163,7 @@ static void ma_engine_node_update_pitch_if_required(ma_engine_node* pEngineNode) ...@@ -12163,7 +12163,7 @@ static void ma_engine_node_update_pitch_if_required(ma_engine_node* pEngineNode)
if (isUpdateRequired) { if (isUpdateRequired) {
float basePitch = (float)pEngineNode->sampleRate / ma_engine_get_sample_rate(pEngineNode->pEngine); 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* ...@@ -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) 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)) { 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 { } 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) 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 ...@@ -12272,7 +12279,7 @@ static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNo
ma_uint64 resampleFrameCountIn = framesAvailableIn; ma_uint64 resampleFrameCountIn = framesAvailableIn;
ma_uint64 resampleFrameCountOut = framesAvailableOut; 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; isWorkingBufferValid = MA_TRUE;
framesJustProcessedIn = (ma_uint32)resampleFrameCountIn; framesJustProcessedIn = (ma_uint32)resampleFrameCountIn;
...@@ -12474,19 +12481,23 @@ static void ma_engine_node_process_pcm_frames__group(ma_node* pNode, const float ...@@ -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); 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. */ /* Our pitch will affect this calculation. We need to update it. */
ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode); 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); inputFrameCount = ma_engine_node_get_required_input_frame_count((ma_engine_node*)pNode, outputFrameCount);
if (result > 0xFFFFFFFF) { if (inputFrameCount > 0xFFFFFFFF) {
result = 0xFFFFFFFF; /* Will never happen because miniaudio will only ever process in relatively small chunks. */ 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 ...@@ -12623,7 +12634,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p
ma_result result; ma_result result;
ma_engine_node_heap_layout heapLayout; ma_engine_node_heap_layout heapLayout;
ma_node_config baseNodeConfig; ma_node_config baseNodeConfig;
ma_resampler_config resamplerConfig; ma_linear_resampler_config resamplerConfig;
ma_fader_config faderConfig; ma_fader_config faderConfig;
ma_spatializer_config spatializerConfig; ma_spatializer_config spatializerConfig;
ma_panner_config pannerConfig; ma_panner_config pannerConfig;
...@@ -12680,10 +12691,10 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p ...@@ -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. */ /* 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 = ma_linear_resampler_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], pEngineNode->sampleRate, ma_engine_get_sample_rate(pEngineNode->pEngine));
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.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) { if (result != MA_SUCCESS) {
goto error1; goto error1;
} }
...@@ -12725,7 +12736,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p ...@@ -12725,7 +12736,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p
return MA_SUCCESS; return MA_SUCCESS;
error3: ma_spatializer_uninit(&pEngineNode->spatializer, NULL); /* <-- No need for allocation callbacks here because we use a preallocated heap. */ 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. */ error1: ma_node_uninit(&pEngineNode->baseNode, NULL); /* <-- No need for allocation callbacks here because we use a preallocated heap. */
error0: return result; error0: return result;
} }
...@@ -12770,7 +12781,7 @@ MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocati ...@@ -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. */ /* Now that the node has been uninitialized we can safely uninitialize the rest. */
ma_spatializer_uninit(&pEngineNode->spatializer, NULL); ma_spatializer_uninit(&pEngineNode->spatializer, NULL);
ma_resampler_uninit(&pEngineNode->resampler, NULL); ma_linear_resampler_uninit(&pEngineNode->resampler, NULL);
/* Free the heap last. */ /* Free the heap last. */
if (pEngineNode->_pHeap != NULL && pEngineNode->_ownsHeap) { 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, ...@@ -14286,7 +14297,7 @@ MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat,
} }
if (pSampleRate != NULL) { if (pSampleRate != NULL) {
*pSampleRate = pSound->engineNode.resampler.sampleRateIn; *pSampleRate = pSound->engineNode.resampler.config.sampleRateIn;
} }
if (pChannelMap != NULL) { if (pChannelMap != NULL) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment