From 7e944566c4aa816558bb8fc505c7cde656da5aab Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 18 Feb 2026 12:51:58 +1000 Subject: [PATCH] Resampler: Add back support for passing in NULL for the input/output. --- miniaudio.h | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 150 insertions(+), 3 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 17240bfa..dca7c48f 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -2995,8 +2995,7 @@ De-interleaved processing is not supported. To process frames, use `ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number of input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer -and the number of input frames that were consumed in the process. You cannot pass in NULL for the -input buffer or output buffer. +and the number of input frames that were consumed in the process. The sample rate can be changed dynamically on the fly. You can change this with explicit sample rates with `ma_resampler_set_rate()` and also with a decimal ratio with @@ -62653,13 +62652,152 @@ MA_API void ma_resampler_uninit(ma_resampler* pResampler, const ma_allocation_ca } } +static ma_result ma_resampler_process_pcm_frames_no_input_output(ma_resampler* pResampler, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut) +{ + ma_uint32 bpf = ma_get_bytes_per_frame(pResampler->format, pResampler->channels); + ma_uint8 framesIn[4096]; + ma_uint64 framesInCap = sizeof(framesIn) / bpf; + ma_uint8 framesOut[4096]; + ma_uint64 framesOutCap = sizeof(framesOut) / bpf; + ma_uint64 totalFramesProcessedIn; + ma_uint64 totalFramesProcessedOut; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + + totalFramesProcessedIn = 0; + totalFramesProcessedOut = 0; + + while (totalFramesProcessedIn < frameCountIn && totalFramesProcessedOut < frameCountOut) { + ma_result result; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + + framesProcessedIn = frameCountIn - totalFramesProcessedIn; + if (framesProcessedIn > framesInCap) { + framesProcessedIn = framesInCap; + } + + framesProcessedOut = frameCountOut - totalFramesProcessedOut; + if (framesProcessedOut > framesOutCap) { + framesProcessedOut = framesOutCap; + } + + result = pResampler->pBackendVTable->onProcess(pResampler->pBackendUserData, pResampler->pBackend, framesIn, &framesProcessedIn, framesOut, &framesProcessedOut); + if (result != MA_SUCCESS) { + break; + } + + totalFramesProcessedIn += framesProcessedIn; + totalFramesProcessedOut += framesProcessedOut; + } + + *pFrameCountIn = totalFramesProcessedIn; + *pFrameCountOut = totalFramesProcessedOut; + + return MA_SUCCESS; +} + +static ma_result ma_resampler_process_pcm_frames_no_input(ma_resampler* pResampler, ma_uint64* pFrameCountIn, const void* pFramesOut, ma_uint64* pFrameCountOut) +{ + ma_uint32 bpf = ma_get_bytes_per_frame(pResampler->format, pResampler->channels); + ma_uint8 framesIn[4096]; + ma_uint64 framesInCap = sizeof(framesIn) / bpf; + ma_uint64 totalFramesProcessedIn; + ma_uint64 totalFramesProcessedOut; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + + if (pFramesOut == NULL) { + return ma_resampler_process_pcm_frames_no_input_output(pResampler, pFrameCountIn, pFrameCountOut); + } + + frameCountIn = *pFrameCountIn; + frameCountOut = *pFrameCountOut; + + /* The input needs to be treated as silence. */ + MA_ZERO_MEMORY(framesIn, sizeof(framesIn)); + + totalFramesProcessedIn = 0; + totalFramesProcessedOut = 0; + + while (totalFramesProcessedIn < frameCountIn && totalFramesProcessedOut < frameCountOut) { + ma_result result; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + + framesProcessedIn = frameCountIn - totalFramesProcessedIn; + if (framesProcessedIn > framesInCap) { + framesProcessedIn = framesInCap; + } + + framesProcessedOut = frameCountOut - totalFramesProcessedOut; + + result = pResampler->pBackendVTable->onProcess(pResampler->pBackendUserData, pResampler->pBackend, framesIn, &framesProcessedIn, ma_offset_ptr(pFramesOut, totalFramesProcessedOut * bpf), &framesProcessedOut); + if (result != MA_SUCCESS) { + break; + } + + totalFramesProcessedIn += framesProcessedIn; + totalFramesProcessedOut += framesProcessedOut; + } + + *pFrameCountIn = totalFramesProcessedIn; + *pFrameCountOut = totalFramesProcessedOut; + + return MA_SUCCESS; +} + +static ma_result ma_resampler_process_pcm_frames_no_output(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut) +{ + ma_uint32 bpf = ma_get_bytes_per_frame(pResampler->format, pResampler->channels); + ma_uint8 framesOut[4096]; + ma_uint64 framesOutCap = sizeof(framesOut) / bpf; + ma_uint64 totalFramesProcessedIn; + ma_uint64 totalFramesProcessedOut; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + + if (pFramesIn == NULL) { + return ma_resampler_process_pcm_frames_no_input_output(pResampler, pFrameCountIn, pFrameCountOut); + } + + totalFramesProcessedIn = 0; + totalFramesProcessedOut = 0; + + while (totalFramesProcessedIn < frameCountIn && totalFramesProcessedOut < frameCountOut) { + ma_result result; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + + framesProcessedIn = frameCountIn - totalFramesProcessedIn; + + framesProcessedOut = frameCountOut - totalFramesProcessedOut; + if (framesProcessedOut > framesOutCap) { + framesProcessedOut = framesOutCap; + } + + result = pResampler->pBackendVTable->onProcess(pResampler->pBackendUserData, pResampler->pBackend, ma_offset_ptr(pFramesIn, totalFramesProcessedIn * bpf), &framesProcessedIn, framesOut, &framesProcessedOut); + if (result != MA_SUCCESS) { + break; + } + + totalFramesProcessedIn += framesProcessedIn; + totalFramesProcessedOut += framesProcessedOut; + } + + *pFrameCountIn = totalFramesProcessedIn; + *pFrameCountOut = totalFramesProcessedOut; + + return MA_SUCCESS; +} + MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) { if (pResampler == NULL) { return MA_INVALID_ARGS; } - if (pFrameCountOut == NULL || pFramesOut == NULL || pFrameCountIn == NULL || pFramesIn == NULL) { + if (pFrameCountOut == NULL || pFrameCountIn == NULL) { return MA_INVALID_ARGS; } @@ -62667,6 +62805,14 @@ MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const return MA_NOT_IMPLEMENTED; } + if (pFramesIn == NULL) { + return ma_resampler_process_pcm_frames_no_input(pResampler, pFrameCountIn, pFramesOut, pFrameCountOut); + } + + if (pFramesOut == NULL) { + return ma_resampler_process_pcm_frames_no_output(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut); + } + return pResampler->pBackendVTable->onProcess(pResampler->pBackendUserData, pResampler->pBackend, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); } @@ -66521,6 +66667,7 @@ MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const } frameCountIn -= framesProcessedIn; + frameCountOut += framesProcessedOut; } } } else {