Program Listing for File rateshift.cpp
↰ Return to documentation for file (sudio/rateshift/src/rateshift.cpp
)
/*
* SUDIO - Audio Processing Platform
* Copyright (C) 2024 Hossein Zahaki
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* - GitHub: https://github.com/MrZahaki/sudio
*/
#include "rateshift.hpp"
#include <stdexcept>
#include <cmath>
namespace rateshift {
namespace {
void error_handler(int errnum) {
if (errnum != 0) {
throw std::runtime_error(src_strerror(errnum));
}
}
int convert_type(ConverterType type) {
switch (type) {
case ConverterType::sinc_best: return SRC_SINC_BEST_QUALITY;
case ConverterType::sinc_medium: return SRC_SINC_MEDIUM_QUALITY;
case ConverterType::sinc_fastest: return SRC_SINC_FASTEST;
case ConverterType::zero_order_hold: return SRC_ZERO_ORDER_HOLD;
case ConverterType::linear: return SRC_LINEAR;
default: throw std::invalid_argument("Invalid converter type");
}
}
}
Resampler::Resampler(ConverterType converter_type, int channels)
: _converter_type(convert_type(converter_type)), _channels(channels) {
int error;
_state = src_new(_converter_type, _channels, &error);
error_handler(error);
}
Resampler::~Resampler() {
if (_state) {
src_delete(_state);
}
}
std::vector<float> Resampler::process(const std::vector<float>& input, double sr_ratio, bool end_of_input) {
size_t input_frames = input.size() / _channels;
size_t output_frames = static_cast<size_t>(std::ceil(input_frames * sr_ratio));
std::vector<float> output(output_frames * _channels);
SRC_DATA src_data = {
const_cast<float*>(input.data()),
const_cast<float*>(output.data()),
static_cast<long>(input_frames),
static_cast<long>(output_frames),
0, 0,
end_of_input ? 1 : 0,
sr_ratio
};
error_handler(src_process(_state, &src_data));
output.resize(src_data.output_frames_gen * _channels);
return output;
}
void Resampler::set_ratio(double new_ratio) {
error_handler(src_set_ratio(_state, new_ratio));
}
void Resampler::reset() {
error_handler(src_reset(_state));
}
CallbackResampler::CallbackResampler(callback_t callback_func, double ratio, ConverterType converter_type, size_t channels)
: _callback(std::move(callback_func)), _ratio(ratio), _converter_type(convert_type(converter_type)), _channels(channels) {
int error;
_state = src_callback_new(
[](void* cb_data, float** data) -> long {
auto* self = static_cast<CallbackResampler*>(cb_data);
auto input = self->_callback();
if (input.empty()) return 0;
*data = input.data();
return static_cast<long>(input.size() / self->_channels);
},
_converter_type,
static_cast<int>(_channels),
&error,
this
);
error_handler(error);
}
CallbackResampler::~CallbackResampler() {
if (_state) {
src_delete(_state);
}
}
std::vector<float> CallbackResampler::read(size_t frames) {
std::vector<float> output(frames * _channels);
long frames_read = src_callback_read(_state, _ratio, static_cast<long>(frames), output.data());
if (frames_read == 0) {
error_handler(src_error(_state));
}
output.resize(frames_read * _channels);
return output;
}
void CallbackResampler::set_starting_ratio(double new_ratio) {
error_handler(src_set_ratio(_state, new_ratio));
_ratio = new_ratio;
}
void CallbackResampler::reset() {
error_handler(src_reset(_state));
}
std::vector<float> resample(const std::vector<float>& input, double sr_ratio, ConverterType converter_type, int channels) {
if (input.size() % channels != 0) {
throw std::invalid_argument("Input size must be divisible by number of channels");
}
size_t input_frames = input.size() / channels;
size_t output_frames = static_cast<size_t>(std::ceil(input_frames * sr_ratio));
std::vector<float> output(output_frames * channels);
SRC_DATA src_data = {
const_cast<float*>(input.data()), // Assuming ALREADY INTERLEAVED input
static_cast<float*>(output.data()),
static_cast<long>(input_frames),
static_cast<long>(output_frames),
0, // Input frames used
0, // Output frames generated
0, // Input sample rate (0 = same as output)
sr_ratio
};
error_handler(src_simple(&src_data, convert_type(converter_type), channels));
output.resize(src_data.output_frames_gen * channels);
return output;
}
}