#pragma once #include #include #include "utils/var.hpp" // IWYU pragma: keep #include "utils/signal_generator/signal_generator.hpp" // IWYU pragma: keep #include "utils/using.hpp" #include "utils/workers/setup.hpp" #include "utils/workers/result.hpp" #include "adapter/adapter.hpp" #include "plugins/magnitude/magnitude.hpp" // IWYU pragma: keep namespace hr { /** * @brief Запуск на чтение аудиофайла и обработка его через плагин * @tparam Plugin Тип плагина для обработки аудиоданных * @param setup Настройки обработки (путь к файлу, параметры и т.д.) * @return Результат обработки аудио */ template inline result run(setup& setup) { // Инициализация структуры для libsndfile и открытие файла SF_INFO sf_info; SNDFILE* file = sf_open(setup.m_file.c_str(), SFM_READ, &sf_info); if (!file) { // Обработка ошибки открытия файла hack::exception ex; hack::log().on_file(); hack::log().on_func(); hack::log().on_row(); ex.title("Error of open file"); ex.description(sf_strerror(file)); ex.set("file", setup.m_file); hack::error()(ex); throw ex; } // Сохранение информации о файле в настройки setup.m_sample_rate = sf_info.samplerate; setup.m_frames = sf_info.frames; setup.m_channels = sf_info.channels; if (setup.m_channels == 0) throw std::runtime_error("Нет каналов в аудио файле"); // Инициализация переменных для чтения std::size_t read = 0; // Количество обработанных кадров fvec_t read_data(setup.m_channels * setup.m_step_size, .0); // Буфер для чтения (интерливированные данные) fvec_t in(setup.m_step_size, .0); // Буфер для моно-данных // Создание плагина и адаптера для обработки Plugin pl { setup }; adapter ad { pl }; do { // Определение длины читаемого блока (защита от выхода за границы) auto length = hack::math::min(setup.m_step_size, in.size()); auto read_samples = sf_read_float(file, read_data.data(), read_data.size()); uint_t read_length = read_samples / setup.m_channels; // Перевод в кадры read_length = hack::math::min(length, read_length); // Ограничение длиной буфера // Де-интерливирование и down-mixing (преобразование многоканального в моно) for (std::size_t i = 0; i < read_length; ++i) { in[i] = 0.0; // Суммирование всех каналов for (int c = 0; c < setup.m_channels; ++c) in[i] += read_data[setup.m_channels * i + c]; // Усреднение для получения моно-сигнала in[i] /= static_cast(setup.m_channels); } // Подготовка к следующей итерации read = hack::math::min(length, static_cast(floorf(read_length + .5))); // Дополнение буфера нулями если считано неполный блок (конец файла) if (in.size() > read) std::fill(in.begin() + read, in.end(), 0.0); // Вычисление временной метки и обработка данных через адаптер real_time timestamp = real_time::frame2rt(read, sf_info.samplerate); ad.process(in, timestamp); } while (read == setup.m_step_size); // Продолжать пока читаются полные блоки // Закрытие файла и возврат результата sf_close(file); return ad.get_result(); } }