diff --git a/miniaudio.h b/miniaudio.h index 54fbbb9e..ba071913 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -3017,7 +3017,9 @@ The linear resampler performs low-pass filtering before or after downsampling or depending on the sample rates you're converting between. When decreasing the sample rate, the low-pass filter will be applied before downsampling. When increasing the rate it will be performed after upsampling. By default a fourth order low-pass filter will be applied. This can be configured -via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering. +via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering. It should be +set to a multiple of 2, such as 2, 4, 6, 8, etc. There are diminishing returns the higher you go. +The maximum is `MA_MAX_FILTER_ORDER` which is 8 by default (it can be configured at compile time). The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of the input and output sample rates (Nyquist Frequency). @@ -5580,7 +5582,7 @@ typedef struct ma_uint32 channels; ma_uint32 sampleRateIn; ma_uint32 sampleRateOut; - ma_uint32 lpfOrder; /* The low-pass filter order. Setting this to 0 will disable low-pass filtering. */ + ma_uint32 lpfOrder; /* The low-pass filter order. Setting this to 0 will disable low-pass filtering. Must be a multiple of 2. */ float lpfNyquistFactor; /* 0..1. Defaults to 1. 1 = Half the sampling frequency (Nyquist Frequency), 0.5 = Quarter the sampling frequency (half Nyquest Frequency), etc. */ } ma_linear_resampler_config; @@ -5667,7 +5669,7 @@ struct ma_resampler_config void* pBackendUserData; struct { - ma_uint32 lpfOrder; + ma_uint32 lpfOrder; /* Must be a multiple of 2. */ } linear; }; @@ -8718,7 +8720,7 @@ then be set directly on the structure. Below are the members of the `ma_device_c resampling.linear.lpfOrder The linear resampler applies a low-pass filter as part of its processing for anti-aliasing. This setting controls the order of the filter. The higher the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is - `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`. + `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`. It must be a multiple of 2. playback.pDeviceID A pointer to a `ma_device_id` structure containing the ID of the playback device to initialize. Setting this NULL (default) will use the system's @@ -58986,6 +58988,8 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes static ma_result ma_linear_resampler_get_heap_layout(const ma_linear_resampler_config* pConfig, ma_linear_resampler_heap_layout* pHeapLayout) { + ma_uint32 lpfOrder; + MA_ASSERT(pHeapLayout != NULL); MA_ZERO_OBJECT(pHeapLayout); @@ -59002,6 +59006,11 @@ static ma_result ma_linear_resampler_get_heap_layout(const ma_linear_resampler_c return MA_INVALID_ARGS; } + lpfOrder = pConfig->lpfOrder; + if ((lpfOrder & 0x1) != 0) { + lpfOrder += 1; /* Round up to even. */ + } + pHeapLayout->sizeInBytes = 0; /* x0 */ @@ -59025,7 +59034,7 @@ static ma_result ma_linear_resampler_get_heap_layout(const ma_linear_resampler_c { ma_result result; size_t lpfHeapSizeInBytes; - ma_lpf_config lpfConfig = ma_lpf_config_init(pConfig->format, pConfig->channels, 1, 1, pConfig->lpfOrder); /* Sample rate and cutoff frequency do not matter. */ + ma_lpf_config lpfConfig = ma_lpf_config_init(pConfig->format, pConfig->channels, 1, 1, lpfOrder); /* Sample rate and cutoff frequency do not matter. */ result = ma_lpf_get_heap_size(&lpfConfig, &lpfHeapSizeInBytes); if (result != MA_SUCCESS) { @@ -59085,6 +59094,11 @@ MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler pResampler->lpfOrder = pConfig->lpfOrder; pResampler->lpfNyquistFactor = pConfig->lpfNyquistFactor; + /* The order needs to be even. */ + if ((pResampler->lpfOrder & 0x1) != 0) { + pResampler->lpfOrder += 1; /* Round up to even. */ + } + pResampler->_pHeap = pHeap; MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);