mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-21 15:56:58 +02:00
Add initial support for dithering.
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
#define MAL_USE_REFERENCE_CONVERSION_APIS
|
||||
#define MAL_IMPLEMENTATION
|
||||
#include "../mini_al.h"
|
||||
|
||||
// Two converters are needed here. One for converting f32 samples from the sine wave generator to the input format,
|
||||
// and another for converting the input format to the output format for device output.
|
||||
mal_sine_wave sineWave;
|
||||
mal_format_converter converterIn;
|
||||
mal_format_converter converterOut;
|
||||
|
||||
mal_uint32 on_convert_samples_in(mal_format_converter* pConverter, mal_uint32 frameCount, void* pFrames, void* pUserData)
|
||||
{
|
||||
(void)pUserData;
|
||||
mal_assert(pConverter->config.formatIn == mal_format_f32);
|
||||
|
||||
mal_sine_wave* pSineWave = (mal_sine_wave*)pConverter->config.pUserData;
|
||||
mal_assert(pSineWave);
|
||||
|
||||
return (mal_uint32)mal_sine_wave_read(pSineWave, frameCount, pFrames);
|
||||
}
|
||||
|
||||
mal_uint32 on_convert_samples_out(mal_format_converter* pConverter, mal_uint32 frameCount, void* pFrames, void* pUserData)
|
||||
{
|
||||
(void)pUserData;
|
||||
|
||||
mal_format_converter* pConverterIn = (mal_format_converter*)pConverter->config.pUserData;
|
||||
mal_assert(pConverterIn != NULL);
|
||||
|
||||
return (mal_uint32)mal_format_converter_read(pConverterIn, frameCount, pFrames, NULL);
|
||||
}
|
||||
|
||||
mal_uint32 on_send_to_device__original(mal_device* pDevice, mal_uint32 frameCount, void* pFrames)
|
||||
{
|
||||
(void)pDevice;
|
||||
mal_assert(pDevice->format == mal_format_f32);
|
||||
mal_assert(pDevice->channels == 1);
|
||||
|
||||
return (mal_uint32)mal_sine_wave_read(&sineWave, frameCount, pFrames);
|
||||
}
|
||||
|
||||
mal_uint32 on_send_to_device__dithered(mal_device* pDevice, mal_uint32 frameCount, void* pFrames)
|
||||
{
|
||||
mal_assert(pDevice->channels == 1);
|
||||
|
||||
mal_format_converter* pConverter = (mal_format_converter*)pDevice->pUserData;
|
||||
mal_assert(pConverter != NULL);
|
||||
mal_assert(pDevice->format == pConverter->config.formatOut);
|
||||
|
||||
return (mal_uint32)mal_format_converter_read(pConverter, frameCount, pFrames, NULL);
|
||||
}
|
||||
|
||||
int do_dithering_test()
|
||||
{
|
||||
mal_sine_wave_init(0.5, 400, 48000, &sineWave);
|
||||
|
||||
|
||||
mal_device_config config = mal_device_config_init_playback(mal_format_f32, 1, 0, on_send_to_device__original);
|
||||
mal_device device;
|
||||
mal_result result;
|
||||
|
||||
// We first play the sound the way it's meant to be played.
|
||||
result = mal_device_init(NULL, mal_device_type_playback, NULL, &config, NULL, &device);
|
||||
if (result != MAL_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = mal_device_start(&device);
|
||||
if (result != MAL_SUCCESS) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
printf("Press Enter to play enable dithering.\n");
|
||||
getchar();
|
||||
mal_device_uninit(&device);
|
||||
|
||||
|
||||
// Now we play the sound after it's run through a dithered format converter.
|
||||
mal_sine_wave_init(0.5, 400, 48000, &sineWave);
|
||||
|
||||
mal_format srcFormat = mal_format_s24;
|
||||
mal_format dstFormat = mal_format_s16;
|
||||
mal_dither_mode ditherMode = mal_dither_mode_triangle;
|
||||
|
||||
mal_format_converter_config converterInConfig;
|
||||
mal_zero_object(&converterInConfig);
|
||||
converterInConfig.formatIn = mal_format_f32; // <-- From the sine wave generator.
|
||||
converterInConfig.formatOut = srcFormat;
|
||||
converterInConfig.channels = config.channels;
|
||||
converterInConfig.ditherMode = mal_dither_mode_none;
|
||||
converterInConfig.onRead = on_convert_samples_in;
|
||||
converterInConfig.pUserData = &sineWave;
|
||||
result = mal_format_converter_init(&converterInConfig, &converterIn);
|
||||
if (result != MAL_SUCCESS) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
mal_format_converter_config converterOutConfig;
|
||||
mal_zero_object(&converterInConfig);
|
||||
converterOutConfig.formatIn = srcFormat;
|
||||
converterOutConfig.formatOut = dstFormat;
|
||||
converterOutConfig.channels = config.channels;
|
||||
converterOutConfig.ditherMode = ditherMode;
|
||||
converterOutConfig.onRead = on_convert_samples_out;
|
||||
converterOutConfig.pUserData = &converterIn;
|
||||
result = mal_format_converter_init(&converterOutConfig, &converterOut);
|
||||
if (result != MAL_SUCCESS) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
config = mal_device_config_init_playback(converterOutConfig.formatOut, 1, 0, on_send_to_device__dithered);
|
||||
|
||||
result = mal_device_init(NULL, mal_device_type_playback, NULL, &config, &converterOut, &device);
|
||||
if (result != MAL_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = mal_device_start(&device);
|
||||
if (result != MAL_SUCCESS) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
printf("Press Enter to stop.\n");
|
||||
getchar();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
|
||||
do_dithering_test();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -260,6 +260,7 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mal_dithering.c" />
|
||||
<ClCompile Include="mal_profiling.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -269,12 +270,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mal_test_0.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mal_test_0.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
<ClCompile Include="mal_profiling.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mal_dithering.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\mini_al.h">
|
||||
|
||||
Reference in New Issue
Block a user