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
705e54c6
Commit
705e54c6
authored
Jan 18, 2020
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for s16 format to the linear resampler.
parent
1449edf4
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
107 additions
and
150 deletions
+107
-150
miniaudio.h
miniaudio.h
+12
-0
research/ma_lpf.h
research/ma_lpf.h
+3
-3
research/ma_resampler.h
research/ma_resampler.h
+92
-147
No files found.
miniaudio.h
View file @
705e54c6
...
@@ -4278,6 +4278,18 @@ static MA_INLINE float ma_mix_f32_fast(float x, float y, float a)
...
@@ -4278,6 +4278,18 @@ static MA_INLINE float ma_mix_f32_fast(float x, float y, float a)
/*return x + (y - x)*a;*/
/*return x + (y - x)*a;*/
}
}
static MA_INLINE ma_int32 ma_mix_s32_fast(ma_int32 x, ma_int32 y, float a)
{
ma_int32 r0 = (y - x);
ma_int32 r1 = (ma_int32)(r0*a);
return x + r1;
}
static MA_INLINE ma_int32 ma_mix_s16_fast(ma_int32 x, ma_int32 y, float a)
{
return (ma_int16)ma_mix_s32_fast(x, y, a);
}
#if defined(MA_SUPPORT_SSE2)
#if defined(MA_SUPPORT_SSE2)
static MA_INLINE __m128 ma_mix_f32_fast__sse2(__m128 x, __m128 y, __m128 a)
static MA_INLINE __m128 ma_mix_f32_fast__sse2(__m128 x, __m128 y, __m128 a)
{
{
research/ma_lpf.h
View file @
705e54c6
...
@@ -119,8 +119,8 @@ ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ)
...
@@ -119,8 +119,8 @@ ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ)
return
MA_INVALID_ARGS
;
/* Division by zero. */
return
MA_INVALID_ARGS
;
/* Division by zero. */
}
}
/* Currently only supporting f32, but support for other formats will be added later. */
/* Currently only supporting f32
and s16
, but support for other formats will be added later. */
if
(
pConfig
->
format
!=
ma_format_f32
)
{
if
(
pConfig
->
format
!=
ma_format_f32
&&
pConfig
->
format
!=
ma_format_s16
)
{
return
MA_INVALID_ARGS
;
return
MA_INVALID_ARGS
;
}
}
...
...
research/ma_resampler.h
View file @
705e54c6
...
@@ -45,8 +45,16 @@ typedef struct
...
@@ -45,8 +45,16 @@ typedef struct
struct
struct
{
{
float
t
;
/* Input time, relative to x0. */
float
t
;
/* Input time, relative to x0. */
float
x0
[
MA_MAX_CHANNELS
];
/* The previous input frame. */
union
float
x1
[
MA_MAX_CHANNELS
];
/* The next input frame. */
{
float
f32
[
MA_MAX_CHANNELS
];
ma_int16
s16
[
MA_MAX_CHANNELS
];
}
x0
;
/* The previous input frame. */
union
{
float
f32
[
MA_MAX_CHANNELS
];
ma_int16
s16
[
MA_MAX_CHANNELS
];
}
x1
;
/* The next input frame. */
ma_lpf
lpf
;
ma_lpf
lpf
;
}
linear
;
}
linear
;
void
*
pSpeex
;
/* SpeexResamplerState* */
void
*
pSpeex
;
/* SpeexResamplerState* */
...
@@ -80,14 +88,6 @@ It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL.
...
@@ -80,14 +88,6 @@ It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL.
*/
*/
ma_result
ma_resampler_process
(
ma_resampler
*
pResampler
,
void
*
pFramesOut
,
ma_uint64
*
pFrameCountOut
,
const
void
*
pFramesIn
,
ma_uint64
*
pFrameCountIn
);
ma_result
ma_resampler_process
(
ma_resampler
*
pResampler
,
void
*
pFramesOut
,
ma_uint64
*
pFrameCountOut
,
const
void
*
pFramesIn
,
ma_uint64
*
pFrameCountIn
);
/*
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 */
#endif
/* ma_resampler_h */
/*
/*
...
@@ -176,7 +176,7 @@ ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pR
...
@@ -176,7 +176,7 @@ ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pR
}
}
#else
#else
/* Speex resampler not available. */
/* Speex resampler not available. */
return
MA_
INVALID_ARGS
;
return
MA_
NO_BACKEND
;
#endif
#endif
}
break
;
}
break
;
...
@@ -237,7 +237,6 @@ static ma_result ma_resampler_process__seek(ma_resampler* pResampler, ma_uint64*
...
@@ -237,7 +237,6 @@ static ma_result ma_resampler_process__seek(ma_resampler* pResampler, ma_uint64*
}
}
}
}
static
ma_result
ma_resampler_process__read__linear
(
ma_resampler
*
pResampler
,
void
*
pFramesOut
,
ma_uint64
*
pFrameCountOut
,
const
void
*
pFramesIn
,
ma_uint64
*
pFrameCountIn
)
static
ma_result
ma_resampler_process__read__linear
(
ma_resampler
*
pResampler
,
void
*
pFramesOut
,
ma_uint64
*
pFrameCountOut
,
const
void
*
pFramesIn
,
ma_uint64
*
pFrameCountIn
)
{
{
ma_uint64
frameCountOut
;
ma_uint64
frameCountOut
;
...
@@ -247,6 +246,12 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
...
@@ -247,6 +246,12 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
ma_uint64
iChannel
;
ma_uint64
iChannel
;
float
ratioInOut
;
float
ratioInOut
;
/* */
float
*
pYF32
=
(
float
*
)
pFramesOut
;
const
float
*
pXF32
=
(
const
float
*
)
pFramesIn
;
/* */
ma_int16
*
pYS16
=
(
ma_int16
*
)
pFramesOut
;
const
ma_int16
*
pXS16
=
(
const
ma_int16
*
)
pFramesIn
;
MA_ASSERT
(
pResampler
!=
NULL
);
MA_ASSERT
(
pResampler
!=
NULL
);
MA_ASSERT
(
pFramesOut
!=
NULL
);
MA_ASSERT
(
pFramesOut
!=
NULL
);
MA_ASSERT
(
pFrameCountOut
!=
NULL
);
MA_ASSERT
(
pFrameCountOut
!=
NULL
);
...
@@ -265,10 +270,6 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
...
@@ -265,10 +270,6 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
iFrameOut
=
0
;
iFrameOut
=
0
;
iFrameIn
=
0
;
iFrameIn
=
0
;
if
(
pResampler
->
config
.
format
==
ma_format_f32
)
{
float
*
pY
=
(
float
*
)
pFramesOut
;
const
float
*
pX
=
(
const
float
*
)
pFramesIn
;
/*
/*
We need to do an initial load of input data so that the first output frame is the same as the input frame. We can know whether or not to do this by
We need to do an initial load of input data so that the first output frame is the same as the input frame. We can know whether or not to do this by
checking whether or not the current time is < 0 (it will be initialized to -1).
checking whether or not the current time is < 0 (it will be initialized to -1).
...
@@ -276,7 +277,11 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
...
@@ -276,7 +277,11 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
if
(
pResampler
->
state
.
linear
.
t
<
0
)
{
if
(
pResampler
->
state
.
linear
.
t
<
0
)
{
if
(
frameCountIn
>
0
)
{
if
(
frameCountIn
>
0
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pResampler
->
state
.
linear
.
x1
[
iChannel
]
=
pX
[
iChannel
];
if
(
pResampler
->
config
.
format
==
ma_format_f32
)
{
pResampler
->
state
.
linear
.
x1
.
f32
[
iChannel
]
=
pXF32
[
iChannel
];
}
else
{
pResampler
->
state
.
linear
.
x1
.
s16
[
iChannel
]
=
pXS16
[
iChannel
];
}
}
}
iFrameIn
+=
1
;
iFrameIn
+=
1
;
...
@@ -297,9 +302,16 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
...
@@ -297,9 +302,16 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
/* We have enough input frames remaining to bring the time down to 0..1. */
/* We have enough input frames remaining to bring the time down to 0..1. */
MA_ASSERT
(
iFrameIn
>
0
);
MA_ASSERT
(
iFrameIn
>
0
);
if
(
pResampler
->
config
.
format
==
ma_format_f32
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pResampler
->
state
.
linear
.
x0
.
f32
[
iChannel
]
=
pXF32
[(
iFrameIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x1
.
f32
[
iChannel
]
=
pXF32
[(
iFrameIn
-
0
)
*
pResampler
->
config
.
channels
+
iChannel
];
}
}
else
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pResampler
->
state
.
linear
.
x0
[
iChannel
]
=
pX
[(
iFrameIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x0
.
s16
[
iChannel
]
=
pXS16
[(
iFrameIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x1
[
iChannel
]
=
pX
[(
iFrameIn
-
0
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x1
.
s16
[
iChannel
]
=
pXS16
[(
iFrameIn
-
0
)
*
pResampler
->
config
.
channels
+
iChannel
];
}
}
}
/* The time should always be relative to x0, and should not be greater than 1. */
/* The time should always be relative to x0, and should not be greater than 1. */
...
@@ -307,15 +319,29 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
...
@@ -307,15 +319,29 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
MA_ASSERT
(
pResampler
->
state
.
linear
.
t
>=
0
&&
pResampler
->
state
.
linear
.
t
<=
1
);
MA_ASSERT
(
pResampler
->
state
.
linear
.
t
>=
0
&&
pResampler
->
state
.
linear
.
t
<=
1
);
}
else
{
}
else
{
/* Ran out of input frames. Make sure we consume the rest of the input frames by adjusting our input time appropriately. */
/* Ran out of input frames. Make sure we consume the rest of the input frames by adjusting our input time appropriately. */
if
(
pResampler
->
config
.
format
==
ma_format_f32
)
{
if
(
frameCountIn
>
1
)
{
if
(
frameCountIn
>
1
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pResampler
->
state
.
linear
.
x0
[
iChannel
]
=
pX
[(
frameCountIn
-
2
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x0
.
f32
[
iChannel
]
=
pXF32
[(
frameCountIn
-
2
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x1
[
iChannel
]
=
pX
[(
frameCountIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x1
.
f32
[
iChannel
]
=
pXF32
[(
frameCountIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
}
}
}
else
{
}
else
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pResampler
->
state
.
linear
.
x0
[
iChannel
]
=
pResampler
->
state
.
linear
.
x1
[
iChannel
];
pResampler
->
state
.
linear
.
x0
.
f32
[
iChannel
]
=
pResampler
->
state
.
linear
.
x1
.
f32
[
iChannel
];
pResampler
->
state
.
linear
.
x1
[
iChannel
]
=
pX
[(
frameCountIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x1
.
f32
[
iChannel
]
=
pXF32
[(
frameCountIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
}
}
}
else
{
if
(
frameCountIn
>
1
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pResampler
->
state
.
linear
.
x0
.
s16
[
iChannel
]
=
pXS16
[(
frameCountIn
-
2
)
*
pResampler
->
config
.
channels
+
iChannel
];
pResampler
->
state
.
linear
.
x1
.
s16
[
iChannel
]
=
pXS16
[(
frameCountIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
}
}
else
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pResampler
->
state
.
linear
.
x0
.
s16
[
iChannel
]
=
pResampler
->
state
.
linear
.
x1
.
s16
[
iChannel
];
pResampler
->
state
.
linear
.
x1
.
s16
[
iChannel
]
=
pXS16
[(
frameCountIn
-
1
)
*
pResampler
->
config
.
channels
+
iChannel
];
}
}
}
}
}
...
@@ -326,8 +352,14 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
...
@@ -326,8 +352,14 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
}
}
}
}
if
(
pResampler
->
config
.
format
==
ma_format_f32
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pY
[
iFrameOut
*
pResampler
->
config
.
channels
+
iChannel
]
=
ma_mix_f32_fast
(
pResampler
->
state
.
linear
.
x0
[
iChannel
],
pResampler
->
state
.
linear
.
x1
[
iChannel
],
pResampler
->
state
.
linear
.
t
);
pYF32
[
iFrameOut
*
pResampler
->
config
.
channels
+
iChannel
]
=
ma_mix_f32_fast
(
pResampler
->
state
.
linear
.
x0
.
f32
[
iChannel
],
pResampler
->
state
.
linear
.
x1
.
f32
[
iChannel
],
pResampler
->
state
.
linear
.
t
);
}
}
else
{
for
(
iChannel
=
0
;
iChannel
<
pResampler
->
config
.
channels
;
iChannel
+=
1
)
{
pYS16
[
iFrameOut
*
pResampler
->
config
.
channels
+
iChannel
]
=
ma_mix_s16_fast
(
pResampler
->
state
.
linear
.
x0
.
s16
[
iChannel
],
pResampler
->
state
.
linear
.
x1
.
s16
[
iChannel
],
pResampler
->
state
.
linear
.
t
);
}
}
}
/* Move time forward. */
/* Move time forward. */
...
@@ -338,10 +370,6 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
...
@@ -338,10 +370,6 @@ static ma_result ma_resampler_process__read__linear(ma_resampler* pResampler, vo
/* Here is where we set the number of frames that were consumed. */
/* Here is where we set the number of frames that were consumed. */
*
pFrameCountOut
=
iFrameOut
;
*
pFrameCountOut
=
iFrameOut
;
*
pFrameCountIn
=
iFrameIn
;
*
pFrameCountIn
=
iFrameIn
;
}
else
{
/* Format not supported. */
return
MA_INVALID_OPERATION
;
}
return
MA_SUCCESS
;
return
MA_SUCCESS
;
}
}
...
@@ -488,89 +516,6 @@ ma_result ma_resampler_process(ma_resampler* pResampler, void* pFramesOut, ma_ui
...
@@ -488,89 +516,6 @@ ma_result ma_resampler_process(ma_resampler* pResampler, void* pFramesOut, ma_ui
return
ma_resampler_process__seek
(
pResampler
,
pFrameCountOut
,
pFramesIn
,
pFrameCountIn
);
return
ma_resampler_process__seek
(
pResampler
,
pFrameCountOut
,
pFramesIn
,
pFrameCountIn
);
}
}
}
}
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
;
}
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
);
default:
return
MA_INVALID_ARGS
;
}
}
#endif
/* MINIAUDIO_IMPLEMENTATION */
#endif
/* MINIAUDIO_IMPLEMENTATION */
...
...
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