Skip to content

Commit a5b4d0d

Browse files
committed
refactor: sound resample utils (partial)
1 parent 6abb1e9 commit a5b4d0d

File tree

6 files changed

+102
-34
lines changed

6 files changed

+102
-34
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "components/acoustics/3rdparty/opus"]
22
path = components/acoustics/3rdparty/opus
33
url = https://github.com/xiph/opus
4+
[submodule "components/acoustics/3rdparty/libsamplerate"]
5+
path = components/acoustics/3rdparty/libsamplerate
6+
url = https://github.com/libsndfile/libsamplerate

components/acoustics-porting/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,28 @@ set(ACOUSTICS_PRIV_REQUIRES
111111
littlefs
112112
)
113113

114+
if(NOT DEFINED ACOUSTICS_LIB_LIBSAMPLERATE_ENABLE)
115+
set(LIB_LIBSAMPLERATE_ENABLE 0)
116+
message(STATUS "SRC (aka libsamplerate) support is disabled by default")
117+
else()
118+
message(STATUS "SRC (aka libsamplerate) support is set to: ${ACOUSTICS_LIB_LIBSAMPLERATE_ENABLE}")
119+
if(ACOUSTICS_LIB_LIBSAMPLERATE_ENABLE STREQUAL "1" OR ACOUSTICS_LIB_LIBSAMPLERATE_ENABLE STREQUAL "ON")
120+
set(LIB_LIBSAMPLERATE_DIR ${CMAKE_CURRENT_LIST_DIR}/../acoustics/3rdparty/libsamplerate)
121+
file(GLOB_RECURSE LIB_LIBSAMPLERATE_SRCS
122+
${LIB_LIBSAMPLERATE_DIR}/src/*.c
123+
${LIB_LIBSAMPLERATE_DIR}/src/*.h
124+
)
125+
list(APPEND ACOUSTICS_PORTING_SRCS ${LIB_LIBSAMPLERATE_SRCS})
126+
list(APPEND ACOUSTICS_PORTING_INCLUDES_DIR ${LIB_LIBSAMPLERATE_DIR}/include)
127+
128+
set(LIB_LIBSAMPLERATE_ENABLE 1)
129+
message(STATUS "SRC (aka libsamplerate) support is enabled")
130+
else()
131+
set(LIB_LIBSAMPLERATE_ENABLE 0)
132+
message(STATUS "SRC (aka libsamplerate) support is disabled")
133+
endif()
134+
endif()
135+
114136
if(NOT DEFINED ACOUSTICS_LIB_OPUS_ENABLE)
115137
set(LIB_OPUS_ENABLE 0)
116138
message(STATUS "OPUS support is disabled by default")
@@ -206,6 +228,7 @@ target_compile_definitions(${COMPONENT_LIB} PUBLIC
206228
CORE_VERSION_MAJOR=${ACOUSTICS_SDK_VERSION_MAJOR}
207229
CORE_VERSION_MINOR=${ACOUSTICS_SDK_VERSION_MINOR}
208230
CORE_VERSION_PATCH=${ACOUSTICS_SDK_VERSION_PATCH}
231+
LIB_LIBSAMPLERATE_ENABLE=${LIB_LIBSAMPLERATE_ENABLE}
209232
LIB_OPUS_ENABLE=${LIB_OPUS_ENABLE}
210233
PORTING_LIB_TFLM_ENABLE=${PORTING_LIB_TFLM_ENABLE}
211234
PORTING_LIB_DL_FFT_ENABLE=${PORTING_LIB_DL_FFT_ENABLE}
Submodule libsamplerate added at 2ccde95

components/acoustics/CMakeLists.txt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,20 @@ if(NOT DEFINED ACOUSTICS_SDK_TARGET)
8989
message(FATAL_ERROR "ACOUSTICS_SDK_TARGET is not defined")
9090
endif()
9191

92+
if(NOT DEFINED ACOUSTICS_LIB_LIBSAMPLERATE_ENABLE)
93+
set(LIB_LIBSAMPLERATE_ENABLE 0)
94+
message(STATUS "SRC (aka libsamplerate) support is disabled by default")
95+
else()
96+
message(STATUS "SRC (aka libsamplerate) support is set to: ${ACOUSTICS_LIB_LIBSAMPLERATE_ENABLE}")
97+
if(ACOUSTICS_LIB_LIBSAMPLERATE_ENABLE STREQUAL "1" OR ACOUSTICS_LIB_LIBSAMPLERATE_ENABLE STREQUAL "ON")
98+
set(LIB_LIBSAMPLERATE_ENABLE 1)
99+
message(STATUS "SRC (aka libsamplerate) support is enabled")
100+
else()
101+
set(LIB_LIBSAMPLERATE_ENABLE 0)
102+
message(STATUS "SRC (aka libsamplerate) support is disabled")
103+
endif()
104+
endif()
105+
92106
if(NOT DEFINED ACOUSTICS_LIB_OPUS_ENABLE)
93107
set(LIB_OPUS_ENABLE 0)
94108
message(STATUS "OPUS support is disabled by default")
@@ -115,6 +129,7 @@ if(${ACOUSTICS_SDK_TARGET} STREQUAL "POSIX")
115129

116130
target_compile_definitions(acoustics PUBLIC
117131
ACOUSTICS_API_VERSION=${ACOUSTICS_API_VERSION}
132+
LIB_LIBSAMPLERATE_ENABLE=${LIB_LIBSAMPLERATE_ENABLE}
118133
LIB_OPUS_ENABLE=${LIB_OPUS_ENABLE}
119134
)
120135

@@ -128,4 +143,4 @@ if(${ACOUSTICS_SDK_TARGET} STREQUAL "POSIX")
128143
endif()
129144
endif()
130145

131-
add_compile_options(-fdiagnostics-color=always -ffast-math -O2)
146+
add_compile_options(-fdiagnostics-color=always -ffast-math -O2)

components/acoustics/core/encoder/opus.hpp

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "core/encoder.hpp"
1818
#include "core/logger.hpp"
19+
#include "core/utils/sound_resample.hpp"
1920

2021
#include <opus.h>
2122

@@ -227,8 +228,13 @@ namespace encoder {
227228
{
228229
while (size >= _frame_size)
229230
{
230-
resampleLinear(data, _frame_size, static_cast<int16_t *>(_resample_buffer),
231-
_resample_frame_size, _sample_rate, _sample_rate_encoder);
231+
if (!soundResampleLinear(data, _frame_size, static_cast<int16_t *>(_resample_buffer),
232+
_resample_frame_size, _sample_rate, _sample_rate_encoder))
233+
{
234+
LOG(ERROR, "Failed to resample audio");
235+
_error = EINVAL;
236+
return encoded;
237+
}
232238
int res = opus_encode(_opus_encoder, static_cast<const opus_int16 *>(_resample_buffer),
233239
_resample_frame_size, static_cast<unsigned char *>(_buffer), _buffer_size);
234240
if (res < 0)
@@ -301,37 +307,6 @@ namespace encoder {
301307
_buffer_size);
302308
}
303309

304-
static void resampleLinear(const int16_t *in_data, size_t in_size, int16_t *out_data, size_t out_size,
305-
size_t in_rate, size_t out_rate)
306-
{
307-
double ratio = static_cast<double>(in_rate) / out_rate;
308-
size_t out_samples = static_cast<size_t>(std::floor(in_size / ratio));
309-
310-
if (out_samples > out_size)
311-
{
312-
LOG(WARNING, "Output buffer size is too small, truncating");
313-
out_samples = out_size;
314-
}
315-
316-
for (size_t i = 0; i < out_samples; ++i)
317-
{
318-
float in_pos = static_cast<double>(i) * ratio;
319-
size_t index1 = static_cast<size_t>(std::floor(in_pos));
320-
size_t index2 = index1 + 1;
321-
322-
float fraction = in_pos - index1;
323-
324-
int16_t sample1 = in_data[index1];
325-
int16_t sample2 = (index2 < in_size) ? in_data[index2] : sample1;
326-
327-
int32_t interpolated_sample
328-
= static_cast<int32_t>(std::roundf((1.0f - fraction) * sample1 + fraction * sample2));
329-
out_data[i] = static_cast<int16_t>(
330-
std::clamp(interpolated_sample, static_cast<int32_t>(std::numeric_limits<int16_t>::min()),
331-
static_cast<int32_t>(std::numeric_limits<int16_t>::max())));
332-
}
333-
}
334-
335310
State _state;
336311
const size_t _frame_size;
337312
const size_t _resample_frame_size;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
#ifndef SOUND_RESAMPLE_HPP
3+
#define SOUND_RESAMPLE_HPP
4+
5+
#include <cmath>
6+
#include <cstddef>
7+
#include <cstdint>
8+
#include <cstring>
9+
#include <limits>
10+
#include <type_traits>
11+
12+
namespace core {
13+
14+
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
15+
static inline bool soundResampleLinear(const T *in_data, size_t in_size, T *out_data, size_t out_size, size_t in_rate,
16+
size_t out_rate)
17+
{
18+
if (!in_data || in_size == 0 || !out_data || out_size == 0 || in_rate == 0 || out_rate == 0) [[unlikely]]
19+
{
20+
return false;
21+
}
22+
23+
if (in_rate == out_rate) [[unlikely]]
24+
{
25+
out_size = std::min(in_size, out_size);
26+
std::memcpy(out_data, in_data, out_size * sizeof(T));
27+
return true;
28+
}
29+
30+
const double ratio = static_cast<double>(in_rate) / out_rate;
31+
const size_t out_samples = std::min(static_cast<size_t>(std::floor(in_size / ratio)), out_size);
32+
for (size_t i = 0; i < out_samples; ++i)
33+
{
34+
float in_pos = static_cast<float>(static_cast<double>(i) * ratio);
35+
size_t index1 = static_cast<size_t>(std::floor(in_pos));
36+
size_t index2 = index1 + 1;
37+
38+
float fraction = in_pos - index1;
39+
T sample1 = in_data[index1];
40+
T sample2 = index2 < in_size ? in_data[index2] : sample1;
41+
42+
float interpolated_sample = std::roundf(((1.0f - fraction) * sample1) + (fraction * sample2));
43+
out_data[i] = static_cast<T>(std::clamp(interpolated_sample, static_cast<float>(std::numeric_limits<T>::min()),
44+
static_cast<float>(std::numeric_limits<T>::max())));
45+
}
46+
return true;
47+
}
48+
49+
} // namespace core
50+
51+
#endif

0 commit comments

Comments
 (0)