Files
harmonica/.ccls-cache/@mnt@raid@projects@dsp@harmonica@harmonica/src@harmonica.hpp
2026-02-22 10:42:29 +03:00

109 lines
4.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <sndfile.h>
#include <hack/logger/logger.hpp>
#include "utils/var.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
#include "plugins/signal_generator/signal_generator.hpp" // IWYU pragma: keep
namespace hr
{
/**
* @brief Запуск на чтение аудиофайла и обработка его через плагин
* @tparam Plugin Тип плагина для обработки аудиоданных
* @param setup Настройки обработки (путь к файлу, параметры и т.д.)
* @return Результат обработки аудио
*/
template<typename Plugin>
inline result run(setup& setup)
{
if (setup.m_signal_type.m_type != hr::signal_type::type::FILE)
{
Plugin pl { setup };
adapter ad { pl };
// просто заглушки для process
fvec_t v;
real_time t;
ad.process(v, t);
return ad.get_result();
}
else
{
// Инициализация структуры для libsndfile и открытие файла
SF_INFO sf_info;
SNDFIoLE* 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<base_t>(setup.m_channels);
}
// Подготовка к следующей итерации
read = hack::math::min(length, static_cast<uint_t>(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();
}
}
}