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
98792cae
Commit
98792cae
authored
Oct 19, 2019
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Resampling testing.
parent
b69f3667
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
321 additions
and
11 deletions
+321
-11
research/ma_resampler.h
research/ma_resampler.h
+198
-0
research/tests/ma_resampler_test_0.c
research/tests/ma_resampler_test_0.c
+114
-2
tests/ma_test_0.vcxproj
tests/ma_test_0.vcxproj
+9
-9
No files found.
research/ma_resampler.h
View file @
98792cae
/* Resampling research. Public domain. */
#ifndef ma_resampler_h
#define ma_resampler_h
typedef
enum
{
ma_resample_algorithm_linear
=
0
,
/* Default. Fastest. */
ma_resample_algorithm_sinc
/* Slower. */
}
ma_resample_algorithm
;
/*
Simple high-level API for resampling 32-bit floating point samples.
Use ma_calculate_frame_count_after_src() to determine the required output buffer size.
*/
ma_result
ma_resample_f32
(
ma_resample_algorithm
algorithm
,
ma_uint32
sampleRateOut
,
ma_uint32
sampleRateIn
,
ma_uint64
sampleCountOut
,
float
*
pSamplesOut
,
ma_uint64
sampleCountIn
,
float
*
pSamplesIn
);
#endif
/* ma_resampler_h */
/*
Implementation
*/
#ifdef MINIAUDIO_IMPLEMENTATION
#ifndef MA_RESAMPLER_MIN_RATIO
#define MA_RESAMPLER_MIN_RATIO 0.02083333
#endif
#ifndef MA_RESAMPLER_MAX_RATIO
#define MA_RESAMPLER_MAX_RATIO 48.0
#endif
ma_result
ma_resample_f32__linear
(
ma_uint32
sampleRateOut
,
ma_uint32
sampleRateIn
,
ma_uint64
sampleCountOut
,
float
*
pSamplesOut
,
ma_uint64
sampleCountIn
,
float
*
pSamplesIn
)
{
double
ratio
=
(
double
)
sampleRateIn
/
(
double
)
sampleRateOut
;
double
timeIn
=
0
;
double
timeOut
=
0
;
/* Fast path if the sample rates are the same. */
if
(
sampleRateOut
==
sampleRateIn
)
{
MA_COPY_MEMORY
(
pSamplesOut
,
pSamplesIn
,
(
size_t
)
ma_min
(
sampleCountOut
,
sampleCountIn
)
*
sizeof
(
float
));
return
MA_SUCCESS
;
}
/* Do nothing if there's no input. */
if
(
sampleCountOut
==
0
||
sampleCountIn
==
0
)
{
return
MA_SUCCESS
;
}
/* The first output sample should always be the same as the input sample. */
pSamplesOut
[
0
]
=
pSamplesIn
[
0
];
timeIn
+=
ratio
;
timeOut
+=
1
;
for
(;;)
{
ma_uint64
iTimeIn
;
ma_uint64
iTimeOut
;
iTimeIn
=
(
ma_uint64
)
timeIn
;
if
(
iTimeIn
>=
sampleCountIn
)
{
break
;
}
iTimeOut
=
(
ma_uint64
)
timeOut
;
if
(
iTimeOut
>=
sampleCountOut
)
{
break
;
}
/* To linearly interpolate we need the previous and next input samples. */
{
ma_uint64
iTimeInPrev
=
iTimeIn
;
ma_uint64
iTimeInNext
=
(
ma_uint64
)
ceil
(
timeIn
);
if
(
iTimeInNext
>=
sampleCountIn
)
{
iTimeInNext
=
iTimeInPrev
;
/* <-- We could instead terminate here which would make the output a few samples shorter. */
}
pSamplesOut
[
iTimeOut
]
=
ma_mix_f32_fast
(
pSamplesIn
[
iTimeInPrev
],
pSamplesIn
[
iTimeInNext
],
(
float
)(
timeIn
-
iTimeIn
));
/* Try some kind of low-pass filter. */
#if 1
{
double
cutoff
=
ma_min
(
sampleRateIn
,
sampleRateOut
)
*
0
.
5
;
double
RC
=
1
.
0
/
(
cutoff
*
MA_TAU_D
);
double
dt
=
1
.
0
/
sampleRateOut
;
float
alpha
=
(
float
)(
dt
/
(
RC
+
dt
));
pSamplesOut
[
iTimeOut
]
=
pSamplesOut
[
iTimeOut
-
1
]
+
(
alpha
*
(
pSamplesOut
[
iTimeOut
]
-
pSamplesOut
[
iTimeOut
-
1
]));
}
#endif
}
timeIn
+=
ratio
;
timeOut
+=
1
;
}
return
MA_INVALID_ARGS
;
}
double
ma_sinc_hann
(
double
n
,
int
N
)
{
double
s
=
sin
(
MA_PI_D
*
n
/
N
);
return
s
*
s
;
}
ma_result
ma_resample_f32__sinc
(
ma_uint32
sampleRateOut
,
ma_uint32
sampleRateIn
,
ma_uint64
sampleCountOut
,
float
*
pSamplesOut
,
ma_uint64
sampleCountIn
,
float
*
pSamplesIn
)
{
double
ratio
=
(
double
)
sampleRateIn
/
(
double
)
sampleRateOut
;
double
timeIn
=
0
;
double
timeOut
=
0
;
double
samplingPeriodIn
=
1
.
0
/
sampleRateIn
;
int
windowWidth
=
32
;
/* Fast path if the sample rates are the same. */
if
(
sampleRateOut
==
sampleRateIn
)
{
MA_COPY_MEMORY
(
pSamplesOut
,
pSamplesIn
,
(
size_t
)
ma_min
(
sampleCountOut
,
sampleCountIn
)
*
sizeof
(
float
));
return
MA_SUCCESS
;
}
/* Do nothing if there's no input. */
if
(
sampleCountOut
==
0
||
sampleCountIn
==
0
)
{
return
MA_SUCCESS
;
}
/* The first output sample should always be the same as the input sample. */
pSamplesOut
[
0
]
=
pSamplesIn
[
0
];
timeIn
+=
ratio
;
timeOut
+=
1
;
for
(;;)
{
ma_uint64
iTimeIn
;
ma_uint64
iTimeOut
;
iTimeIn
=
(
ma_uint64
)
timeIn
;
if
(
iTimeIn
>=
sampleCountIn
)
{
break
;
}
iTimeOut
=
(
ma_uint64
)
timeOut
;
if
(
iTimeOut
>=
sampleCountOut
)
{
break
;
}
/* To linearly interpolate we need the previous and next input samples. */
{
ma_uint64
iTimeInPrev
=
iTimeIn
;
ma_uint64
iTimeInNext
=
(
ma_uint64
)
ceil
(
timeIn
);
if
(
iTimeInNext
>=
sampleCountIn
)
{
iTimeInNext
=
iTimeInPrev
;
/* <-- We could instead terminate here which would make the output a few samples shorter. */
}
#if 0
pSamplesOut[iTimeOut] = ma_mix_f32_fast(pSamplesIn[iTimeInPrev], pSamplesIn[iTimeInNext], (float)(timeIn - iTimeIn));
#else
pSamplesOut
[
iTimeOut
]
=
0
;
for
(
int
i
=
-
windowWidth
;
i
<
windowWidth
;
i
+=
1
)
{
if
((
i
<
0
&&
-
i
<
iTimeIn
)
||
i
>
0
&&
i
<
sampleCountIn
)
{
#if 0
double t = (iTimeIn+n);
double s = ma_sinc(sampleRateIn*t);
pSamplesOut[iTimeOut] += pSamplesIn[(ma_uint64)(iTimeIn+n)] * s;
#endif
}
}
#endif
}
timeIn
+=
ratio
;
timeOut
+=
1
;
}
return
MA_INVALID_ARGS
;
}
ma_result
ma_resample_f32
(
ma_resample_algorithm
algorithm
,
ma_uint32
sampleRateOut
,
ma_uint32
sampleRateIn
,
ma_uint64
sampleCountOut
,
float
*
pSamplesOut
,
ma_uint64
sampleCountIn
,
float
*
pSamplesIn
)
{
if
(
pSamplesOut
==
NULL
||
pSamplesIn
==
NULL
)
{
return
MA_INVALID_ARGS
;
}
switch
(
algorithm
)
{
case
ma_resample_algorithm_linear
:
return
ma_resample_f32__linear
(
sampleRateOut
,
sampleRateIn
,
sampleCountOut
,
pSamplesOut
,
sampleCountIn
,
pSamplesIn
);
case
ma_resample_algorithm_sinc
:
return
ma_resample_f32__sinc
(
sampleRateOut
,
sampleRateIn
,
sampleCountOut
,
pSamplesOut
,
sampleCountIn
,
pSamplesIn
);
default:
return
MA_INVALID_ARGS
;
}
}
#endif
/* MINIAUDIO_IMPLEMENTATION */
#if 0
/*
/*
Consider this code public domain.
Consider this code public domain.
...
@@ -1204,3 +1401,4 @@ ma_uint64 ma_resampler_seek__sinc(ma_resampler* pResampler, ma_uint64 frameCount
...
@@ -1204,3 +1401,4 @@ ma_uint64 ma_resampler_seek__sinc(ma_resampler* pResampler, ma_uint64 frameCount
}
}
#endif
#endif
#endif /* 0 (Old Implementation)*/
\ No newline at end of file
research/tests/ma_resampler_test_0.c
View file @
98792cae
#define DR_FLAC_IMPLEMENTATION
#include "../../extras/dr_flac.h"
/* Enables FLAC decoding. */
#define DR_MP3_IMPLEMENTATION
#include "../../extras/dr_mp3.h"
/* Enables MP3 decoding. */
#define DR_WAV_IMPLEMENTATION
#define DR_WAV_IMPLEMENTATION
#include "../../../../dr_libs/dr_wav.h"
#include "../../extras/dr_wav.h"
/* Enables WAV decoding. */
#define MA_DEBUG_OUTPUT
#define MA_DEBUG_OUTPUT
#define MINIAUDIO_IMPLEMENTATION
#define MINIAUDIO_IMPLEMENTATION
#include "../../miniaudio.h"
#include "../../miniaudio.h"
#include "../ma_resampler.h"
#include "../ma_resampler.h"
#define USE_NEW_RESAMPLER 1
ma_uint64
g_outputFrameCount
;
void
*
g_pRunningFrameData
;
void
data_callback
(
ma_device
*
pDevice
,
void
*
pOutput
,
const
void
*
pInput
,
ma_uint32
frameCount
)
{
ma_uint32
framesToCopy
;
framesToCopy
=
frameCount
;
if
(
framesToCopy
>
(
ma_uint32
)
g_outputFrameCount
)
{
framesToCopy
=
(
ma_uint32
)
g_outputFrameCount
;
}
MA_COPY_MEMORY
(
pOutput
,
g_pRunningFrameData
,
framesToCopy
*
ma_get_bytes_per_frame
(
pDevice
->
playback
.
format
,
pDevice
->
playback
.
channels
));
g_pRunningFrameData
=
ma_offset_ptr
(
g_pRunningFrameData
,
framesToCopy
*
ma_get_bytes_per_frame
(
pDevice
->
playback
.
format
,
pDevice
->
playback
.
channels
));
g_outputFrameCount
-=
framesToCopy
;
(
void
)
pInput
;
}
int
main
(
int
argc
,
char
**
argv
)
{
ma_result
result
;
ma_decoder_config
decoderConfig
;
ma_uint64
inputFrameCount
;
void
*
pInputFrameData
;
ma_uint64
outputFrameCount
=
0
;
void
*
pOutputFrameData
=
NULL
;
ma_device_config
deviceConfig
;
ma_device
device
;
ma_backend
backend
;
/* This example just resamples the input file to an exclusive device's native sample rate. */
if
(
argc
<
2
)
{
printf
(
"No input file.
\n
"
);
return
-
1
;
}
decoderConfig
=
ma_decoder_config_init
(
ma_format_f32
,
1
,
0
);
result
=
ma_decode_file
(
argv
[
1
],
&
decoderConfig
,
&
inputFrameCount
,
&
pInputFrameData
);
if
(
result
!=
MA_SUCCESS
)
{
return
(
int
)
result
;
}
backend
=
ma_backend_wasapi
;
deviceConfig
=
ma_device_config_init
(
ma_device_type_playback
);
#if USE_NEW_RESAMPLER
deviceConfig
.
playback
.
shareMode
=
ma_share_mode_exclusive
;
/* <-- We need to use exclusive mode to ensure there's no resampling going on by the OS. */
deviceConfig
.
sampleRate
=
0
;
/* <-- Always use the device's native sample rate. */
#else
deviceConfig
.
playback
.
shareMode
=
ma_share_mode_shared
;
/* <-- We need to use exclusive mode to ensure there's no resampling going on by the OS. */
deviceConfig
.
sampleRate
=
decoderConfig
.
sampleRate
;
#endif
deviceConfig
.
playback
.
format
=
decoderConfig
.
format
;
deviceConfig
.
playback
.
channels
=
decoderConfig
.
channels
;
deviceConfig
.
dataCallback
=
data_callback
;
deviceConfig
.
pUserData
=
NULL
;
if
(
ma_device_init
(
NULL
,
&
deviceConfig
,
&
device
)
!=
MA_SUCCESS
)
{
printf
(
"Failed to open playback device.
\n
"
);
ma_free
(
pInputFrameData
);
return
-
3
;
}
#if USE_NEW_RESAMPLER
/* Resample. */
outputFrameCount
=
ma_calculate_frame_count_after_src
(
device
.
sampleRate
,
decoderConfig
.
sampleRate
,
inputFrameCount
);
pOutputFrameData
=
ma_malloc
((
size_t
)(
outputFrameCount
*
ma_get_bytes_per_frame
(
device
.
playback
.
format
,
device
.
playback
.
channels
)));
if
(
pOutputFrameData
==
NULL
)
{
printf
(
"Out of memory.
\n
"
);
ma_free
(
pInputFrameData
);
ma_device_uninit
(
&
device
);
}
ma_resample_f32
(
ma_resample_algorithm_sinc
,
device
.
playback
.
internalSampleRate
,
decoderConfig
.
sampleRate
,
outputFrameCount
,
pOutputFrameData
,
inputFrameCount
,
pInputFrameData
);
g_pRunningFrameData
=
pOutputFrameData
;
g_outputFrameCount
=
outputFrameCount
;
#else
g_pRunningFrameData
=
pInputFrameData
;
g_outputFrameCount
=
inputFrameCount
;
#endif
if
(
ma_device_start
(
&
device
)
!=
MA_SUCCESS
)
{
printf
(
"Failed to start playback device.
\n
"
);
ma_device_uninit
(
&
device
);
ma_free
(
pInputFrameData
);
ma_free
(
pOutputFrameData
);
return
-
4
;
}
printf
(
"Press Enter to quit..."
);
getchar
();
ma_device_uninit
(
&
device
);
ma_free
(
pInputFrameData
);
ma_free
(
pOutputFrameData
);
return
0
;
}
#if 0
#define SAMPLE_RATE_IN 44100
#define SAMPLE_RATE_IN 44100
#define SAMPLE_RATE_OUT 44100
#define SAMPLE_RATE_OUT 44100
#define CHANNELS 1
#define CHANNELS 1
...
@@ -71,4 +182,5 @@ int main(int argc, char** argv)
...
@@ -71,4 +182,5 @@ int main(int argc, char** argv)
(void)argc;
(void)argc;
(void)argv;
(void)argv;
return 0;
return 0;
}
}
\ No newline at end of file
#endif
tests/ma_test_0.vcxproj
View file @
98792cae
...
@@ -319,14 +319,6 @@
...
@@ -319,14 +319,6 @@
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|x64'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|x64'"
>
true
</ExcludedFromBuild>
</ClCompile>
</ClCompile>
<ClCompile
Include=
"..\examples\simple_playback.c"
>
<ClCompile
Include=
"..\examples\simple_playback.c"
>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
>
false
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
>
false
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|ARM'"
>
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>
</ClCompile>
<ClCompile
Include=
"..\examples\simple_playback_emscripten.c"
>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|ARM'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|ARM'"
>
true
</ExcludedFromBuild>
...
@@ -334,7 +326,7 @@
...
@@ -334,7 +326,7 @@
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|x64'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|x64'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|x64'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|x64'"
>
true
</ExcludedFromBuild>
</ClCompile>
</ClCompile>
<ClCompile
Include=
"..\
research\tests\ma_resampler_test_0
.c"
>
<ClCompile
Include=
"..\
examples\simple_playback_emscripten
.c"
>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|ARM'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|ARM'"
>
true
</ExcludedFromBuild>
...
@@ -342,6 +334,14 @@
...
@@ -342,6 +334,14 @@
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|x64'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|x64'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|x64'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|x64'"
>
true
</ExcludedFromBuild>
</ClCompile>
</ClCompile>
<ClCompile
Include=
"..\research\tests\ma_resampler_test_0.c"
>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
>
false
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
>
false
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|ARM'"
>
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>
</ClCompile>
<ClCompile
Include=
"ma_dithering.c"
>
<ClCompile
Include=
"ma_dithering.c"
>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
>
true
</ExcludedFromBuild>
<ExcludedFromBuild
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
>
true
</ExcludedFromBuild>
...
...
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