Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
miniaudio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
miniaudio
Commits
961223b5
Commit
961223b5
authored
Aug 04, 2021
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for preallocation to ma_data_converter.
parent
59b6bcdf
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
197 additions
and
54 deletions
+197
-54
miniaudio.h
miniaudio.h
+197
-54
No files found.
miniaudio.h
View file @
961223b5
...
@@ -3512,7 +3512,6 @@ struct ma_resampler_config
...
@@ -3512,7 +3512,6 @@ struct ma_resampler_config
struct
struct
{
{
ma_uint32 lpfOrder;
ma_uint32 lpfOrder;
double lpfNyquistFactor;
} linear;
} linear;
};
};
...
@@ -3720,8 +3719,14 @@ typedef struct
...
@@ -3720,8 +3719,14 @@ typedef struct
ma_bool8 hasChannelConverter;
ma_bool8 hasChannelConverter;
ma_bool8 hasResampler;
ma_bool8 hasResampler;
ma_bool8 isPassthrough;
ma_bool8 isPassthrough;
/* Memory management. */
ma_bool8 _ownsHeap;
void* _pHeap;
} ma_data_converter;
} ma_data_converter;
MA_API ma_result ma_data_converter_get_heap_size(const ma_data_converter_config* pConfig, size_t* pHeapSizeInBytes);
MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_config* pConfig, void* pHeap, ma_data_converter* pConverter);
MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter);
MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter);
MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
MA_API ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
...
@@ -44172,8 +44177,7 @@ static ma_linear_resampler_config ma_resampling_backend_get_config__linear(const
...
@@ -44172,8 +44177,7 @@ static ma_linear_resampler_config ma_resampling_backend_get_config__linear(const
ma_linear_resampler_config linearConfig;
ma_linear_resampler_config linearConfig;
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;
return linearConfig;
return linearConfig;
}
}
...
@@ -44286,7 +44290,6 @@ MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32
...
@@ -44286,7 +44290,6 @@ MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32
/* Linear. */
/* Linear. */
config.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
config.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
config.linear.lpfNyquistFactor = 1;
return config;
return config;
}
}
...
@@ -45844,7 +45847,6 @@ MA_API ma_data_converter_config ma_data_converter_config_init_default()
...
@@ -45844,7 +45847,6 @@ MA_API ma_data_converter_config ma_data_converter_config_init_default()
/* Linear resampling defaults. */
/* Linear resampling defaults. */
config.resampling.linear.lpfOrder = 1;
config.resampling.linear.lpfOrder = 1;
config.resampling.linear.lpfNyquistFactor = 1;
return config;
return config;
}
}
...
@@ -45862,9 +45864,150 @@ MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn
...
@@ -45862,9 +45864,150 @@ MA_API ma_data_converter_config ma_data_converter_config_init(ma_format formatIn
return config;
return config;
}
}
MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter)
typedef struct
{
size_t sizeInBytes;
size_t channelConverterOffset;
size_t resamplerOffset;
} ma_data_converter_heap_layout;
static ma_bool32 ma_data_converter_config_is_resampler_required(const ma_data_converter_config* pConfig)
{
MA_ASSERT(pConfig != NULL);
return pConfig->allowDynamicSampleRate || pConfig->sampleRateIn != pConfig->sampleRateOut;
}
static ma_format ma_data_converter_config_get_mid_format(const ma_data_converter_config* pConfig)
{
MA_ASSERT(pConfig != NULL);
/*
We want to avoid as much data conversion as possible. The channel converter and linear
resampler both support s16 and f32 natively. We need to decide on the format to use for this
stage. We call this the mid format because it's used in the middle stage of the conversion
pipeline. If the output format is either s16 or f32 we use that one. If that is not the case it
will do the same thing for the input format. If it's neither we just use f32. If we are using a
custom resampling backend, we can only guarantee that f32 will be supported so we'll be forced
to use that if resampling is required.
*/
if (ma_data_converter_config_is_resampler_required(pConfig) && pConfig->resampling.algorithm != ma_resample_algorithm_linear) {
return ma_format_f32; /* <-- Force f32 since that is the only one we can guarantee will be supported by the resampler. */
} else {
/* */ if (pConfig->formatOut == ma_format_s16 || pConfig->formatOut == ma_format_f32) {
return pConfig->formatOut;
} else if (pConfig->formatIn == ma_format_s16 || pConfig->formatIn == ma_format_f32) {
return pConfig->formatIn;
} else {
return ma_format_f32;
}
}
}
static ma_channel_converter_config ma_channel_converter_config_init_from_data_converter_config(const ma_data_converter_config* pConfig)
{
MA_ASSERT(pConfig != NULL);
return ma_channel_converter_config_init(ma_data_converter_config_get_mid_format(pConfig), pConfig->channelsIn, pConfig->channelMapIn, pConfig->channelsOut, pConfig->channelMapOut, pConfig->channelMixMode);
}
static ma_resampler_config ma_resampler_config_init_from_data_converter_config(const ma_data_converter_config* pConfig)
{
ma_resampler_config resamplerConfig;
ma_uint32 resamplerChannels;
MA_ASSERT(pConfig != NULL);
/* The resampler is the most expensive part of the conversion process, so we need to do it at the stage where the channel count is at it's lowest. */
if (pConfig->channelsIn < pConfig->channelsOut) {
resamplerChannels = pConfig->channelsIn;
} else {
resamplerChannels = pConfig->channelsOut;
}
resamplerConfig = ma_resampler_config_init(ma_data_converter_config_get_mid_format(pConfig), resamplerChannels, pConfig->sampleRateIn, pConfig->sampleRateOut, pConfig->resampling.algorithm);
resamplerConfig.linear = pConfig->resampling.linear;
resamplerConfig.pBackendVTable = pConfig->resampling.pBackendVTable;
resamplerConfig.pBackendUserData = pConfig->resampling.pBackendUserData;
return resamplerConfig;
}
static ma_result ma_data_converter_get_heap_layout(const ma_data_converter_config* pConfig, ma_data_converter_heap_layout* pHeapLayout)
{
ma_result result;
MA_ASSERT(pHeapLayout != NULL);
MA_ZERO_OBJECT(pHeapLayout);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) {
return MA_INVALID_ARGS;
}
pHeapLayout->sizeInBytes = 0;
/* Channel converter. */
pHeapLayout->channelConverterOffset = pHeapLayout->sizeInBytes;
{
size_t heapSizeInBytes;
ma_channel_converter_config channelConverterConfig = ma_channel_converter_config_init_from_data_converter_config(pConfig);
result = ma_channel_converter_get_heap_size(&channelConverterConfig, &heapSizeInBytes);
if (result != MA_SUCCESS) {
return result;
}
pHeapLayout->sizeInBytes += heapSizeInBytes;
}
/* Resampler. */
pHeapLayout->resamplerOffset = pHeapLayout->sizeInBytes;
if (ma_data_converter_config_is_resampler_required(pConfig)) {
size_t heapSizeInBytes;
ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig);
result = ma_resampler_get_heap_size(&resamplerConfig, &heapSizeInBytes);
if (result != MA_SUCCESS) {
return result;
}
pHeapLayout->sizeInBytes += heapSizeInBytes;
}
return MA_SUCCESS;
}
MA_API ma_result ma_data_converter_get_heap_size(const ma_data_converter_config* pConfig, size_t* pHeapSizeInBytes)
{
{
ma_result result;
ma_result result;
ma_data_converter_heap_layout heapLayout;
if (pHeapSizeInBytes == NULL) {
return MA_INVALID_ARGS;
}
*pHeapSizeInBytes = 0;
result = ma_data_converter_get_heap_layout(pConfig, &heapLayout);
if (result != MA_SUCCESS) {
return result;
}
*pHeapSizeInBytes = heapLayout.sizeInBytes;
return MA_SUCCESS;
}
MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_config* pConfig, void* pHeap, ma_data_converter* pConverter)
{
ma_result result;
ma_data_converter_heap_layout heapLayout;
ma_format midFormat;
ma_format midFormat;
ma_bool32 isResamplingRequired;
ma_bool32 isResamplingRequired;
...
@@ -45874,45 +46017,23 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
...
@@ -45874,45 +46017,23 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
MA_ZERO_OBJECT(pConverter);
MA_ZERO_OBJECT(pConverter);
if (pConfig == NULL) {
result = ma_data_converter_get_heap_layout(pConfig, &heapLayout);
return MA_INVALID_ARGS;
if (result != MA_SUCCESS) {
return result;
}
}
pConverter->config = *pConfig;
pConverter->_pHeap = pHeap;
MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
/* Basic validation. */
pConverter->config = *pConfig;
if (pConfig->channelsIn < MA_MIN_CHANNELS || pConfig->channelsOut < MA_MIN_CHANNELS ||
pConfig->channelsIn > MA_MAX_CHANNELS || pConfig->channelsOut > MA_MAX_CHANNELS) {
return MA_INVALID_ARGS;
}
/*
/*
Determine if resampling is required. We need to do this so we can determine an appropriate
Determine if resampling is required. We need to do this so we can determine an appropriate
mid format to use. If resampling is required, the mid format must be ma_format_f32 since
mid format to use. If resampling is required, the mid format must be ma_format_f32 since
that is the only one that is guaranteed to supported by custom resampling backends.
that is the only one that is guaranteed to supported by custom resampling backends.
*/
*/
isResamplingRequired = pConfig->allowDynamicSampleRate || pConfig->sampleRateIn != pConfig->sampleRateOut;
isResamplingRequired = ma_data_converter_config_is_resampler_required(pConfig);
midFormat = ma_data_converter_config_get_mid_format(pConfig);
/*
We want to avoid as much data conversion as possible. The channel converter and linear
resampler both support s16 and f32 natively. We need to decide on the format to use for this
stage. We call this the mid format because it's used in the middle stage of the conversion
pipeline. If the output format is either s16 or f32 we use that one. If that is not the case it
will do the same thing for the input format. If it's neither we just use f32. If we are using a
custom resampling backend, we can only guarantee that f32 will be supported so we'll be forced
to use that if resampling is required.
*/
if (isResamplingRequired && pConfig->resampling.algorithm != ma_resample_algorithm_linear) {
midFormat = ma_format_f32; /* <-- Force f32 since that is the only one we can guarantee will be supported by the resampler. */
} else {
/* */ if (pConverter->config.formatOut == ma_format_s16 || pConverter->config.formatOut == ma_format_f32) {
midFormat = pConverter->config.formatOut;
} else if (pConverter->config.formatIn == ma_format_s16 || pConverter->config.formatIn == ma_format_f32) {
midFormat = pConverter->config.formatIn;
} else {
midFormat = ma_format_f32;
}
}
/* Channel converter. We always initialize this, but we check if it configures itself as a passthrough to determine whether or not it's needed. */
/* Channel converter. We always initialize this, but we check if it configures itself as a passthrough to determine whether or not it's needed. */
...
@@ -45921,7 +46042,7 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
...
@@ -45921,7 +46042,7 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
ma_uint32 iChannelOut;
ma_uint32 iChannelOut;
ma_channel_converter_config channelConverterConfig;
ma_channel_converter_config channelConverterConfig;
channelConverterConfig = ma_channel_converter_config_init
(midFormat, pConverter->config.channelsIn, pConverter->config.channelMapIn, pConverter->config.channelsOut, pConverter->config.channelMapOut, pConverter->config.channelMixMode
);
channelConverterConfig = ma_channel_converter_config_init
_from_data_converter_config(pConfig
);
/* Channel weights. */
/* Channel weights. */
for (iChannelIn = 0; iChannelIn < pConverter->config.channelsIn; iChannelIn += 1) {
for (iChannelIn = 0; iChannelIn < pConverter->config.channelsIn; iChannelIn += 1) {
...
@@ -45930,7 +46051,7 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
...
@@ -45930,7 +46051,7 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
}
}
}
}
result = ma_channel_converter_init
(&channelConverterConfig, pAllocationCallbacks
, &pConverter->channelConverter);
result = ma_channel_converter_init
_preallocated(&channelConverterConfig, ma_offset_ptr(pHeap, heapLayout.channelConverterOffset)
, &pConverter->channelConverter);
if (result != MA_SUCCESS) {
if (result != MA_SUCCESS) {
return result;
return result;
}
}
...
@@ -45949,23 +46070,9 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
...
@@ -45949,23 +46070,9 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
/* Resampler. */
/* Resampler. */
if (isResamplingRequired) {
if (isResamplingRequired) {
ma_resampler_config resamplerConfig;
ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig);
ma_uint32 resamplerChannels;
/* The resampler is the most expensive part of the conversion process, so we need to do it at the stage where the channel count is at it's lowest. */
result = ma_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pConverter->resampler);
if (pConverter->config.channelsIn < pConverter->config.channelsOut) {
resamplerChannels = pConverter->config.channelsIn;
} else {
resamplerChannels = pConverter->config.channelsOut;
}
resamplerConfig = ma_resampler_config_init(midFormat, resamplerChannels, pConverter->config.sampleRateIn, pConverter->config.sampleRateOut, pConverter->config.resampling.algorithm);
resamplerConfig.linear.lpfOrder = pConverter->config.resampling.linear.lpfOrder;
resamplerConfig.linear.lpfNyquistFactor = pConverter->config.resampling.linear.lpfNyquistFactor;
resamplerConfig.pBackendVTable = pConverter->config.resampling.pBackendVTable;
resamplerConfig.pBackendUserData = pConverter->config.resampling.pBackendUserData;
result = ma_resampler_init(&resamplerConfig, pAllocationCallbacks, &pConverter->resampler);
if (result != MA_SUCCESS) {
if (result != MA_SUCCESS) {
return result;
return result;
}
}
...
@@ -46040,6 +46147,36 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
...
@@ -46040,6 +46147,36 @@ MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig,
return MA_SUCCESS;
return MA_SUCCESS;
}
}
MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter)
{
ma_result result;
size_t heapSizeInBytes;
void* pHeap;
result = ma_data_converter_get_heap_size(pConfig, &heapSizeInBytes);
if (result != MA_SUCCESS) {
return result;
}
if (heapSizeInBytes > 0) {
pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
if (pHeap == NULL) {
return MA_OUT_OF_MEMORY;
}
} else {
pHeap = NULL;
}
result = ma_data_converter_init_preallocated(pConfig, pHeap, pConverter);
if (result != MA_SUCCESS) {
ma_free(pHeap, pAllocationCallbacks);
return result;
}
pConverter->_ownsHeap = MA_TRUE;
return MA_SUCCESS;
}
MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks)
MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks)
{
{
if (pConverter == NULL) {
if (pConverter == NULL) {
...
@@ -46049,6 +46186,12 @@ MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_all
...
@@ -46049,6 +46186,12 @@ MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_all
if (pConverter->hasResampler) {
if (pConverter->hasResampler) {
ma_resampler_uninit(&pConverter->resampler, pAllocationCallbacks);
ma_resampler_uninit(&pConverter->resampler, pAllocationCallbacks);
}
}
ma_channel_converter_uninit(&pConverter->channelConverter, pAllocationCallbacks);
if (pConverter->_ownsHeap) {
ma_free(pConverter->_pHeap, pAllocationCallbacks);
}
}
}
static ma_result ma_data_converter_process_pcm_frames__passthrough(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
static ma_result ma_data_converter_process_pcm_frames__passthrough(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment