160 lines
5.0 KiB
C++
160 lines
5.0 KiB
C++
#include "audio_buffer.h"
|
|
|
|
#include <cstring>
|
|
#include <experimental/simd>
|
|
|
|
#include "audio_buffer_pool.h"
|
|
#include "misc/cpu_simd.h"
|
|
#include "misc/likely.h"
|
|
|
|
void(*audio_buffer::add_func)(audio_buffer& in_buffer, audio_buffer& from_buffer, float percent);
|
|
void(*audio_buffer::multiple_func)(audio_buffer& in_buffer, float percent);
|
|
|
|
template<int simd_size>
|
|
void add_simd(audio_buffer& in_buffer, audio_buffer& from_buffer, float percent) {
|
|
using namespace std::experimental;
|
|
using simd_type = simd_abi::fixed_size<simd_size>;
|
|
|
|
simd<sample_t, simd_type> percent_simd(percent);
|
|
for (uint32_t channel_index = 0; channel_index < in_buffer.get_num_channels(); channel_index++) {
|
|
sample_t* channel = in_buffer.get_headers()[channel_index];
|
|
sample_t* in_channel = from_buffer.get_headers()[channel_index];
|
|
int i = 0;
|
|
for (; i < in_buffer.get_num_samples(); i += simd_size) {
|
|
simd<sample_t, simd_type> a(channel, element_aligned);
|
|
simd<sample_t, simd_type> b(in_channel, element_aligned);
|
|
a += b * percent_simd;
|
|
a.copy_to(channel, element_aligned);
|
|
|
|
channel += simd_size;
|
|
in_channel += simd_size;
|
|
}
|
|
// if the number of samples is not a multiple of simd_size
|
|
for (; i < in_buffer.get_num_samples(); ++i) {
|
|
channel[i] += in_channel[i] * percent;
|
|
}
|
|
}
|
|
}
|
|
|
|
void add_no_simd(audio_buffer& in_buffer, audio_buffer& from_buffer, float percent) {
|
|
for (uint32_t channel_index = 0; channel_index < in_buffer.get_num_channels(); channel_index++) {
|
|
sample_t* channel = in_buffer.get_headers()[channel_index];
|
|
sample_t* in_channel = from_buffer.get_headers()[channel_index];
|
|
for (int i = 0; i < in_buffer.get_num_samples(); ++i) {
|
|
channel[i] += in_channel[i] * percent;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<int simd_size>
|
|
void multiple_simd(audio_buffer& in_buffer, float percent) {
|
|
using namespace std::experimental;
|
|
using simd_type = simd_abi::fixed_size<simd_size>;
|
|
|
|
simd<sample_t, simd_type> percent_simd(percent);
|
|
for (auto channel : in_buffer.get_headers_vector()) {
|
|
int i = 0;
|
|
for (; i < in_buffer.get_num_samples(); i += simd_size) {
|
|
simd<sample_t, simd_type> a(channel, element_aligned);
|
|
a *= percent_simd;
|
|
a.copy_to(channel, element_aligned);
|
|
channel += simd_size;
|
|
}
|
|
// if the number of samples is not a multiple of simd_size
|
|
for (; i < in_buffer.get_num_samples(); ++i) {
|
|
channel[i] *= percent;
|
|
}
|
|
}
|
|
}
|
|
|
|
void multiple_no_simd(audio_buffer& in_buffer, float percent) {
|
|
for (auto channel : in_buffer.get_headers_vector()) {
|
|
for (int i = 0; i < in_buffer.get_num_samples(); ++i) {
|
|
channel[i] *= percent;
|
|
}
|
|
}
|
|
}
|
|
|
|
audio_buffer::audio_buffer() {
|
|
using namespace std::experimental;
|
|
static bool func_initialized = false;
|
|
if (UNLIKELY(!func_initialized)) {
|
|
cpuid cpu;
|
|
#define DEFINE_SIMD_FUNC(simd_max) \
|
|
constexpr size_t simd_size = simd_max / sizeof(sample_t) / 8; \
|
|
add_func = &add_simd<simd_size>; \
|
|
multiple_func = &multiple_simd<simd_size>;
|
|
#if CPU_AMD64
|
|
if (cpu.support_avx512()) {
|
|
DEFINE_SIMD_FUNC(512)
|
|
} else if (cpu.support_avx() || cpu.support_avx2()) {
|
|
DEFINE_SIMD_FUNC(256)
|
|
} else if (cpu.support_sse()) {
|
|
DEFINE_SIMD_FUNC(128)
|
|
}
|
|
#endif
|
|
#if CPU_ARM
|
|
if (cpu.support_neon128()) {
|
|
DEFINE_SIMD_FUNC(128)
|
|
} else if (cpu.support_neon64()) {
|
|
DEFINE_SIMD_FUNC(64)
|
|
}
|
|
#endif
|
|
if (!add_func) {
|
|
add_func = &add_no_simd;
|
|
multiple_func = &multiple_no_simd;
|
|
}
|
|
func_initialized = true;
|
|
}
|
|
#undef DEFINE_SIMD_FUNC
|
|
}
|
|
|
|
audio_buffer::~audio_buffer() {
|
|
free();
|
|
}
|
|
|
|
void audio_buffer::resize(uint32_t channel_num, uint32_t frame_size) {
|
|
frame_size_ = frame_size;
|
|
free();
|
|
audio_buffer_pool* pool = get_audio_buffer_pool();
|
|
for (int i = 0; i < channel_num; ++i) {
|
|
sample_t* block = pool->alloc(frame_size);
|
|
headers_.push_back(block);
|
|
}
|
|
clear();
|
|
}
|
|
|
|
void audio_buffer::clear() {
|
|
for (sample_t* channel : headers_) {
|
|
std::memset(channel, 0, frame_size_ * sizeof(sample_t));
|
|
}
|
|
}
|
|
|
|
|
|
void audio_buffer::add(audio_buffer& from_buffer, float percent) {
|
|
std::scoped_lock lock(lock_);
|
|
add_func(*this, from_buffer, percent);
|
|
}
|
|
|
|
void audio_buffer::multiple(float percent) {
|
|
std::scoped_lock lock(lock_);
|
|
multiple_func(*this, percent);
|
|
}
|
|
|
|
std::vector<sample_t> audio_buffer::get_interleaved_buffer() const {
|
|
std::vector<sample_t> result;
|
|
result.reserve(headers_.size() * frame_size_);
|
|
for (int i = 0; i < frame_size_; ++i) {
|
|
for (const sample_t* channel : headers_) {
|
|
result.push_back(channel[i]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void audio_buffer::free() {
|
|
for (sample_t* header : headers_)
|
|
get_audio_buffer_pool()->free(header);
|
|
headers_.clear();
|
|
}
|