Commit b458faee authored by David Reid's avatar David Reid

API CHANGE: Remove ma_format_converter.

Use the following APIs as alternatives:

  * ma_pcm_*_to_*()
  * ma_pcm_convert()
  * ma_convert_pcm_frames()
parent dbaa2479
......@@ -1411,41 +1411,6 @@ ma_uint64 ma_data_converter_get_output_latency(ma_data_converter* pConverter);
typedef struct ma_format_converter ma_format_converter;
typedef ma_uint32 (* ma_format_converter_read_proc) (ma_format_converter* pConverter, ma_uint32 frameCount, void* pFramesOut, void* pUserData);
typedef ma_uint32 (* ma_format_converter_read_deinterleaved_proc)(ma_format_converter* pConverter, ma_uint32 frameCount, void** ppSamplesOut, void* pUserData);
typedef struct
{
ma_format formatIn;
ma_format formatOut;
ma_uint32 channels;
ma_stream_format streamFormatIn;
ma_stream_format streamFormatOut;
ma_dither_mode ditherMode;
ma_bool32 noSSE2 : 1;
ma_bool32 noAVX2 : 1;
ma_bool32 noAVX512 : 1;
ma_bool32 noNEON : 1;
ma_format_converter_read_proc onRead;
ma_format_converter_read_deinterleaved_proc onReadDeinterleaved;
void* pUserData;
} ma_format_converter_config;
struct ma_format_converter
{
ma_format_converter_config config;
ma_bool32 useSSE2 : 1;
ma_bool32 useAVX2 : 1;
ma_bool32 useAVX512 : 1;
ma_bool32 useNEON : 1;
void (* onConvertPCM)(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode);
void (* onInterleavePCM)(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels);
void (* onDeinterleavePCM)(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels);
};
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
......@@ -1560,68 +1525,6 @@ Helper for determining whether or not a channel is present in the given channel
ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS], ma_channel channelPosition);
/************************************************************************************************************************************************************
Format Conversion
=================
The format converter serves two purposes:
1) Conversion between data formats (u8 to f32, etc.)
2) Interleaving and deinterleaving
When initializing a converter, you specify the input and output formats (u8, s16, etc.) and read callbacks. There are two read callbacks - one for
interleaved input data (onRead) and another for deinterleaved input data (onReadDeinterleaved). You implement whichever is most convenient for you. You
can implement both, but it's not recommended as it just introduces unnecessary complexity.
To read data as interleaved samples, use ma_format_converter_read(). Otherwise use ma_format_converter_read_deinterleaved().
Dithering
---------
The format converter also supports dithering. Dithering can be set using ditherMode variable in the config, like so.
pConfig->ditherMode = ma_dither_mode_rectangle;
The different dithering modes include the following, in order of efficiency:
- None: ma_dither_mode_none
- Rectangle: ma_dither_mode_rectangle
- Triangle: ma_dither_mode_triangle
Note that even if the dither mode is set to something other than ma_dither_mode_none, it will be ignored for conversions where dithering is not needed.
Dithering is available for the following conversions:
- s16 -> u8
- s24 -> u8
- s32 -> u8
- f32 -> u8
- s24 -> s16
- s32 -> s16
- f32 -> s16
Note that it is not an error to pass something other than ma_dither_mode_none for conversions where dither is not used. It will just be ignored.
************************************************************************************************************************************************************/
/*
Initializes a format converter.
*/
ma_result ma_format_converter_init(const ma_format_converter_config* pConfig, ma_format_converter* pConverter);
/*
Reads data from the format converter as interleaved channels.
*/
ma_uint64 ma_format_converter_read(ma_format_converter* pConverter, ma_uint64 frameCount, void* pFramesOut, void* pUserData);
/*
Reads data from the format converter as deinterleaved channels.
*/
ma_uint64 ma_format_converter_read_deinterleaved(ma_format_converter* pConverter, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData);
/*
Helper for initializing a format converter config.
*/
ma_format_converter_config ma_format_converter_config_init_new(void);
ma_format_converter_config ma_format_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channels, ma_format_converter_read_proc onRead, void* pUserData);
ma_format_converter_config ma_format_converter_config_init_deinterleaved(ma_format formatIn, ma_format formatOut, ma_uint32 channels, ma_format_converter_read_deinterleaved_proc onReadDeinterleaved, void* pUserData);
/************************************************************************************************************************************************************
Conversion
......@@ -1813,6 +1716,28 @@ const char* ma_log_level_to_string(ma_uint32 logLevel);
/************************************************************************************************************************************************************
Format Conversion
=================
Dithering
---------
Dithering can be set using ditherMode parmater.
The different dithering modes include the following, in order of efficiency:
- None: ma_dither_mode_none
- Rectangle: ma_dither_mode_rectangle
- Triangle: ma_dither_mode_triangle
Note that even if the dither mode is set to something other than ma_dither_mode_none, it will be ignored for conversions where dithering is not needed.
Dithering is available for the following conversions:
- s16 -> u8
- s24 -> u8
- s32 -> u8
- f32 -> u8
- s24 -> s16
- s32 -> s16
- f32 -> s16
Note that it is not an error to pass something other than ma_dither_mode_none for conversions where dither is not used. It will just be ignored.
************************************************************************************************************************************************************/
void ma_pcm_u8_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
......@@ -33223,817 +33148,6 @@ void ma_pcm_deinterleave_f32(void** dst, const void* src, ma_uint64 frameCount,
}
void ma_format_converter_init_callbacks__default(ma_format_converter* pConverter)
{
ma_assert(pConverter != NULL);
switch (pConverter->config.formatIn)
{
case ma_format_u8:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_u8_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_u8_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_u8_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_u8_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_u8_to_f32;
}
} break;
case ma_format_s16:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s16_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s16_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s16_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s16_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s16_to_f32;
}
} break;
case ma_format_s24:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s24_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s24_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s24_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s24_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s24_to_f32;
}
} break;
case ma_format_s32:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s32_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s32_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s32_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s32_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s32_to_f32;
}
} break;
case ma_format_f32:
default:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_f32_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_f32_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_f32_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_f32_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_f32_to_f32;
}
} break;
}
}
#if defined(MA_SUPPORT_SSE2)
void ma_format_converter_init_callbacks__sse2(ma_format_converter* pConverter)
{
ma_assert(pConverter != NULL);
switch (pConverter->config.formatIn)
{
case ma_format_u8:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_u8_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_u8_to_s16__sse2;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_u8_to_s24__sse2;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_u8_to_s32__sse2;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_u8_to_f32__sse2;
}
} break;
case ma_format_s16:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s16_to_u8__sse2;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s16_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s16_to_s24__sse2;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s16_to_s32__sse2;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s16_to_f32__sse2;
}
} break;
case ma_format_s24:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s24_to_u8__sse2;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s24_to_s16__sse2;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s24_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s24_to_s32__sse2;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s24_to_f32__sse2;
}
} break;
case ma_format_s32:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s32_to_u8__sse2;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s32_to_s16__sse2;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s32_to_s24__sse2;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s32_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s32_to_f32__sse2;
}
} break;
case ma_format_f32:
default:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_f32_to_u8__sse2;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_f32_to_s16__sse2;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_f32_to_s24__sse2;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_f32_to_s32__sse2;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_f32_to_f32;
}
} break;
}
}
#endif
#if defined(MA_SUPPORT_AVX2)
void ma_format_converter_init_callbacks__avx2(ma_format_converter* pConverter)
{
ma_assert(pConverter != NULL);
switch (pConverter->config.formatIn)
{
case ma_format_u8:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_u8_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_u8_to_s16__avx2;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_u8_to_s24__avx2;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_u8_to_s32__avx2;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_u8_to_f32__avx2;
}
} break;
case ma_format_s16:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s16_to_u8__avx2;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s16_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s16_to_s24__avx2;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s16_to_s32__avx2;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s16_to_f32__avx2;
}
} break;
case ma_format_s24:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s24_to_u8__avx2;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s24_to_s16__avx2;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s24_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s24_to_s32__avx2;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s24_to_f32__avx2;
}
} break;
case ma_format_s32:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s32_to_u8__avx2;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s32_to_s16__avx2;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s32_to_s24__avx2;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s32_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s32_to_f32__avx2;
}
} break;
case ma_format_f32:
default:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_f32_to_u8__avx2;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_f32_to_s16__avx2;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_f32_to_s24__avx2;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_f32_to_s32__avx2;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_f32_to_f32;
}
} break;
}
}
#endif
#if defined(MA_SUPPORT_AVX512)
void ma_format_converter_init_callbacks__avx512(ma_format_converter* pConverter)
{
ma_assert(pConverter != NULL);
switch (pConverter->config.formatIn)
{
case ma_format_u8:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_u8_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_u8_to_s16__avx512;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_u8_to_s24__avx512;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_u8_to_s32__avx512;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_u8_to_f32__avx512;
}
} break;
case ma_format_s16:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s16_to_u8__avx512;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s16_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s16_to_s24__avx512;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s16_to_s32__avx512;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s16_to_f32__avx512;
}
} break;
case ma_format_s24:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s24_to_u8__avx512;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s24_to_s16__avx512;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s24_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s24_to_s32__avx512;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s24_to_f32__avx512;
}
} break;
case ma_format_s32:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s32_to_u8__avx512;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s32_to_s16__avx512;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s32_to_s24__avx512;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s32_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s32_to_f32__avx512;
}
} break;
case ma_format_f32:
default:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_f32_to_u8__avx512;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_f32_to_s16__avx512;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_f32_to_s24__avx512;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_f32_to_s32__avx512;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_f32_to_f32;
}
} break;
}
}
#endif
#if defined(MA_SUPPORT_NEON)
void ma_format_converter_init_callbacks__neon(ma_format_converter* pConverter)
{
ma_assert(pConverter != NULL);
switch (pConverter->config.formatIn)
{
case ma_format_u8:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_u8_to_u8;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_u8_to_s16__neon;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_u8_to_s24__neon;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_u8_to_s32__neon;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_u8_to_f32__neon;
}
} break;
case ma_format_s16:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s16_to_u8__neon;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s16_to_s16;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s16_to_s24__neon;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s16_to_s32__neon;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s16_to_f32__neon;
}
} break;
case ma_format_s24:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s24_to_u8__neon;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s24_to_s16__neon;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s24_to_s24;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s24_to_s32__neon;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s24_to_f32__neon;
}
} break;
case ma_format_s32:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_s32_to_u8__neon;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_s32_to_s16__neon;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_s32_to_s24__neon;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_s32_to_s32;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_s32_to_f32__neon;
}
} break;
case ma_format_f32:
default:
{
if (pConverter->config.formatOut == ma_format_u8) {
pConverter->onConvertPCM = ma_pcm_f32_to_u8__neon;
} else if (pConverter->config.formatOut == ma_format_s16) {
pConverter->onConvertPCM = ma_pcm_f32_to_s16__neon;
} else if (pConverter->config.formatOut == ma_format_s24) {
pConverter->onConvertPCM = ma_pcm_f32_to_s24__neon;
} else if (pConverter->config.formatOut == ma_format_s32) {
pConverter->onConvertPCM = ma_pcm_f32_to_s32__neon;
} else if (pConverter->config.formatOut == ma_format_f32) {
pConverter->onConvertPCM = ma_pcm_f32_to_f32;
}
} break;
}
}
#endif
ma_result ma_format_converter_init(const ma_format_converter_config* pConfig, ma_format_converter* pConverter)
{
if (pConverter == NULL) {
return MA_INVALID_ARGS;
}
ma_zero_object(pConverter);
if (pConfig == NULL) {
return MA_INVALID_ARGS;
}
pConverter->config = *pConfig;
/* SIMD */
pConverter->useSSE2 = ma_has_sse2() && !pConfig->noSSE2;
pConverter->useAVX2 = ma_has_avx2() && !pConfig->noAVX2;
pConverter->useAVX512 = ma_has_avx512f() && !pConfig->noAVX512;
pConverter->useNEON = ma_has_neon() && !pConfig->noNEON;
#if defined(MA_SUPPORT_AVX512)
if (pConverter->useAVX512) {
ma_format_converter_init_callbacks__avx512(pConverter);
} else
#endif
#if defined(MA_SUPPORT_AVX2)
if (pConverter->useAVX2) {
ma_format_converter_init_callbacks__avx2(pConverter);
} else
#endif
#if defined(MA_SUPPORT_SSE2)
if (pConverter->useSSE2) {
ma_format_converter_init_callbacks__sse2(pConverter);
} else
#endif
#if defined(MA_SUPPORT_NEON)
if (pConverter->useNEON) {
ma_format_converter_init_callbacks__neon(pConverter);
} else
#endif
{
ma_format_converter_init_callbacks__default(pConverter);
}
switch (pConfig->formatOut)
{
case ma_format_u8:
{
pConverter->onInterleavePCM = ma_pcm_interleave_u8;
pConverter->onDeinterleavePCM = ma_pcm_deinterleave_u8;
} break;
case ma_format_s16:
{
pConverter->onInterleavePCM = ma_pcm_interleave_s16;
pConverter->onDeinterleavePCM = ma_pcm_deinterleave_s16;
} break;
case ma_format_s24:
{
pConverter->onInterleavePCM = ma_pcm_interleave_s24;
pConverter->onDeinterleavePCM = ma_pcm_deinterleave_s24;
} break;
case ma_format_s32:
{
pConverter->onInterleavePCM = ma_pcm_interleave_s32;
pConverter->onDeinterleavePCM = ma_pcm_deinterleave_s32;
} break;
case ma_format_f32:
default:
{
pConverter->onInterleavePCM = ma_pcm_interleave_f32;
pConverter->onDeinterleavePCM = ma_pcm_deinterleave_f32;
} break;
}
return MA_SUCCESS;
}
ma_uint64 ma_format_converter_read(ma_format_converter* pConverter, ma_uint64 frameCount, void* pFramesOut, void* pUserData)
{
ma_uint64 totalFramesRead;
ma_uint32 sampleSizeIn;
ma_uint32 sampleSizeOut;
ma_uint32 frameSizeOut;
ma_uint8* pNextFramesOut;
if (pConverter == NULL || pFramesOut == NULL) {
return 0;
}
totalFramesRead = 0;
sampleSizeIn = ma_get_bytes_per_sample(pConverter->config.formatIn);
sampleSizeOut = ma_get_bytes_per_sample(pConverter->config.formatOut);
/*frameSizeIn = sampleSizeIn * pConverter->config.channels;*/
frameSizeOut = sampleSizeOut * pConverter->config.channels;
pNextFramesOut = (ma_uint8*)pFramesOut;
if (pConverter->config.onRead != NULL) {
/* Input data is interleaved. */
if (pConverter->config.formatIn == pConverter->config.formatOut) {
/* Pass through. */
while (totalFramesRead < frameCount) {
ma_uint32 framesJustRead;
ma_uint64 framesRemaining = (frameCount - totalFramesRead);
ma_uint64 framesToReadRightNow = framesRemaining;
if (framesToReadRightNow > 0xFFFFFFFF) {
framesToReadRightNow = 0xFFFFFFFF;
}
framesJustRead = (ma_uint32)pConverter->config.onRead(pConverter, (ma_uint32)framesToReadRightNow, pNextFramesOut, pUserData);
if (framesJustRead == 0) {
break;
}
totalFramesRead += framesJustRead;
pNextFramesOut += framesJustRead * frameSizeOut;
if (framesJustRead < framesToReadRightNow) {
break;
}
}
} else {
/* Conversion required. */
ma_uint32 maxFramesToReadAtATime;
MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 temp[MA_MAX_CHANNELS * MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128];
ma_assert(sizeof(temp) <= 0xFFFFFFFF);
maxFramesToReadAtATime = sizeof(temp) / sampleSizeIn / pConverter->config.channels;
while (totalFramesRead < frameCount) {
ma_uint32 framesJustRead;
ma_uint64 framesRemaining = (frameCount - totalFramesRead);
ma_uint64 framesToReadRightNow = framesRemaining;
if (framesToReadRightNow > maxFramesToReadAtATime) {
framesToReadRightNow = maxFramesToReadAtATime;
}
framesJustRead = (ma_uint32)pConverter->config.onRead(pConverter, (ma_uint32)framesToReadRightNow, temp, pUserData);
if (framesJustRead == 0) {
break;
}
pConverter->onConvertPCM(pNextFramesOut, temp, framesJustRead*pConverter->config.channels, pConverter->config.ditherMode);
totalFramesRead += framesJustRead;
pNextFramesOut += framesJustRead * frameSizeOut;
if (framesJustRead < framesToReadRightNow) {
break;
}
}
}
} else {
/* Input data is deinterleaved. If a conversion is required we need to do an intermediary step. */
void* ppTempSamplesOfOutFormat[MA_MAX_CHANNELS];
size_t splitBufferSizeOut;
ma_uint32 maxFramesToReadAtATime;
MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 tempSamplesOfOutFormat[MA_MAX_CHANNELS * MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128];
ma_assert(sizeof(tempSamplesOfOutFormat) <= 0xFFFFFFFF);
ma_split_buffer(tempSamplesOfOutFormat, sizeof(tempSamplesOfOutFormat), pConverter->config.channels, MA_SIMD_ALIGNMENT, (void**)&ppTempSamplesOfOutFormat, &splitBufferSizeOut);
maxFramesToReadAtATime = (ma_uint32)(splitBufferSizeOut / sampleSizeIn);
while (totalFramesRead < frameCount) {
ma_uint32 framesJustRead;
ma_uint64 framesRemaining = (frameCount - totalFramesRead);
ma_uint64 framesToReadRightNow = framesRemaining;
if (framesToReadRightNow > maxFramesToReadAtATime) {
framesToReadRightNow = maxFramesToReadAtATime;
}
if (pConverter->config.formatIn == pConverter->config.formatOut) {
/* Only interleaving. */
framesJustRead = (ma_uint32)pConverter->config.onReadDeinterleaved(pConverter, (ma_uint32)framesToReadRightNow, ppTempSamplesOfOutFormat, pUserData);
if (framesJustRead == 0) {
break;
}
} else {
/* Interleaving + Conversion. Convert first, then interleave. */
void* ppTempSamplesOfInFormat[MA_MAX_CHANNELS];
size_t splitBufferSizeIn;
ma_uint32 iChannel;
MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 tempSamplesOfInFormat[MA_MAX_CHANNELS * MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128];
ma_split_buffer(tempSamplesOfInFormat, sizeof(tempSamplesOfInFormat), pConverter->config.channels, MA_SIMD_ALIGNMENT, (void**)&ppTempSamplesOfInFormat, &splitBufferSizeIn);
if (framesToReadRightNow > (splitBufferSizeIn / sampleSizeIn)) {
framesToReadRightNow = (splitBufferSizeIn / sampleSizeIn);
}
framesJustRead = (ma_uint32)pConverter->config.onReadDeinterleaved(pConverter, (ma_uint32)framesToReadRightNow, ppTempSamplesOfInFormat, pUserData);
if (framesJustRead == 0) {
break;
}
for (iChannel = 0; iChannel < pConverter->config.channels; iChannel += 1) {
pConverter->onConvertPCM(ppTempSamplesOfOutFormat[iChannel], ppTempSamplesOfInFormat[iChannel], framesJustRead, pConverter->config.ditherMode);
}
}
pConverter->onInterleavePCM(pNextFramesOut, (const void**)ppTempSamplesOfOutFormat, framesJustRead, pConverter->config.channels);
totalFramesRead += framesJustRead;
pNextFramesOut += framesJustRead * frameSizeOut;
if (framesJustRead < framesToReadRightNow) {
break;
}
}
}
return totalFramesRead;
}
ma_uint64 ma_format_converter_read_deinterleaved(ma_format_converter* pConverter, ma_uint64 frameCount, void** ppSamplesOut, void* pUserData)
{
ma_uint64 totalFramesRead;
ma_uint32 sampleSizeIn;
ma_uint32 sampleSizeOut;
ma_uint8* ppNextSamplesOut[MA_MAX_CHANNELS];
if (pConverter == NULL || ppSamplesOut == NULL) {
return 0;
}
totalFramesRead = 0;
sampleSizeIn = ma_get_bytes_per_sample(pConverter->config.formatIn);
sampleSizeOut = ma_get_bytes_per_sample(pConverter->config.formatOut);
ma_copy_memory(ppNextSamplesOut, ppSamplesOut, sizeof(void*) * pConverter->config.channels);
if (pConverter->config.onRead != NULL) {
/* Input data is interleaved. */
ma_uint32 maxFramesToReadAtATime;
MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 tempSamplesOfOutFormat[MA_MAX_CHANNELS * MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128];
ma_assert(sizeof(tempSamplesOfOutFormat) <= 0xFFFFFFFF);
maxFramesToReadAtATime = sizeof(tempSamplesOfOutFormat) / sampleSizeIn / pConverter->config.channels;
while (totalFramesRead < frameCount) {
ma_uint32 iChannel;
ma_uint32 framesJustRead;
ma_uint64 framesRemaining = (frameCount - totalFramesRead);
ma_uint64 framesToReadRightNow = framesRemaining;
if (framesToReadRightNow > maxFramesToReadAtATime) {
framesToReadRightNow = maxFramesToReadAtATime;
}
if (pConverter->config.formatIn == pConverter->config.formatOut) {
/* Only de-interleaving. */
framesJustRead = (ma_uint32)pConverter->config.onRead(pConverter, (ma_uint32)framesToReadRightNow, tempSamplesOfOutFormat, pUserData);
if (framesJustRead == 0) {
break;
}
} else {
/* De-interleaving + Conversion. Convert first, then de-interleave. */
MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 tempSamplesOfInFormat[sizeof(tempSamplesOfOutFormat)];
framesJustRead = (ma_uint32)pConverter->config.onRead(pConverter, (ma_uint32)framesToReadRightNow, tempSamplesOfInFormat, pUserData);
if (framesJustRead == 0) {
break;
}
pConverter->onConvertPCM(tempSamplesOfOutFormat, tempSamplesOfInFormat, framesJustRead * pConverter->config.channels, pConverter->config.ditherMode);
}
pConverter->onDeinterleavePCM((void**)ppNextSamplesOut, tempSamplesOfOutFormat, framesJustRead, pConverter->config.channels);
totalFramesRead += framesJustRead;
for (iChannel = 0; iChannel < pConverter->config.channels; ++iChannel) {
ppNextSamplesOut[iChannel] += framesJustRead * sampleSizeOut;
}
if (framesJustRead < framesToReadRightNow) {
break;
}
}
} else {
/* Input data is deinterleaved. */
if (pConverter->config.formatIn == pConverter->config.formatOut) {
/* Pass through. */
while (totalFramesRead < frameCount) {
ma_uint32 iChannel;
ma_uint32 framesJustRead;
ma_uint64 framesRemaining = (frameCount - totalFramesRead);
ma_uint64 framesToReadRightNow = framesRemaining;
if (framesToReadRightNow > 0xFFFFFFFF) {
framesToReadRightNow = 0xFFFFFFFF;
}
framesJustRead = (ma_uint32)pConverter->config.onReadDeinterleaved(pConverter, (ma_uint32)framesToReadRightNow, (void**)ppNextSamplesOut, pUserData);
if (framesJustRead == 0) {
break;
}
totalFramesRead += framesJustRead;
for (iChannel = 0; iChannel < pConverter->config.channels; ++iChannel) {
ppNextSamplesOut[iChannel] += framesJustRead * sampleSizeOut;
}
if (framesJustRead < framesToReadRightNow) {
break;
}
}
} else {
/* Conversion required. */
void* ppTemp[MA_MAX_CHANNELS];
size_t splitBufferSize;
ma_uint32 maxFramesToReadAtATime;
MA_ALIGN(MA_SIMD_ALIGNMENT) ma_uint8 temp[MA_MAX_CHANNELS][MA_MAX_PCM_SAMPLE_SIZE_IN_BYTES * 128];
ma_assert(sizeof(temp) <= 0xFFFFFFFF);
ma_split_buffer(temp, sizeof(temp), pConverter->config.channels, MA_SIMD_ALIGNMENT, (void**)&ppTemp, &splitBufferSize);
maxFramesToReadAtATime = (ma_uint32)(splitBufferSize / sampleSizeIn);
while (totalFramesRead < frameCount) {
ma_uint32 iChannel;
ma_uint32 framesJustRead;
ma_uint64 framesRemaining = (frameCount - totalFramesRead);
ma_uint64 framesToReadRightNow = framesRemaining;
if (framesToReadRightNow > maxFramesToReadAtATime) {
framesToReadRightNow = maxFramesToReadAtATime;
}
framesJustRead = (ma_uint32)pConverter->config.onReadDeinterleaved(pConverter, (ma_uint32)framesToReadRightNow, ppTemp, pUserData);
if (framesJustRead == 0) {
break;
}
for (iChannel = 0; iChannel < pConverter->config.channels; iChannel += 1) {
pConverter->onConvertPCM(ppNextSamplesOut[iChannel], ppTemp[iChannel], framesJustRead, pConverter->config.ditherMode);
ppNextSamplesOut[iChannel] += framesJustRead * sampleSizeOut;
}
totalFramesRead += framesJustRead;
if (framesJustRead < framesToReadRightNow) {
break;
}
}
}
}
return totalFramesRead;
}
ma_format_converter_config ma_format_converter_config_init_new()
{
ma_format_converter_config config;
ma_zero_object(&config);
return config;
}
ma_format_converter_config ma_format_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channels, ma_format_converter_read_proc onRead, void* pUserData)
{
ma_format_converter_config config = ma_format_converter_config_init_new();
config.formatIn = formatIn;
config.formatOut = formatOut;
config.channels = channels;
config.onRead = onRead;
config.onReadDeinterleaved = NULL;
config.pUserData = pUserData;
return config;
}
ma_format_converter_config ma_format_converter_config_init_deinterleaved(ma_format formatIn, ma_format formatOut, ma_uint32 channels, ma_format_converter_read_deinterleaved_proc onReadDeinterleaved, void* pUserData)
{
ma_format_converter_config config = ma_format_converter_config_init(formatIn, formatOut, channels, NULL, pUserData);
config.onReadDeinterleaved = onReadDeinterleaved;
return config;
}
/**************************************************************************************************************************************************************
Format Conversion
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