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
4e91c638
Commit
4e91c638
authored
Feb 22, 2020
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Delete old tests.
parent
673dce19
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
0 additions
and
2100 deletions
+0
-2100
tests/ma_debug_playback.c
tests/ma_debug_playback.c
+0
-175
tests/ma_dithering.c
tests/ma_dithering.c
+0
-148
tests/ma_no_device_io.c
tests/ma_no_device_io.c
+0
-34
tests/ma_profiling.c
tests/ma_profiling.c
+0
-1172
tests/ma_resampling.c
tests/ma_resampling.c
+0
-143
tests/ma_stop.c
tests/ma_stop.c
+0
-98
tests/ma_webaudio_test_0.html
tests/ma_webaudio_test_0.html
+0
-330
No files found.
tests/ma_debug_playback.c
deleted
100644 → 0
View file @
673dce19
#define MA_LOG_LEVEL MA_LOG_LEVEL_VERBOSE
#define MA_DEBUG_OUTPUT
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.h"
int
print_context_info
(
ma_context
*
pContext
)
{
ma_result
result
=
MA_SUCCESS
;
ma_device_info
*
pPlaybackDeviceInfos
;
ma_uint32
playbackDeviceCount
;
ma_device_info
*
pCaptureDeviceInfos
;
ma_uint32
captureDeviceCount
;
printf
(
"BACKEND: %s
\n
"
,
ma_get_backend_name
(
pContext
->
backend
));
// Enumeration.
printf
(
" Enumerating Devices... "
);
{
result
=
ma_context_get_devices
(
pContext
,
&
pPlaybackDeviceInfos
,
&
playbackDeviceCount
,
&
pCaptureDeviceInfos
,
&
captureDeviceCount
);
if
(
result
==
MA_SUCCESS
)
{
printf
(
"Done
\n
"
);
}
else
{
printf
(
"Failed
\n
"
);
goto
done
;
}
printf
(
" Playback Devices (%d)
\n
"
,
playbackDeviceCount
);
for
(
ma_uint32
iDevice
=
0
;
iDevice
<
playbackDeviceCount
;
++
iDevice
)
{
printf
(
" %d: %s
\n
"
,
iDevice
,
pPlaybackDeviceInfos
[
iDevice
].
name
);
}
printf
(
" Capture Devices (%d)
\n
"
,
captureDeviceCount
);
for
(
ma_uint32
iDevice
=
0
;
iDevice
<
captureDeviceCount
;
++
iDevice
)
{
printf
(
" %d: %s
\n
"
,
iDevice
,
pCaptureDeviceInfos
[
iDevice
].
name
);
}
}
// Device Information.
printf
(
" Getting Device Information...
\n
"
);
{
printf
(
" Playback Devices (%d)
\n
"
,
playbackDeviceCount
);
for
(
ma_uint32
iDevice
=
0
;
iDevice
<
playbackDeviceCount
;
++
iDevice
)
{
printf
(
" %d: %s
\n
"
,
iDevice
,
pPlaybackDeviceInfos
[
iDevice
].
name
);
result
=
ma_context_get_device_info
(
pContext
,
ma_device_type_playback
,
&
pPlaybackDeviceInfos
[
iDevice
].
id
,
ma_share_mode_shared
,
&
pPlaybackDeviceInfos
[
iDevice
]);
if
(
result
==
MA_SUCCESS
)
{
printf
(
" Name: %s
\n
"
,
pPlaybackDeviceInfos
[
iDevice
].
name
);
printf
(
" Min Channels: %d
\n
"
,
pPlaybackDeviceInfos
[
iDevice
].
minChannels
);
printf
(
" Max Channels: %d
\n
"
,
pPlaybackDeviceInfos
[
iDevice
].
maxChannels
);
printf
(
" Min Sample Rate: %d
\n
"
,
pPlaybackDeviceInfos
[
iDevice
].
minSampleRate
);
printf
(
" Max Sample Rate: %d
\n
"
,
pPlaybackDeviceInfos
[
iDevice
].
maxSampleRate
);
printf
(
" Format Count: %d
\n
"
,
pPlaybackDeviceInfos
[
iDevice
].
formatCount
);
for
(
ma_uint32
iFormat
=
0
;
iFormat
<
pPlaybackDeviceInfos
[
iDevice
].
formatCount
;
++
iFormat
)
{
printf
(
" %s
\n
"
,
ma_get_format_name
(
pPlaybackDeviceInfos
[
iDevice
].
formats
[
iFormat
]));
}
}
else
{
printf
(
" ERROR
\n
"
);
}
}
printf
(
" Capture Devices (%d)
\n
"
,
captureDeviceCount
);
for
(
ma_uint32
iDevice
=
0
;
iDevice
<
captureDeviceCount
;
++
iDevice
)
{
printf
(
" %d: %s
\n
"
,
iDevice
,
pCaptureDeviceInfos
[
iDevice
].
name
);
result
=
ma_context_get_device_info
(
pContext
,
ma_device_type_capture
,
&
pCaptureDeviceInfos
[
iDevice
].
id
,
ma_share_mode_shared
,
&
pCaptureDeviceInfos
[
iDevice
]);
if
(
result
==
MA_SUCCESS
)
{
printf
(
" Name: %s
\n
"
,
pCaptureDeviceInfos
[
iDevice
].
name
);
printf
(
" Min Channels: %d
\n
"
,
pCaptureDeviceInfos
[
iDevice
].
minChannels
);
printf
(
" Max Channels: %d
\n
"
,
pCaptureDeviceInfos
[
iDevice
].
maxChannels
);
printf
(
" Min Sample Rate: %d
\n
"
,
pCaptureDeviceInfos
[
iDevice
].
minSampleRate
);
printf
(
" Max Sample Rate: %d
\n
"
,
pCaptureDeviceInfos
[
iDevice
].
maxSampleRate
);
printf
(
" Format Count: %d
\n
"
,
pCaptureDeviceInfos
[
iDevice
].
formatCount
);
for
(
ma_uint32
iFormat
=
0
;
iFormat
<
pCaptureDeviceInfos
[
iDevice
].
formatCount
;
++
iFormat
)
{
printf
(
" %s
\n
"
,
ma_get_format_name
(
pCaptureDeviceInfos
[
iDevice
].
formats
[
iFormat
]));
}
}
else
{
printf
(
" ERROR
\n
"
);
}
}
}
done:
printf
(
"
\n
"
);
return
(
result
==
MA_SUCCESS
)
?
0
:
-
1
;
}
int
print_device_info
(
ma_device
*
pDevice
)
{
printf
(
"DEVICE NAME: %s
\n
"
,
pDevice
->
name
);
printf
(
" Format: %s -> %s
\n
"
,
ma_get_format_name
(
pDevice
->
format
),
ma_get_format_name
(
pDevice
->
internalFormat
));
printf
(
" Channels: %d -> %d
\n
"
,
pDevice
->
channels
,
pDevice
->
internalChannels
);
printf
(
" Sample Rate: %d -> %d
\n
"
,
pDevice
->
sampleRate
,
pDevice
->
internalSampleRate
);
printf
(
" Buffer Size: %d
\n
"
,
pDevice
->
bufferSizeInFrames
);
printf
(
" Periods: %d
\n
"
,
pDevice
->
periods
);
return
0
;
}
ma_uint32
on_send
(
ma_device
*
pDevice
,
ma_uint32
frameCount
,
void
*
pFramesOut
)
{
ma_sine_wave
*
pSineWave
=
(
ma_sine_wave
*
)
pDevice
->
pUserData
;
ma_assert
(
pSineWave
!=
NULL
);
float
*
pFramesOutF32
=
(
float
*
)
pFramesOut
;
for
(
ma_uint32
iFrame
=
0
;
iFrame
<
frameCount
;
++
iFrame
)
{
float
sample
;
ma_sine_wave_read
(
pSineWave
,
1
,
&
sample
);
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
pDevice
->
channels
;
++
iChannel
)
{
pFramesOutF32
[
iChannel
]
=
sample
;
}
pFramesOutF32
+=
pDevice
->
channels
;
}
return
frameCount
;
}
int
main
(
int
argc
,
char
**
argv
)
{
ma_result
result
;
ma_sine_wave
sineWave
;
result
=
ma_sine_wave_init
(
0
.
2
,
400
,
44100
,
&
sineWave
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to initialize sine wave.
\n
"
);
return
-
1
;
}
// Separate context for this test.
ma_context_config
contextConfig
=
ma_context_config_init
(
NULL
);
// <-- Don't need a log callback because we're using debug output instead.
ma_context
context
;
result
=
ma_context_init
(
NULL
,
0
,
&
contextConfig
,
&
context
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to initialize context.
\n
"
);
return
-
1
;
}
print_context_info
(
&
context
);
// Device.
ma_device_config
deviceConfig
=
ma_device_config_init_playback
(
ma_format_f32
,
2
,
44100
,
on_send
);
deviceConfig
.
bufferSizeInFrames
=
32768
;
ma_device
device
;
result
=
ma_device_init
(
&
context
,
ma_device_type_playback
,
NULL
,
&
deviceConfig
,
&
sineWave
,
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
ma_context_uninit
(
&
context
);
printf
(
"Failed to initialize device.
\n
"
);
return
-
1
;
}
print_device_info
(
&
device
);
// Start playback.
result
=
ma_device_start
(
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
ma_device_uninit
(
&
device
);
ma_context_uninit
(
&
context
);
printf
(
"Failed to start device.
\n
"
);
return
-
1
;
}
printf
(
"Press Enter to quit...
\n
"
);
getchar
();
ma_device_uninit
(
&
device
);
ma_context_uninit
(
&
context
);
return
0
;
}
tests/ma_dithering.c
deleted
100644 → 0
View file @
673dce19
#define MA_DEBUG_OUTPUT
#define MA_USE_REFERENCE_CONVERSION_APIS
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.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.
ma_sine_wave
sineWave
;
ma_format_converter
converterIn
;
ma_format_converter
converterOut
;
ma_uint32
on_convert_samples_in
(
ma_format_converter
*
pConverter
,
ma_uint32
frameCount
,
void
*
pFrames
,
void
*
pUserData
)
{
(
void
)
pUserData
;
ma_assert
(
pConverter
->
config
.
formatIn
==
ma_format_f32
);
ma_sine_wave
*
pSineWave
=
(
ma_sine_wave
*
)
pConverter
->
config
.
pUserData
;
ma_assert
(
pSineWave
);
return
(
ma_uint32
)
ma_sine_wave_read_f32
(
pSineWave
,
frameCount
,
(
float
*
)
pFrames
);
}
ma_uint32
on_convert_samples_out
(
ma_format_converter
*
pConverter
,
ma_uint32
frameCount
,
void
*
pFrames
,
void
*
pUserData
)
{
(
void
)
pUserData
;
ma_format_converter
*
pConverterIn
=
(
ma_format_converter
*
)
pConverter
->
config
.
pUserData
;
ma_assert
(
pConverterIn
!=
NULL
);
return
(
ma_uint32
)
ma_format_converter_read
(
pConverterIn
,
frameCount
,
pFrames
,
NULL
);
}
void
on_send_to_device__original
(
ma_device
*
pDevice
,
void
*
pOutput
,
const
void
*
pInput
,
ma_uint32
frameCount
)
{
ma_assert
(
pDevice
->
playback
.
format
==
ma_format_f32
);
ma_assert
(
pDevice
->
playback
.
channels
==
1
);
ma_sine_wave_read_f32
(
&
sineWave
,
frameCount
,
(
float
*
)
pOutput
);
(
void
)
pDevice
;
(
void
)
pInput
;
}
void
on_send_to_device__dithered
(
ma_device
*
pDevice
,
void
*
pOutput
,
const
void
*
pInput
,
ma_uint32
frameCount
)
{
ma_assert
(
pDevice
->
playback
.
channels
==
1
);
ma_format_converter
*
pConverter
=
(
ma_format_converter
*
)
pDevice
->
pUserData
;
ma_assert
(
pConverter
!=
NULL
);
ma_assert
(
pDevice
->
playback
.
format
==
pConverter
->
config
.
formatOut
);
ma_format_converter_read
(
pConverter
,
frameCount
,
pOutput
,
NULL
);
(
void
)
pInput
;
}
int
do_dithering_test
()
{
ma_device_config
config
;
ma_device
device
;
ma_result
result
;
config
=
ma_device_config_init
(
ma_device_type_playback
);
config
.
playback
.
format
=
ma_format_f32
;
config
.
playback
.
channels
=
1
;
config
.
sampleRate
=
0
;
config
.
dataCallback
=
on_send_to_device__original
;
// We first play the sound the way it's meant to be played.
result
=
ma_device_init
(
NULL
,
&
config
,
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
return
-
1
;
}
ma_sine_wave_init
(
0
.
5
,
400
,
device
.
sampleRate
,
&
sineWave
);
result
=
ma_device_start
(
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
return
-
2
;
}
printf
(
"Press Enter to play enable dithering.
\n
"
);
getchar
();
ma_device_uninit
(
&
device
);
ma_format
srcFormat
=
ma_format_s24
;
ma_format
dstFormat
=
ma_format_u8
;
ma_dither_mode
ditherMode
=
ma_dither_mode_triangle
;
ma_format_converter_config
converterInConfig
=
ma_format_converter_config_init_new
();
converterInConfig
.
formatIn
=
ma_format_f32
;
// <-- From the sine wave generator.
converterInConfig
.
formatOut
=
srcFormat
;
converterInConfig
.
channels
=
config
.
playback
.
channels
;
converterInConfig
.
ditherMode
=
ma_dither_mode_none
;
converterInConfig
.
onRead
=
on_convert_samples_in
;
converterInConfig
.
pUserData
=
&
sineWave
;
result
=
ma_format_converter_init
(
&
converterInConfig
,
&
converterIn
);
if
(
result
!=
MA_SUCCESS
)
{
return
-
3
;
}
ma_format_converter_config
converterOutConfig
=
ma_format_converter_config_init_new
();
converterOutConfig
.
formatIn
=
srcFormat
;
converterOutConfig
.
formatOut
=
dstFormat
;
converterOutConfig
.
channels
=
config
.
playback
.
channels
;
converterOutConfig
.
ditherMode
=
ditherMode
;
converterOutConfig
.
onRead
=
on_convert_samples_out
;
converterOutConfig
.
pUserData
=
&
converterIn
;
result
=
ma_format_converter_init
(
&
converterOutConfig
,
&
converterOut
);
if
(
result
!=
MA_SUCCESS
)
{
return
-
3
;
}
config
.
playback
.
format
=
dstFormat
;
config
.
dataCallback
=
on_send_to_device__dithered
;
config
.
pUserData
=
&
converterOut
;
result
=
ma_device_init
(
NULL
,
&
config
,
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
return
-
1
;
}
// Now we play the sound after it's run through a dithered format converter.
ma_sine_wave_init
(
0
.
5
,
400
,
device
.
sampleRate
,
&
sineWave
);
result
=
ma_device_start
(
&
device
);
if
(
result
!=
MA_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
;
}
\ No newline at end of file
tests/ma_no_device_io.c
deleted
100644 → 0
View file @
673dce19
// Just a simple test to check that MA_NO_DEVICE_IO compiles.
#include "../extras/dr_flac.h"
#include "../extras/dr_mp3.h"
#include "../extras/dr_wav.h"
#define MA_NO_DEVICE_IO
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.h"
int
main
(
int
argc
,
char
**
argv
)
{
(
void
)
argc
;
(
void
)
argv
;
ma_result
result
=
MA_ERROR
;
ma_pcm_converter_config
dspConfig
=
ma_pcm_converter_config_init_new
();
ma_pcm_converter
converter
;
result
=
ma_pcm_converter_init
(
&
dspConfig
,
&
converter
);
ma_decoder_config
decoderConfig
=
ma_decoder_config_init
(
ma_format_unknown
,
0
,
0
);
ma_decoder
decoder
;
result
=
ma_decoder_init_file
(
"res/sine_s16_mono_48000.wav"
,
&
decoderConfig
,
&
decoder
);
return
result
;
}
#define DR_FLAC_IMPLEMENTATION
#include "../extras/dr_flac.h"
#define DR_MP3_IMPLEMENTATION
#include "../extras/dr_mp3.h"
#define DR_WAV_IMPLEMENTATION
#include "../extras/dr_wav.h"
tests/ma_profiling.c
deleted
100644 → 0
View file @
673dce19
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.h"
typedef
enum
{
simd_mode_scalar
=
0
,
simd_mode_sse2
,
simd_mode_avx2
,
simd_mode_avx512
,
simd_mode_neon
}
simd_mode
;
const
char
*
simd_mode_to_string
(
simd_mode
mode
)
{
switch
(
mode
)
{
case
simd_mode_scalar
:
return
"Reference"
;
case
simd_mode_sse2
:
return
"SSE2"
;
case
simd_mode_avx2
:
return
"AVX2"
;
case
simd_mode_avx512
:
return
"AVX-512"
;
case
simd_mode_neon
:
return
"NEON"
;
}
return
"Unknown"
;
}
const
char
*
ma_src_algorithm_to_string
(
ma_src_algorithm
algorithm
)
{
switch
(
algorithm
)
{
case
ma_src_algorithm_none
:
return
"Passthrough"
;
case
ma_src_algorithm_linear
:
return
"Linear"
;
case
ma_src_algorithm_sinc
:
return
"Sinc"
;
}
return
"Unknown"
;
}
const
char
*
ma_dither_mode_to_string
(
ma_dither_mode
ditherMode
)
{
switch
(
ditherMode
)
{
case
ma_dither_mode_none
:
return
"None"
;
case
ma_dither_mode_rectangle
:
return
"Rectangle"
;
case
ma_dither_mode_triangle
:
return
"Triangle"
;
}
return
"Unkown"
;
}
///////////////////////////////////////////////////////////////////////////////
//
// Format Conversion
//
///////////////////////////////////////////////////////////////////////////////
typedef
struct
{
void
*
pBaseData
;
ma_uint64
sampleCount
;
ma_uint64
iNextSample
;
}
format_conversion_data
;
void
pcm_convert__reference
(
void
*
pOut
,
ma_format
formatOut
,
const
void
*
pIn
,
ma_format
formatIn
,
ma_uint64
sampleCount
,
ma_dither_mode
ditherMode
)
{
switch
(
formatIn
)
{
case
ma_format_u8
:
{
switch
(
formatOut
)
{
case
ma_format_s16
:
ma_pcm_u8_to_s16__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_u8_to_s24__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_u8_to_s32__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_u8_to_f32__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s16
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s16_to_u8__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s16_to_s24__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s16_to_s32__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s16_to_f32__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s24
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s24_to_u8__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s24_to_s16__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s24_to_s32__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s24_to_f32__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s32_to_u8__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s32_to_s16__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s32_to_s24__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s32_to_f32__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_f32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_f32_to_u8__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_f32_to_s16__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_f32_to_s24__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_f32_to_s32__reference
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
default:
break
;
}
}
void
pcm_convert__optimized
(
void
*
pOut
,
ma_format
formatOut
,
const
void
*
pIn
,
ma_format
formatIn
,
ma_uint64
sampleCount
,
ma_dither_mode
ditherMode
)
{
switch
(
formatIn
)
{
case
ma_format_u8
:
{
switch
(
formatOut
)
{
case
ma_format_s16
:
ma_pcm_u8_to_s16__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_u8_to_s24__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_u8_to_s32__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_u8_to_f32__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s16
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s16_to_u8__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s16_to_s24__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s16_to_s32__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s16_to_f32__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s24
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s24_to_u8__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s24_to_s16__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s24_to_s32__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s24_to_f32__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s32_to_u8__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s32_to_s16__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s32_to_s24__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s32_to_f32__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_f32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_f32_to_u8__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_f32_to_s16__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_f32_to_s24__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_f32_to_s32__optimized
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
default:
break
;
}
}
#if defined(MA_SUPPORT_SSE2)
void
pcm_convert__sse2
(
void
*
pOut
,
ma_format
formatOut
,
const
void
*
pIn
,
ma_format
formatIn
,
ma_uint64
sampleCount
,
ma_dither_mode
ditherMode
)
{
switch
(
formatIn
)
{
case
ma_format_u8
:
{
switch
(
formatOut
)
{
case
ma_format_s16
:
ma_pcm_u8_to_s16__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_u8_to_s24__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_u8_to_s32__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_u8_to_f32__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s16
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s16_to_u8__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s16_to_s24__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s16_to_s32__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s16_to_f32__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s24
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s24_to_u8__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s24_to_s16__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s24_to_s32__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s24_to_f32__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s32_to_u8__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s32_to_s16__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s32_to_s24__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s32_to_f32__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_f32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_f32_to_u8__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_f32_to_s16__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_f32_to_s24__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_f32_to_s32__sse2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
default:
break
;
}
}
#endif
#if defined(MA_SUPPORT_AVX2)
void
pcm_convert__avx
(
void
*
pOut
,
ma_format
formatOut
,
const
void
*
pIn
,
ma_format
formatIn
,
ma_uint64
sampleCount
,
ma_dither_mode
ditherMode
)
{
switch
(
formatIn
)
{
case
ma_format_u8
:
{
switch
(
formatOut
)
{
case
ma_format_s16
:
ma_pcm_u8_to_s16__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_u8_to_s24__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_u8_to_s32__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_u8_to_f32__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s16
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s16_to_u8__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s16_to_s24__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s16_to_s32__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s16_to_f32__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s24
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s24_to_u8__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s24_to_s16__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s24_to_s32__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s24_to_f32__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s32_to_u8__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s32_to_s16__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s32_to_s24__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s32_to_f32__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_f32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_f32_to_u8__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_f32_to_s16__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_f32_to_s24__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_f32_to_s32__avx2
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
default:
break
;
}
}
#endif
#if defined(MA_SUPPORT_AVX512)
void
pcm_convert__avx512
(
void
*
pOut
,
ma_format
formatOut
,
const
void
*
pIn
,
ma_format
formatIn
,
ma_uint64
sampleCount
,
ma_dither_mode
ditherMode
)
{
switch
(
formatIn
)
{
case
ma_format_u8
:
{
switch
(
formatOut
)
{
case
ma_format_s16
:
ma_pcm_u8_to_s16__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_u8_to_s24__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_u8_to_s32__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_u8_to_f32__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s16
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s16_to_u8__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s16_to_s24__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s16_to_s32__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s16_to_f32__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s24
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s24_to_u8__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s24_to_s16__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s24_to_s32__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s24_to_f32__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s32_to_u8__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s32_to_s16__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s32_to_s24__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s32_to_f32__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_f32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_f32_to_u8__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_f32_to_s16__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_f32_to_s24__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_f32_to_s32__avx512
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
default:
break
;
}
}
#endif
#if defined(MA_SUPPORT_NEON)
void
pcm_convert__neon
(
void
*
pOut
,
ma_format
formatOut
,
const
void
*
pIn
,
ma_format
formatIn
,
ma_uint64
sampleCount
,
ma_dither_mode
ditherMode
)
{
switch
(
formatIn
)
{
case
ma_format_u8
:
{
switch
(
formatOut
)
{
case
ma_format_s16
:
ma_pcm_u8_to_s16__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_u8_to_s24__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_u8_to_s32__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_u8_to_f32__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s16
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s16_to_u8__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s16_to_s24__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s16_to_s32__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s16_to_f32__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s24
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s24_to_u8__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s24_to_s16__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_s24_to_s32__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s24_to_f32__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_s32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_s32_to_u8__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_s32_to_s16__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_s32_to_s24__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_f32
:
ma_pcm_s32_to_f32__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
case
ma_format_f32
:
{
switch
(
formatOut
)
{
case
ma_format_u8
:
ma_pcm_f32_to_u8__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s16
:
ma_pcm_f32_to_s16__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s24
:
ma_pcm_f32_to_s24__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
case
ma_format_s32
:
ma_pcm_f32_to_s32__neon
(
pOut
,
pIn
,
sampleCount
,
ditherMode
);
return
;
default:
break
;
}
}
break
;
default:
break
;
}
}
#endif
void
pcm_convert
(
void
*
pOut
,
ma_format
formatOut
,
const
void
*
pIn
,
ma_format
formatIn
,
ma_uint64
sampleCount
,
ma_dither_mode
ditherMode
,
simd_mode
mode
)
{
// For testing, we always reset the seed for dithering so we can get consistent results for comparisons.
ma_seed
(
1234
);
switch
(
mode
)
{
case
simd_mode_scalar
:
{
pcm_convert__optimized
(
pOut
,
formatOut
,
pIn
,
formatIn
,
sampleCount
,
ditherMode
);
}
break
;
#if defined(MA_SUPPORT_SSE2)
case
simd_mode_sse2
:
{
pcm_convert__sse2
(
pOut
,
formatOut
,
pIn
,
formatIn
,
sampleCount
,
ditherMode
);
}
break
;
#endif
#if defined(MA_SUPPORT_AVX2)
case
simd_mode_avx2
:
{
pcm_convert__avx
(
pOut
,
formatOut
,
pIn
,
formatIn
,
sampleCount
,
ditherMode
);
}
break
;
#endif
#if defined(MA_SUPPORT_AVX512)
case
simd_mode_avx512
:
{
pcm_convert__avx512
(
pOut
,
formatOut
,
pIn
,
formatIn
,
sampleCount
,
ditherMode
);
}
break
;
#endif
#if defined(MA_SUPPORT_NEON)
case
simd_mode_neon
:
{
pcm_convert__neon
(
pOut
,
formatOut
,
pIn
,
formatIn
,
sampleCount
,
ditherMode
);
}
break
;
#endif
default:
break
;
}
}
int
do_profiling__format_conversion__profile_individual
(
ma_format
formatIn
,
ma_format
formatOut
,
ma_dither_mode
ditherMode
,
const
void
*
pBaseData
,
ma_uint64
sampleCount
,
simd_mode
mode
,
const
void
*
pReferenceData
,
double
referenceTime
)
{
void
*
pTestData
=
ma_aligned_malloc
((
size_t
)(
sampleCount
*
ma_get_bytes_per_sample
(
formatOut
)),
MA_SIMD_ALIGNMENT
);
if
(
pTestData
==
NULL
)
{
printf
(
"Out of memory.
\n
"
);
return
-
1
;
}
ma_timer
timer
;
ma_timer_init
(
&
timer
);
double
timeTaken
=
ma_timer_get_time_in_seconds
(
&
timer
);
{
pcm_convert
(
pTestData
,
formatOut
,
pBaseData
,
formatIn
,
sampleCount
,
ditherMode
,
mode
);
}
timeTaken
=
ma_timer_get_time_in_seconds
(
&
timer
)
-
timeTaken
;
// Compare with the reference for correctness.
ma_bool32
passed
=
MA_TRUE
;
for
(
ma_uint64
iSample
=
0
;
iSample
<
sampleCount
;
++
iSample
)
{
ma_uint32
bps
=
ma_get_bytes_per_sample
(
formatOut
);
// We need to compare on a format by format basis because we allow for very slight deviations in results depending on the output format.
switch
(
formatOut
)
{
case
ma_format_s16
:
{
ma_int16
a
=
((
const
ma_int16
*
)
pReferenceData
)[
iSample
];
ma_int16
b
=
((
const
ma_int16
*
)
pTestData
)[
iSample
];
if
(
abs
(
a
-
b
)
>
0
)
{
printf
(
"Incorrect Sample: (%d) %d != %d
\n
"
,
(
int
)
iSample
,
a
,
b
);
passed
=
MA_FALSE
;
}
}
break
;
default:
{
if
(
memcmp
(
ma_offset_ptr
(
pReferenceData
,
iSample
*
bps
),
ma_offset_ptr
(
pTestData
,
iSample
*
bps
),
bps
)
!=
0
)
{
printf
(
"Incorrect Sample: (%d)
\n
"
,
(
int
)
iSample
);
passed
=
MA_FALSE
;
}
}
break
;
}
}
if
(
passed
)
{
printf
(
" [PASSED] "
);
}
else
{
printf
(
" [FAILED] "
);
}
printf
(
"(Dither = %s) %s -> %s (%s): %.4fms (%.2f%%)
\n
"
,
ma_dither_mode_to_string
(
ditherMode
),
ma_get_format_name
(
formatIn
),
ma_get_format_name
(
formatOut
),
simd_mode_to_string
(
mode
),
timeTaken
*
1000
,
referenceTime
/
timeTaken
*
100
);
ma_aligned_free
(
pTestData
);
return
0
;
}
int
do_profiling__format_conversion__profile_set
(
ma_format
formatIn
,
ma_format
formatOut
,
ma_dither_mode
ditherMode
)
{
// Generate our base data to begin with. This is generated from an f32 sine wave which is converted to formatIn. That then becomes our base data.
ma_uint32
sampleCount
=
10000000
;
float
*
pSourceData
=
(
float
*
)
ma_aligned_malloc
(
sampleCount
*
sizeof
(
*
pSourceData
),
MA_SIMD_ALIGNMENT
);
if
(
pSourceData
==
NULL
)
{
printf
(
"Out of memory.
\n
"
);
return
-
1
;
}
ma_sine_wave
sineWave
;
ma_sine_wave_init
(
1
.
0
,
400
,
48000
,
&
sineWave
);
ma_sine_wave_read_f32
(
&
sineWave
,
sampleCount
,
pSourceData
);
void
*
pBaseData
=
ma_aligned_malloc
(
sampleCount
*
ma_get_bytes_per_sample
(
formatIn
),
MA_SIMD_ALIGNMENT
);
ma_pcm_convert
(
pBaseData
,
formatIn
,
pSourceData
,
ma_format_f32
,
sampleCount
,
ma_dither_mode_none
);
// Reference first so we can get a benchmark.
void
*
pReferenceData
=
ma_aligned_malloc
(
sampleCount
*
ma_get_bytes_per_sample
(
formatOut
),
MA_SIMD_ALIGNMENT
);
ma_timer
timer
;
ma_timer_init
(
&
timer
);
double
referenceTime
=
ma_timer_get_time_in_seconds
(
&
timer
);
{
pcm_convert__reference
(
pReferenceData
,
formatOut
,
pBaseData
,
formatIn
,
sampleCount
,
ditherMode
);
}
referenceTime
=
ma_timer_get_time_in_seconds
(
&
timer
)
-
referenceTime
;
// Here is where each optimized implementation is profiled.
do_profiling__format_conversion__profile_individual
(
formatIn
,
formatOut
,
ditherMode
,
pBaseData
,
sampleCount
,
simd_mode_scalar
,
pReferenceData
,
referenceTime
);
if
(
ma_has_sse2
())
{
do_profiling__format_conversion__profile_individual
(
formatIn
,
formatOut
,
ditherMode
,
pBaseData
,
sampleCount
,
simd_mode_sse2
,
pReferenceData
,
referenceTime
);
}
if
(
ma_has_avx2
())
{
do_profiling__format_conversion__profile_individual
(
formatIn
,
formatOut
,
ditherMode
,
pBaseData
,
sampleCount
,
simd_mode_avx2
,
pReferenceData
,
referenceTime
);
}
if
(
ma_has_avx512f
())
{
do_profiling__format_conversion__profile_individual
(
formatIn
,
formatOut
,
ditherMode
,
pBaseData
,
sampleCount
,
simd_mode_avx512
,
pReferenceData
,
referenceTime
);
}
if
(
ma_has_neon
())
{
do_profiling__format_conversion__profile_individual
(
formatIn
,
formatOut
,
ditherMode
,
pBaseData
,
sampleCount
,
simd_mode_neon
,
pReferenceData
,
referenceTime
);
}
ma_aligned_free
(
pReferenceData
);
ma_aligned_free
(
pBaseData
);
ma_aligned_free
(
pSourceData
);
return
0
;
}
int
do_profiling__format_conversion
()
{
// First we need to generate our base data.
do_profiling__format_conversion__profile_set
(
ma_format_f32
,
ma_format_s16
,
ma_dither_mode_none
);
return
0
;
}
///////////////////////////////////////////////////////////////////////////////
//
// Channel Routing
//
///////////////////////////////////////////////////////////////////////////////
float
g_ChannelRouterProfilingOutputBenchmark
[
8
][
48000
];
float
g_ChannelRouterProfilingOutput
[
8
][
48000
];
double
g_ChannelRouterTime_Reference
=
0
;
double
g_ChannelRouterTime_SSE2
=
0
;
double
g_ChannelRouterTime_AVX2
=
0
;
double
g_ChannelRouterTime_AVX512
=
0
;
double
g_ChannelRouterTime_NEON
=
0
;
ma_sine_wave
g_sineWave
;
ma_bool32
channel_router_test
(
ma_uint32
channels
,
ma_uint64
frameCount
,
float
**
ppFramesA
,
float
**
ppFramesB
)
{
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
channels
;
++
iChannel
)
{
for
(
ma_uint32
iFrame
=
0
;
iFrame
<
frameCount
;
++
iFrame
)
{
if
(
ppFramesA
[
iChannel
][
iFrame
]
!=
ppFramesB
[
iChannel
][
iFrame
])
{
return
MA_FALSE
;
}
}
}
return
MA_TRUE
;
}
ma_uint32
channel_router_on_read
(
ma_channel_router
*
pRouter
,
ma_uint32
frameCount
,
void
**
ppSamplesOut
,
void
*
pUserData
)
{
(
void
)
pUserData
;
(
void
)
pRouter
;
float
**
ppSamplesOutF
=
(
float
**
)
ppSamplesOut
;
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
pRouter
->
config
.
channelsIn
;
++
iChannel
)
{
ma_sine_wave_init
(
1
/
(
iChannel
+
1
),
400
,
48000
,
&
g_sineWave
);
ma_sine_wave_read_f32
(
&
g_sineWave
,
frameCount
,
ppSamplesOutF
[
iChannel
]);
}
return
frameCount
;
}
int
do_profiling__channel_routing
()
{
ma_result
result
;
// When profiling we need to compare against a benchmark to ensure the optimization is implemented correctly. We always
// use the reference implementation for our benchmark.
ma_uint32
channels
=
ma_countof
(
g_ChannelRouterProfilingOutputBenchmark
);
ma_channel
channelMapIn
[
MA_MAX_CHANNELS
];
ma_get_standard_channel_map
(
ma_standard_channel_map_default
,
channels
,
channelMapIn
);
ma_channel
channelMapOut
[
MA_MAX_CHANNELS
];
ma_get_standard_channel_map
(
ma_standard_channel_map_default
,
channels
,
channelMapOut
);
ma_channel_router_config
routerConfig
=
ma_channel_router_config_init
(
channels
,
channelMapIn
,
channels
,
channelMapOut
,
ma_channel_mix_mode_planar_blend
,
channel_router_on_read
,
NULL
);
ma_channel_router
router
;
result
=
ma_channel_router_init
(
&
routerConfig
,
&
router
);
if
(
result
!=
MA_SUCCESS
)
{
return
-
1
;
}
// Disable optimizations for our tests.
router
.
isPassthrough
=
MA_FALSE
;
router
.
isSimpleShuffle
=
MA_FALSE
;
router
.
useSSE2
=
MA_FALSE
;
router
.
useAVX2
=
MA_FALSE
;
router
.
useAVX512
=
MA_FALSE
;
router
.
useNEON
=
MA_FALSE
;
ma_uint64
framesToRead
=
ma_countof
(
g_ChannelRouterProfilingOutputBenchmark
[
0
]);
// Benchmark
void
*
ppOutBenchmark
[
8
];
for
(
int
i
=
0
;
i
<
8
;
++
i
)
{
ppOutBenchmark
[
i
]
=
(
void
*
)
g_ChannelRouterProfilingOutputBenchmark
[
i
];
}
ma_sine_wave_init
(
1
,
400
,
48000
,
&
g_sineWave
);
ma_uint64
framesRead
=
ma_channel_router_read_deinterleaved
(
&
router
,
framesToRead
,
ppOutBenchmark
,
NULL
);
if
(
framesRead
!=
framesToRead
)
{
printf
(
"Channel Router: An error occurred while reading benchmark data.
\n
"
);
}
void
*
ppOut
[
8
];
for
(
int
i
=
0
;
i
<
8
;
++
i
)
{
ppOut
[
i
]
=
(
void
*
)
g_ChannelRouterProfilingOutput
[
i
];
}
printf
(
"Channel Routing
\n
"
);
printf
(
"===============
\n
"
);
// Reference
{
ma_timer
timer
;
ma_timer_init
(
&
timer
);
double
startTime
=
ma_timer_get_time_in_seconds
(
&
timer
);
framesRead
=
ma_channel_router_read_deinterleaved
(
&
router
,
framesToRead
,
ppOut
,
NULL
);
if
(
framesRead
!=
framesToRead
)
{
printf
(
"Channel Router: An error occurred while reading reference data.
\n
"
);
}
if
(
!
channel_router_test
(
channels
,
framesRead
,
(
float
**
)
ppOutBenchmark
,
(
float
**
)
ppOut
))
{
printf
(
" [ERROR] "
);
}
else
{
printf
(
" [PASSED] "
);
}
g_ChannelRouterTime_Reference
=
ma_timer_get_time_in_seconds
(
&
timer
)
-
startTime
;
printf
(
"Reference: %.4fms (%.2f%%)
\n
"
,
g_ChannelRouterTime_Reference
*
1000
,
g_ChannelRouterTime_Reference
/
g_ChannelRouterTime_Reference
*
100
);
}
// SSE2
if
(
ma_has_sse2
())
{
router
.
useSSE2
=
MA_TRUE
;
ma_timer
timer
;
ma_timer_init
(
&
timer
);
double
startTime
=
ma_timer_get_time_in_seconds
(
&
timer
);
framesRead
=
ma_channel_router_read_deinterleaved
(
&
router
,
framesToRead
,
ppOut
,
NULL
);
if
(
framesRead
!=
framesToRead
)
{
printf
(
"Channel Router: An error occurred while reading SSE2 data.
\n
"
);
}
g_ChannelRouterTime_SSE2
=
ma_timer_get_time_in_seconds
(
&
timer
)
-
startTime
;
router
.
useSSE2
=
MA_FALSE
;
if
(
!
channel_router_test
(
channels
,
framesRead
,
(
float
**
)
ppOutBenchmark
,
(
float
**
)
ppOut
))
{
printf
(
" [ERROR] "
);
}
else
{
printf
(
" [PASSED] "
);
}
printf
(
"SSE2: %.4fms (%.2f%%)
\n
"
,
g_ChannelRouterTime_SSE2
*
1000
,
g_ChannelRouterTime_Reference
/
g_ChannelRouterTime_SSE2
*
100
);
}
// AVX2
if
(
ma_has_avx2
())
{
router
.
useAVX2
=
MA_TRUE
;
ma_timer
timer
;
ma_timer_init
(
&
timer
);
double
startTime
=
ma_timer_get_time_in_seconds
(
&
timer
);
framesRead
=
ma_channel_router_read_deinterleaved
(
&
router
,
framesToRead
,
ppOut
,
NULL
);
if
(
framesRead
!=
framesToRead
)
{
printf
(
"Channel Router: An error occurred while reading AVX2 data.
\n
"
);
}
g_ChannelRouterTime_AVX2
=
ma_timer_get_time_in_seconds
(
&
timer
)
-
startTime
;
router
.
useAVX2
=
MA_FALSE
;
if
(
!
channel_router_test
(
channels
,
framesRead
,
(
float
**
)
ppOutBenchmark
,
(
float
**
)
ppOut
))
{
printf
(
" [ERROR] "
);
}
else
{
printf
(
" [PASSED] "
);
}
printf
(
"AVX2: %.4fms (%.2f%%)
\n
"
,
g_ChannelRouterTime_AVX2
*
1000
,
g_ChannelRouterTime_Reference
/
g_ChannelRouterTime_AVX2
*
100
);
}
// NEON
if
(
ma_has_neon
())
{
router
.
useNEON
=
MA_TRUE
;
ma_timer
timer
;
ma_timer_init
(
&
timer
);
double
startTime
=
ma_timer_get_time_in_seconds
(
&
timer
);
framesRead
=
ma_channel_router_read_deinterleaved
(
&
router
,
framesToRead
,
ppOut
,
NULL
);
if
(
framesRead
!=
framesToRead
)
{
printf
(
"Channel Router: An error occurred while reading NEON data.
\n
"
);
}
g_ChannelRouterTime_NEON
=
ma_timer_get_time_in_seconds
(
&
timer
)
-
startTime
;
router
.
useNEON
=
MA_FALSE
;
if
(
!
channel_router_test
(
channels
,
framesRead
,
(
float
**
)
ppOutBenchmark
,
(
float
**
)
ppOut
))
{
printf
(
" [ERROR] "
);
}
else
{
printf
(
" [PASSED] "
);
}
printf
(
"NEON: %.4fms (%.2f%%)
\n
"
,
g_ChannelRouterTime_NEON
*
1000
,
g_ChannelRouterTime_Reference
/
g_ChannelRouterTime_NEON
*
100
);
}
return
0
;
}
///////////////////////////////////////////////////////////////////////////////
//
// SRC
//
///////////////////////////////////////////////////////////////////////////////
typedef
struct
{
float
*
pFrameData
[
MA_MAX_CHANNELS
];
ma_uint64
frameCount
;
ma_uint32
channels
;
double
timeTaken
;
}
src_reference_data
;
typedef
struct
{
float
*
pFrameData
[
MA_MAX_CHANNELS
];
ma_uint64
frameCount
;
ma_uint64
iNextFrame
;
ma_uint32
channels
;
}
src_data
;
ma_uint32
do_profiling__src__on_read
(
ma_src
*
pSRC
,
ma_uint32
frameCount
,
void
**
ppSamplesOut
,
void
*
pUserData
)
{
src_data
*
pBaseData
=
(
src_data
*
)
pUserData
;
ma_assert
(
pBaseData
!=
NULL
);
ma_assert
(
pBaseData
->
iNextFrame
<=
pBaseData
->
frameCount
);
ma_uint64
framesToRead
=
frameCount
;
ma_uint64
framesAvailable
=
pBaseData
->
frameCount
-
pBaseData
->
iNextFrame
;
if
(
framesToRead
>
framesAvailable
)
{
framesToRead
=
framesAvailable
;
}
if
(
framesToRead
>
0
)
{
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
pSRC
->
config
.
channels
;
iChannel
+=
1
)
{
ma_copy_memory
(
ppSamplesOut
[
iChannel
],
pBaseData
->
pFrameData
[
iChannel
],
(
size_t
)(
framesToRead
*
sizeof
(
float
)));
}
}
pBaseData
->
iNextFrame
+=
framesToRead
;
return
(
ma_uint32
)
framesToRead
;
}
ma_result
init_src
(
src_data
*
pBaseData
,
ma_uint32
sampleRateIn
,
ma_uint32
sampleRateOut
,
ma_src_algorithm
algorithm
,
simd_mode
mode
,
ma_src
*
pSRC
)
{
ma_assert
(
pBaseData
!=
NULL
);
ma_assert
(
pSRC
!=
NULL
);
ma_src_config
srcConfig
=
ma_src_config_init
(
sampleRateIn
,
sampleRateOut
,
pBaseData
->
channels
,
do_profiling__src__on_read
,
pBaseData
);
srcConfig
.
sinc
.
windowWidth
=
17
;
// <-- Make this an odd number to test unaligned section in the SIMD implementations.
srcConfig
.
algorithm
=
algorithm
;
srcConfig
.
noSSE2
=
MA_TRUE
;
srcConfig
.
noAVX2
=
MA_TRUE
;
srcConfig
.
noAVX512
=
MA_TRUE
;
srcConfig
.
noNEON
=
MA_TRUE
;
switch
(
mode
)
{
case
simd_mode_sse2
:
srcConfig
.
noSSE2
=
MA_FALSE
;
break
;
case
simd_mode_avx2
:
srcConfig
.
noAVX2
=
MA_FALSE
;
break
;
case
simd_mode_avx512
:
srcConfig
.
noAVX512
=
MA_FALSE
;
break
;
case
simd_mode_neon
:
srcConfig
.
noNEON
=
MA_FALSE
;
break
;
case
simd_mode_scalar
:
default:
break
;
}
ma_result
result
=
ma_src_init
(
&
srcConfig
,
pSRC
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to initialize sample rate converter.
\n
"
);
return
(
int
)
result
;
}
return
result
;
}
int
do_profiling__src__profile_individual
(
src_data
*
pBaseData
,
ma_uint32
sampleRateIn
,
ma_uint32
sampleRateOut
,
ma_src_algorithm
algorithm
,
simd_mode
mode
,
src_reference_data
*
pReferenceData
)
{
ma_assert
(
pBaseData
!=
NULL
);
ma_assert
(
pReferenceData
!=
NULL
);
ma_result
result
=
MA_ERROR
;
// Make sure the base data is moved back to the start.
pBaseData
->
iNextFrame
=
0
;
ma_src
src
;
result
=
init_src
(
pBaseData
,
sampleRateIn
,
sampleRateOut
,
algorithm
,
mode
,
&
src
);
if
(
result
!=
MA_SUCCESS
)
{
return
(
int
)
result
;
}
// Profiling.
ma_uint64
sz
=
pReferenceData
->
frameCount
*
sizeof
(
float
);
ma_assert
(
sz
<=
SIZE_MAX
);
float
*
pFrameData
[
MA_MAX_CHANNELS
];
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
pBaseData
->
channels
;
iChannel
+=
1
)
{
pFrameData
[
iChannel
]
=
(
float
*
)
ma_aligned_malloc
((
size_t
)
sz
,
MA_SIMD_ALIGNMENT
);
if
(
pFrameData
[
iChannel
]
==
NULL
)
{
printf
(
"Out of memory.
\n
"
);
return
-
2
;
}
ma_zero_memory
(
pFrameData
[
iChannel
],
(
size_t
)
sz
);
}
ma_timer
timer
;
ma_timer_init
(
&
timer
);
double
startTime
=
ma_timer_get_time_in_seconds
(
&
timer
);
{
ma_src_read_deinterleaved
(
&
src
,
pReferenceData
->
frameCount
,
(
void
**
)
pFrameData
,
pBaseData
);
}
double
timeTaken
=
ma_timer_get_time_in_seconds
(
&
timer
)
-
startTime
;
// Correctness test.
ma_bool32
passed
=
MA_TRUE
;
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
pReferenceData
->
channels
;
iChannel
+=
1
)
{
for
(
ma_uint32
iFrame
=
0
;
iFrame
<
pReferenceData
->
frameCount
;
iFrame
+=
1
)
{
float
s0
=
pReferenceData
->
pFrameData
[
iChannel
][
iFrame
];
float
s1
=
pFrameData
[
iChannel
][
iFrame
];
//if (s0 != s1) {
if
(
fabs
(
s0
-
s1
)
>
0
.
000001
)
{
printf
(
"(Channel %d, Sample %d) %f != %f
\n
"
,
iChannel
,
iFrame
,
s0
,
s1
);
passed
=
MA_FALSE
;
}
}
}
// Print results.
if
(
passed
)
{
printf
(
" [PASSED] "
);
}
else
{
printf
(
" [FAILED] "
);
}
printf
(
"%s %d -> %d (%s): %.4fms (%.2f%%)
\n
"
,
ma_src_algorithm_to_string
(
algorithm
),
sampleRateIn
,
sampleRateOut
,
simd_mode_to_string
(
mode
),
timeTaken
*
1000
,
pReferenceData
->
timeTaken
/
timeTaken
*
100
);
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
pBaseData
->
channels
;
iChannel
+=
1
)
{
ma_aligned_free
(
pFrameData
[
iChannel
]);
}
return
(
int
)
result
;
}
int
do_profiling__src__profile_set
(
src_data
*
pBaseData
,
ma_uint32
sampleRateIn
,
ma_uint32
sampleRateOut
,
ma_src_algorithm
algorithm
)
{
ma_assert
(
pBaseData
!=
NULL
);
// Make sure the base data is back at the start.
pBaseData
->
iNextFrame
=
0
;
src_reference_data
referenceData
;
ma_zero_object
(
&
referenceData
);
referenceData
.
channels
=
pBaseData
->
channels
;
// The first thing to do is to perform a sample rate conversion using the scalar/reference implementation. This reference is used to compare
// the results of the optimized implementation.
referenceData
.
frameCount
=
ma_calculate_frame_count_after_src
(
sampleRateOut
,
sampleRateIn
,
pBaseData
->
frameCount
);
if
(
referenceData
.
frameCount
==
0
)
{
printf
(
"Failed to calculate output frame count.
\n
"
);
return
-
1
;
}
ma_uint64
sz
=
referenceData
.
frameCount
*
sizeof
(
float
);
ma_assert
(
sz
<=
SIZE_MAX
);
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
referenceData
.
channels
;
iChannel
+=
1
)
{
referenceData
.
pFrameData
[
iChannel
]
=
(
float
*
)
ma_aligned_malloc
((
size_t
)
sz
,
MA_SIMD_ALIGNMENT
);
if
(
referenceData
.
pFrameData
[
iChannel
]
==
NULL
)
{
printf
(
"Out of memory.
\n
"
);
return
-
2
;
}
ma_zero_memory
(
referenceData
.
pFrameData
[
iChannel
],
(
size_t
)
sz
);
}
// Generate the reference data.
ma_src
src
;
ma_result
result
=
init_src
(
pBaseData
,
sampleRateIn
,
sampleRateOut
,
algorithm
,
simd_mode_scalar
,
&
src
);
if
(
result
!=
MA_SUCCESS
)
{
return
(
int
)
result
;
}
ma_timer
timer
;
ma_timer_init
(
&
timer
);
double
startTime
=
ma_timer_get_time_in_seconds
(
&
timer
);
{
ma_src_read_deinterleaved
(
&
src
,
referenceData
.
frameCount
,
(
void
**
)
referenceData
.
pFrameData
,
pBaseData
);
}
referenceData
.
timeTaken
=
ma_timer_get_time_in_seconds
(
&
timer
)
-
startTime
;
// Now that we have the reference data to compare against we can go ahead and measure the SIMD optimizations.
do_profiling__src__profile_individual
(
pBaseData
,
sampleRateIn
,
sampleRateOut
,
algorithm
,
simd_mode_scalar
,
&
referenceData
);
if
(
ma_has_sse2
())
{
do_profiling__src__profile_individual
(
pBaseData
,
sampleRateIn
,
sampleRateOut
,
algorithm
,
simd_mode_sse2
,
&
referenceData
);
}
if
(
ma_has_avx2
())
{
do_profiling__src__profile_individual
(
pBaseData
,
sampleRateIn
,
sampleRateOut
,
algorithm
,
simd_mode_avx2
,
&
referenceData
);
}
if
(
ma_has_avx512f
())
{
do_profiling__src__profile_individual
(
pBaseData
,
sampleRateIn
,
sampleRateOut
,
algorithm
,
simd_mode_avx512
,
&
referenceData
);
}
if
(
ma_has_neon
())
{
do_profiling__src__profile_individual
(
pBaseData
,
sampleRateIn
,
sampleRateOut
,
algorithm
,
simd_mode_neon
,
&
referenceData
);
}
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
referenceData
.
channels
;
iChannel
+=
1
)
{
ma_aligned_free
(
referenceData
.
pFrameData
[
iChannel
]);
}
return
0
;
}
int
do_profiling__src
()
{
printf
(
"Sample Rate Conversion
\n
"
);
printf
(
"======================
\n
"
);
// Set up base data.
src_data
baseData
;
ma_zero_object
(
&
baseData
);
baseData
.
channels
=
8
;
baseData
.
frameCount
=
100000
;
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
baseData
.
channels
;
++
iChannel
)
{
baseData
.
pFrameData
[
iChannel
]
=
(
float
*
)
ma_aligned_malloc
((
size_t
)(
baseData
.
frameCount
*
sizeof
(
float
)),
MA_SIMD_ALIGNMENT
);
if
(
baseData
.
pFrameData
[
iChannel
]
==
NULL
)
{
printf
(
"Out of memory.
\n
"
);
return
-
1
;
}
ma_sine_wave
sineWave
;
ma_sine_wave_init
(
1
.
0
f
,
400
+
(
iChannel
*
50
),
48000
,
&
sineWave
);
ma_sine_wave_read_f32
(
&
sineWave
,
baseData
.
frameCount
,
baseData
.
pFrameData
[
iChannel
]);
}
// Upsampling.
do_profiling__src__profile_set
(
&
baseData
,
44100
,
48000
,
ma_src_algorithm_sinc
);
// Downsampling.
do_profiling__src__profile_set
(
&
baseData
,
48000
,
44100
,
ma_src_algorithm_sinc
);
for
(
ma_uint32
iChannel
=
0
;
iChannel
<
baseData
.
channels
;
iChannel
+=
1
)
{
ma_aligned_free
(
baseData
.
pFrameData
[
iChannel
]);
}
return
0
;
}
#if 0
// Converts two 4xf32 vectors to one 8xi16 vector with signed saturation.
__m128i drmath_vf32_to_vi16__sse2(__m128 f32_0, __m128 f32_1)
{
return _mm_packs_epi32(_mm_cvttps_epi32(f32_0), _mm_cvttps_epi32(f32_1));
}
__m256i drmath_vf32_to_vi16__avx(__m256 f32_0, __m256 f32_1)
{
__m256i i0 = _mm256_cvttps_epi32(f32_0);
__m256i i1 = _mm256_cvttps_epi32(f32_1);
__m256i p0 = _mm256_permute2x128_si256(i0, i1, 32);
__m256i p1 = _mm256_permute2x128_si256(i0, i1, 49);
__m256i r = _mm256_packs_epi32(p0, p1);
return r;
}
#endif
int
main
(
int
argc
,
char
**
argv
)
{
(
void
)
argc
;
(
void
)
argv
;
{
//__m128 f0 = _mm_set_ps(32780, 2, 1, 0);
//__m128 f1 = _mm_set_ps(-32780, 6, 5, 4);
//__m128i r = drmath_vf32_to_vi16__sse2(f0, f1);
//__m256 f0 = _mm256_set_ps(7, 6, 5, 4, 3, 2, 1, 0);
//__m256 f1 = _mm256_set_ps(15, 14, 13, 12, 11, 10, 9, 8);
//__m256i r = drmath_vf32_to_vi16__avx(f0, f1);
//
//int a = 5;
}
// Summary.
if
(
ma_has_sse2
())
{
printf
(
"Has SSE2: YES
\n
"
);
}
else
{
printf
(
"Has SSE2: NO
\n
"
);
}
if
(
ma_has_avx2
())
{
printf
(
"Has AVX2: YES
\n
"
);
}
else
{
printf
(
"Has AVX2: NO
\n
"
);
}
if
(
ma_has_avx512f
())
{
printf
(
"Has AVX-512F: YES
\n
"
);
}
else
{
printf
(
"Has AVX-512F: NO
\n
"
);
}
if
(
ma_has_neon
())
{
printf
(
"Has NEON: YES
\n
"
);
}
else
{
printf
(
"Has NEON: NO
\n
"
);
}
printf
(
"
\n
"
);
// Format conversion.
do_profiling__format_conversion
();
printf
(
"
\n\n
"
);
// Channel routing.
do_profiling__channel_routing
();
printf
(
"
\n\n
"
);
// Sample rate conversion.
do_profiling__src
();
printf
(
"
\n\n
"
);
printf
(
"Press any key to quit...
\n
"
);
getchar
();
return
0
;
}
\ No newline at end of file
tests/ma_resampling.c
deleted
100644 → 0
View file @
673dce19
#define MA_NO_SSE2
#define MA_NO_AVX2
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.h"
// There is a usage pattern for resampling that miniaudio does not properly support which is where the client continuously
// reads samples until ma_src_read() returns 0. The problem with this pattern is that is consumes the samples sitting
// in the window which are needed to compute the next samples in future calls to ma_src_read() (assuming the client
// has re-filled the resampler's input data).
/*
for (;;) {
fill_src_input_data(&src, someData);
float buffer[4096]
while ((framesRead = ma_src_read(&src, ...) != 0) {
do_something_with_resampled_data(buffer);
}
}
*/
// In the use case above, the very last samples that are read from ma_src_read() will not have future samples to draw
// from in order to calculate the correct interpolation factor which in turn results in crackling.
ma_uint32
sampleRateIn
=
0
;
ma_uint32
sampleRateOut
=
0
;
ma_sine_wave
sineWave
;
// <-- This is the source data.
ma_src
src
;
float
srcInput
[
1024
];
ma_uint32
srcNextSampleIndex
=
ma_countof
(
srcInput
);
void
reload_src_input
()
{
ma_sine_wave_read_f32
(
&
sineWave
,
ma_countof
(
srcInput
),
srcInput
);
srcNextSampleIndex
=
0
;
}
ma_uint32
on_src
(
ma_src
*
pSRC
,
ma_uint32
frameCount
,
void
**
ppSamplesOut
,
void
*
pUserData
)
{
ma_assert
(
pSRC
!=
NULL
);
ma_assert
(
pSRC
->
config
.
channels
==
1
);
(
void
)
pUserData
;
// Only read as much as is available in the input buffer. Do not reload the buffer here.
ma_uint32
framesAvailable
=
ma_countof
(
srcInput
)
-
srcNextSampleIndex
;
ma_uint32
framesToRead
=
frameCount
;
if
(
framesToRead
>
framesAvailable
)
{
framesToRead
=
framesAvailable
;
}
ma_copy_memory
(
ppSamplesOut
[
0
],
srcInput
+
srcNextSampleIndex
,
sizeof
(
float
)
*
framesToRead
);
srcNextSampleIndex
+=
framesToRead
;
return
framesToRead
;
}
void
on_send_to_device
(
ma_device
*
pDevice
,
void
*
pOutput
,
const
void
*
pInput
,
ma_uint32
frameCount
)
{
(
void
)
pDevice
;
(
void
)
pInput
;
ma_assert
(
pDevice
->
playback
.
format
==
ma_format_f32
);
ma_assert
(
pDevice
->
playback
.
channels
==
1
);
float
*
pFramesF32
=
(
float
*
)
pOutput
;
// To reproduce the case we are needing to test, we need to read from the SRC in a very specific way. We keep looping
// until we've read the requested frame count, however we have an inner loop that keeps running until ma_src_read()
// returns 0, in which case we need to reload the SRC's input data and keep going.
ma_uint32
totalFramesRead
=
0
;
while
(
totalFramesRead
<
frameCount
)
{
ma_uint32
framesRemaining
=
frameCount
-
totalFramesRead
;
ma_uint32
maxFramesToRead
=
128
;
ma_uint32
framesToRead
=
framesRemaining
;
if
(
framesToRead
>
maxFramesToRead
)
{
framesToRead
=
maxFramesToRead
;
}
ma_uint32
framesRead
=
(
ma_uint32
)
ma_src_read_deinterleaved
(
&
src
,
framesToRead
,
(
void
**
)
&
pFramesF32
,
NULL
);
if
(
framesRead
==
0
)
{
reload_src_input
();
}
totalFramesRead
+=
framesRead
;
pFramesF32
+=
framesRead
;
}
ma_assert
(
totalFramesRead
==
frameCount
);
}
int
main
(
int
argc
,
char
**
argv
)
{
(
void
)
argc
;
(
void
)
argv
;
ma_device_config
config
=
ma_device_config_init
(
ma_device_type_playback
);
config
.
playback
.
format
=
ma_format_f32
;
config
.
playback
.
channels
=
1
;
config
.
dataCallback
=
on_send_to_device
;
ma_device
device
;
ma_result
result
;
config
.
bufferSizeInFrames
=
8192
*
1
;
// We first play the sound the way it's meant to be played.
result
=
ma_device_init
(
NULL
,
&
config
,
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
return
-
1
;
}
// For this test, we need the sine wave to be a different format to the device.
sampleRateOut
=
device
.
sampleRate
;
sampleRateIn
=
(
sampleRateOut
==
44100
)
?
48000
:
44100
;
ma_sine_wave_init
(
0
.
2
,
400
,
sampleRateIn
,
&
sineWave
);
ma_src_config
srcConfig
=
ma_src_config_init
(
sampleRateIn
,
sampleRateOut
,
1
,
on_src
,
NULL
);
srcConfig
.
algorithm
=
ma_src_algorithm_sinc
;
srcConfig
.
neverConsumeEndOfInput
=
MA_TRUE
;
result
=
ma_src_init
(
&
srcConfig
,
&
src
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to create SRC.
\n
"
);
return
-
1
;
}
result
=
ma_device_start
(
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
return
-
2
;
}
printf
(
"Press Enter to quit...
\n
"
);
getchar
();
ma_device_uninit
(
&
device
);
return
0
;
}
tests/ma_stop.c
deleted
100644 → 0
View file @
673dce19
#include <stdio.h>
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.h"
ma_sine_wave
sineWave
;
ma_uint32
framesWritten
;
ma_event
stopEvent
;
ma_bool32
isInitialRun
=
MA_TRUE
;
void
on_stop
(
ma_device
*
pDevice
)
{
(
void
)
pDevice
;
printf
(
"STOPPED
\n
"
);
}
void
on_data
(
ma_device
*
pDevice
,
void
*
pOutput
,
const
void
*
pInput
,
ma_uint32
frameCount
)
{
(
void
)
pInput
;
/* Not used yet. */
/* Output exactly one second of data. Pad the end with silence. */
ma_uint32
framesRemaining
=
pDevice
->
sampleRate
-
framesWritten
;
ma_uint32
framesToProcess
=
frameCount
;
if
(
framesToProcess
>
framesRemaining
&&
isInitialRun
)
{
framesToProcess
=
framesRemaining
;
}
ma_sine_wave_read_f32_ex
(
&
sineWave
,
framesToProcess
,
pDevice
->
playback
.
channels
,
ma_stream_layout_interleaved
,
(
float
**
)
&
pOutput
);
if
(
isInitialRun
)
{
framesWritten
+=
framesToProcess
;
}
ma_assert
(
framesWritten
<=
pDevice
->
sampleRate
);
if
(
framesWritten
>=
pDevice
->
sampleRate
)
{
if
(
isInitialRun
)
{
printf
(
"STOPPING [AUDIO THREAD]...
\n
"
);
ma_event_signal
(
&
stopEvent
);
isInitialRun
=
MA_FALSE
;
}
}
}
int
main
(
int
argc
,
char
**
argv
)
{
ma_result
result
;
(
void
)
argc
;
(
void
)
argv
;
ma_backend
backend
=
ma_backend_wasapi
;
ma_sine_wave_init
(
0
.
25
,
400
,
44100
,
&
sineWave
);
ma_device_config
config
=
ma_device_config_init
(
ma_device_type_playback
);
config
.
playback
.
format
=
ma_format_f32
;
config
.
playback
.
channels
=
2
;
config
.
sampleRate
=
44100
;
config
.
dataCallback
=
on_data
;
config
.
stopCallback
=
on_stop
;
config
.
bufferSizeInFrames
=
16384
;
ma_device
device
;
result
=
ma_device_init_ex
(
&
backend
,
1
,
NULL
,
&
config
,
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to initialize device.
\n
"
);
return
result
;
}
result
=
ma_event_init
(
device
.
pContext
,
&
stopEvent
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to initialize stop event.
\n
"
);
return
result
;
}
ma_device_start
(
&
device
);
/* We wait for the stop event, stop the device, then ask the user to press any key to restart. This checks that the device can restart after stopping. */
ma_event_wait
(
&
stopEvent
);
printf
(
"STOPPING [MAIN THREAD]...
\n
"
);
ma_device_stop
(
&
device
);
printf
(
"Press Enter to restart...
\n
"
);
getchar
();
result
=
ma_device_start
(
&
device
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to restart the device.
\n
"
);
ma_device_uninit
(
&
device
);
return
-
1
;
}
printf
(
"Press Enter to quit...
\n
"
);
getchar
();
ma_device_uninit
(
&
device
);
return
0
;
}
\ No newline at end of file
tests/ma_webaudio_test_0.html
deleted
100644 → 0
View file @
673dce19
<html>
<head>
</head>
<body>
This is a test of the Web Audio API
<div
id=
"Error"
style=
"color:red"
>
</div>
<div><b>
Playback Devices
</b></div>
<div
id=
"PlaybackDevices"
>
[Playback Devices]
</div>
<div><b>
Capture Devices
</b></div>
<div
id=
"CaptureDevices"
>
[Capture Devices]
</div>
<button
id=
"btnStartPlayback"
>
Start Playback
</button>
<button
id=
"btnStopPlayback"
>
Stop Playback
</button>
<button
id=
"btnClosePlayback"
>
Close Playback
</button>
<br/>
<button
id=
"btnStartCapture"
>
Start Capture
</button>
<button
id=
"btnStopCapture"
>
Stop Capture
</button>
<button
id=
"btnCloseCapture"
>
Close Capture
</button>
<script>
var
runningTime
=
0.0
;
function
ma_enum_devices
(
deviceType
)
{
if
(
deviceType
!==
'
audiooutput
'
&&
deviceType
!==
'
audioinput
'
)
{
alert
(
"
Invalid device type:
"
+
deviceType
);
return
null
;
}
// Unfortunately the navigator.mediaDevices.enumerateDevices() API doesn't seem to be very well supported.
// 1) On Chrome and Opera the label is always an empty string
// 2) No devices are returned in Firefox.
//
// This is not a production quality solution right now. It's better to instead just assume default
// devices and output/input silence if they fail to open (if a microphone is not connected, for example).
var
promise
=
new
Promise
(
function
(
resolve
,
reject
)
{
var
devices
=
[];
navigator
.
mediaDevices
.
enumerateDevices
().
then
(
function
(
deviceInfos
)
{
for
(
var
i
=
0
;
i
<
deviceInfos
.
length
;
++
i
)
{
if
(
deviceInfos
[
i
].
kind
===
deviceType
)
{
devices
.
push
(
deviceInfos
[
i
]);
}
}
resolve
(
devices
);
}).
catch
(
function
(
error
)
{
reject
(
"
Failed to enumerate devices:
"
+
error
);
});
});
return
promise
;
}
function
ma_device_new
(
deviceType
,
deviceID
)
{
if
(
typeof
(
mal
)
===
'
undefined
'
)
{
return
null
;
// Context not initialized.
}
// For now only default devices are being used. The device ID needs to be null.
if
(
deviceID
!=
null
)
{
return
null
;
// Only default devices are currently supported.
}
if
(
deviceID
==
null
)
{
deviceID
=
""
;
}
var
bufferSizeInFrames
=
512
;
var
sampleRate
=
44100
;
var
channelCount
=
2
;
var
device
=
{};
device
.
webaudioContext
=
new
(
window
.
AudioContext
||
window
.
webkitAudioContext
)({
latencyHint
:
'
interactive
'
,
sampleRate
:
sampleRate
,
});
device
.
webaudioContext
.
suspend
();
// miniaudio always starts it's devices in a stopped state.
console
.
log
(
"
Sample Rate:
"
+
device
.
webaudioContext
.
sampleRate
);
device
.
intermediaryBufferSizeInBytes
=
channelCount
*
bufferSizeInFrames
*
4
;
//device.intermediaryBuffer = Module._malloc(device.intermediaryBufferSizeInBytes);
device
.
intermediaryBuffer
=
new
Float32Array
(
channelCount
*
bufferSizeInFrames
);
if
(
deviceType
==
'
audiooutput
'
)
{
device
.
playback
=
{};
device
.
playback
.
scriptNode
=
device
.
webaudioContext
.
createScriptProcessor
(
bufferSizeInFrames
,
channelCount
,
channelCount
);
device
.
playback
.
scriptNode
.
onaudioprocess
=
function
(
e
)
{
// TODO: Don't do anything if we don't have an intermediary buffer. This means the device
// was uninitialized.
// The buffer we give to the client needs to be interleaved. After the client callback has returned
// we deinterleave it.
var
requiredBufferLength
=
channelCount
*
e
.
outputBuffer
.
length
;
if
(
device
.
intermediaryBuffer
.
length
<
requiredBufferLength
)
{
device
.
intermediaryBuffer
=
new
Float32Array
(
requiredBufferLength
);
}
// Here is where we get the client to fill the buffer with audio data.
// TESTING: Output a sine wave to the speakers.
for
(
var
iFrame
=
0
;
iFrame
<
e
.
outputBuffer
.
length
;
++
iFrame
)
{
var
value
=
Math
.
sin
((
runningTime
+
(
iFrame
*
6.28318530717958647693
/
44100.0
))
*
400.0
)
*
0.25
;
for
(
var
iChannel
=
0
;
iChannel
<
channelCount
;
++
iChannel
)
{
device
.
intermediaryBuffer
[
iFrame
*
channelCount
+
iChannel
]
=
value
;
}
}
runningTime
+=
(
6.28318530717958647693
*
e
.
outputBuffer
.
length
)
/
44100.0
;
// At this point the intermediary buffer should be filled with data. We now need to deinterleave
// it and write it to the output buffer.
for
(
var
iChannel
=
0
;
iChannel
<
channelCount
;
++
iChannel
)
{
for
(
var
iFrame
=
0
;
iFrame
<
e
.
outputBuffer
.
length
;
++
iFrame
)
{
e
.
outputBuffer
.
getChannelData
(
iChannel
)[
iFrame
]
=
device
.
intermediaryBuffer
[
iFrame
*
channelCount
+
iChannel
];
}
}
};
device
.
playback
.
scriptNode
.
connect
(
device
.
webaudioContext
.
destination
);
}
else
if
(
deviceType
==
'
audioinput
'
)
{
device
.
capture
=
{};
navigator
.
mediaDevices
.
getUserMedia
({
audio
:
true
,
video
:
false
})
.
then
(
function
(
stream
)
{
// We need to use ScriptProcessorNode instead of MediaRecorder because we need raw PCM data
// rather than compressed data. Why is this not supported? Seriously...
//
// This way this works is that we connect the output of a MediaStreamSourceNode to the input
// of a ScriptProcessorNode. The ScriptProcessorNode is connected to the AudioContext
// destination, but instead of connecting the input to the output we just output silence.
device
.
capture
.
streamNode
=
device
.
webaudioContext
.
createMediaStreamSource
(
stream
);
device
.
capture
.
scriptNode
=
device
.
webaudioContext
.
createScriptProcessor
(
bufferSizeInFrames
,
channelCount
,
channelCount
);
device
.
capture
.
scriptNode
.
onaudioprocess
=
function
(
e
)
{
// The input buffer needs to be interleaved before sending to the client. We need to do
// this in an intermediary buffer.
var
requiredBufferLength
=
e
.
inputBuffer
.
numberOfChannels
*
e
.
inputBuffer
.
length
;
if
(
device
.
intermediaryBuffer
.
length
<
requiredBufferLength
)
{
device
.
intermediaryBuffer
=
new
Float32Array
(
requiredBufferLength
);
}
for
(
var
iFrame
=
0
;
iFrame
<
e
.
inputBuffer
.
length
;
++
iFrame
)
{
for
(
var
iChannel
=
0
;
iChannel
<
e
.
inputBuffer
.
numberOfChannels
;
++
iChannel
)
{
device
.
intermediaryBuffer
[
iFrame
*
e
.
inputBuffer
.
numberOfChannels
+
iChannel
]
=
e
.
inputBuffer
.
getChannelData
(
iChannel
)[
iFrame
];
}
}
// At this point the input data has been interleaved and can be passed on to the client.
// Always output silence.
for
(
var
iChannel
=
0
;
iChannel
<
e
.
outputBuffer
.
numberOfChannels
;
++
iChannel
)
{
e
.
outputBuffer
.
getChannelData
(
iChannel
).
fill
(
0.0
);
}
/*
// TESTING: Write to the interleaved data to the output buffers.
for (var iChannel = 0; iChannel < e.inputBuffer.numberOfChannels; ++iChannel) {
for (var iFrame = 0; iFrame < e.inputBuffer.length; ++iFrame) {
e.outputBuffer.getChannelData(iChannel)[iFrame] = device.intermediaryBuffer[iFrame*e.inputBuffer.numberOfChannels + iChannel];
}
}
*/
};
device
.
capture
.
streamNode
.
connect
(
device
.
capture
.
scriptNode
);
device
.
capture
.
scriptNode
.
connect
(
device
.
webaudioContext
.
destination
);
})
.
catch
(
function
(
error
)
{
// For now just do nothing, but later on we may want to periodically fire the callback with silence.
console
.
log
(
"
No Stream.
"
);
});
}
else
{
return
null
;
// Unknown device type.
}
return
device
;
}
function
ma_device_delete
(
device
)
{
Module
.
_free
(
device
.
intermediaryBuffer
);
}
function
ma_context_init
()
{
if
((
window
.
AudioContext
||
window
.
webkitAudioContext
)
===
undefined
)
{
return
0
;
// Web Audio not supported.
}
if
(
typeof
(
Float32Array
)
===
'
undefined
'
)
{
return
0
;
// Float32Array not supported.
}
if
(
typeof
(
mal
)
===
'
undefined
'
)
{
mal
=
{};
miniaudio
.
devices
=
[];
// Device cache for mapping devices to indexes for JavaScript/C interop.
// Returns the index of the device. Throws an exception on error.
miniaudio
.
track_device
=
function
(
device
)
{
// Try inserting into a free slot first.
for
(
var
iDevice
=
0
;
iDevice
<
miniaudio
.
devices
.
length
;
++
iDevice
)
{
if
(
miniaudio
.
devices
[
iDevice
]
==
null
)
{
miniaudio
.
devices
[
iDevice
]
=
device
;
return
iDevice
;
}
}
// Getting here means there is no empty slots in the array so we just push to the end.
miniaudio
.
devices
.
push
(
device
);
return
miniaudio
.
devices
.
length
-
1
;
};
miniaudio
.
untrack_device_by_index
=
function
(
deviceIndex
)
{
// We just set the device's slot to null. The slot will get reused in the next call to ma_track_device.
miniaudio
.
devices
[
iDevice
]
=
null
;
// Trim the array if possible.
while
(
miniaudio
.
devices
.
length
>
0
)
{
if
(
miniaudio
.
devices
[
miniaudio
.
devices
.
length
-
1
]
==
null
)
{
miniaudio
.
devices
.
pop
();
}
else
{
break
;
}
}
};
miniaudio
.
untrack_device
=
function
(
device
)
{
for
(
var
iDevice
=
0
;
iDevice
<
miniaudio
.
devices
.
length
;
++
iDevice
)
{
if
(
miniaudio
.
devices
[
iDevice
]
==
device
)
{
return
miniaudio
.
untrack_device_by_index
(
iDevice
);
}
}
};
miniaudio
.
get_device_by_index
=
function
(
deviceIndex
)
{
return
miniaudio
.
devices
[
deviceIndex
];
};
}
return
1
;
}
window
.
onload
=
function
()
{
if
(
ma_context_init
()
!=
1
)
{
alert
(
"
Failed to initialize context.
"
);
return
;
}
// Unfortunately this doesn't seem to work too well. See comment in ma_enum_devices().
ma_enum_devices
(
'
audiooutput
'
).
then
(
function
(
outputDevices
)
{
for
(
var
iDevice
=
0
;
iDevice
<
outputDevices
.
length
;
++
iDevice
)
{
console
.
log
(
"
Output Device:
"
,
JSON
.
stringify
(
outputDevices
[
iDevice
]));
}
}).
catch
(
function
(
error
)
{
console
.
log
(
"
Failed to retrieve output devices:
"
,
error
);
});
ma_enum_devices
(
'
audioinput
'
).
then
(
function
(
inputDevices
)
{
for
(
var
iDevice
=
0
;
iDevice
<
inputDevices
.
length
;
++
iDevice
)
{
console
.
log
(
"
Input Device:
"
,
JSON
.
stringify
(
inputDevices
[
iDevice
]));
}
}).
catch
(
function
(
error
)
{
console
.
log
(
"
Failed to retrieve input devices:
"
,
error
);
});
var
outputDevice
=
ma_device_new
(
'
audiooutput
'
,
null
);
var
inputDevice
=
ma_device_new
(
'
audioinput
'
,
null
);
var
btnStartPlayback
=
document
.
getElementById
(
"
btnStartPlayback
"
);
btnStartPlayback
.
addEventListener
(
'
click
'
,
function
()
{
outputDevice
.
webaudioContext
.
resume
();
});
var
btnStopPlayback
=
document
.
getElementById
(
"
btnStopPlayback
"
);
btnStopPlayback
.
addEventListener
(
'
click
'
,
function
()
{
outputDevice
.
webaudioContext
.
suspend
();
});
var
btnClosePlayback
=
document
.
getElementById
(
"
btnClosePlayback
"
);
btnClosePlayback
.
addEventListener
(
'
click
'
,
function
()
{
outputDevice
.
webaudioContext
.
close
();
});
var
btnStartCapture
=
document
.
getElementById
(
"
btnStartCapture
"
);
btnStartCapture
.
addEventListener
(
'
click
'
,
function
()
{
inputDevice
.
webaudioContext
.
resume
();
});
var
btnStopCapture
=
document
.
getElementById
(
"
btnStopCapture
"
);
btnStopCapture
.
addEventListener
(
'
click
'
,
function
()
{
inputDevice
.
webaudioContext
.
suspend
();
});
var
btnCloseCapture
=
document
.
getElementById
(
"
btnCloseCapture
"
);
btnCloseCapture
.
addEventListener
(
'
click
'
,
function
()
{
inputDevice
.
webaudioContext
.
close
();
});
}
</script>
</body>
</html>
\ No newline at end of file
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