Program Listing for File rateshift.cpp — sudio documentation

# Program Listing for File rateshift.cpp

↰ Return to documentation for file (`sudio\rateshift\src\rateshift.cpp`)

    /*
     -- W.T.A
     -- SUDIO (https://github.com/MrZahaki/sudio)
     -- The Audio Processing Platform
     -- Mail: mrzahaki@gmail.com
     -- Software license: "Apache License 2.0".
    */
    #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) {
        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()),
            static_cast<float *>(output.data()),
            static_cast<long>(input_frames),
            static_cast<long>(output_frames),
            0, 0, 0,
            sr_ratio
        };

        error_handler(src_simple(&src_data, convert_type(converter_type), channels));

        output.resize(src_data.output_frames_gen * channels);
        return output;
    }

    }