remove signal generator

This commit is contained in:
2026-02-22 10:42:29 +03:00
parent 0b9c830f58
commit a082537c94
524 changed files with 101136 additions and 375 deletions

View File

@@ -0,0 +1,23 @@
#include <hack/logger/logger.hpp>
#include "harmonica.hpp"
auto main() -> int
{
// setup создается для каждого файла свой
// т.к. при чтении данных из файла уже должен быть определен размер блока
// данных для чтения m_block_size; см. установки по умолчанию.
// Передается по ссылке и заполняется необходимыми данными
hr::setup setup;
setup.m_domain = hr::DOMAIN_PLUGIN::FREQUENSY;
setup.m_file = hr::TEST_SOUND;
auto r = hr::run<hr::plugins::magnitude>(setup);
hack::log()("size:", r.m_data.size());
if (!r.empty())
{
std::vector<float> s;
for (auto p : r.m_data) s.push_back(p.m_value[0]);
hack::log()(s);
}
}

View File

@@ -0,0 +1,75 @@
#pragma once
#include "utils/workers/result.hpp"
#include "utils/workers/setup.hpp"
#include "utils/fft/fft.hpp"
#include "utils/fvec/fvec.hpp"
#include "utils/windows/hann/hann.hpp"
namespace hr
{
template<typename Plugin>
class adapter
{
public:
adapter(Plugin& p) : m_plugin { p }
{
m_end = m_plugin.m_setup.m_block_size - m_plugin.m_setup.m_step_size;
m_data.resize(m_plugin.m_setup.m_block_size, 0.0);
m_data_old.resize(m_end, 0.0);
m_fft.init(m_plugin.m_setup.m_block_size);
m_hann.creaate(m_plugin.m_setup.m_block_size);
}
virtual ~adapter() { }
protected:
Plugin& m_plugin;
real_time m_timestamp;
fft m_fft;
math::hann m_hann;
fvec_t m_data;
fvec_t m_data_old;
size_t m_end;
public:
void process(fvec_t& in, real_time timestamp)
{
m_timestamp = timestamp;
switch(m_plugin.m_setup.m_domain)
{
case DOMAIN_PLUGIN::TIME:
{
m_plugin.process(in, m_timestamp);
break;
}
case DOMAIN_PLUGIN::FREQUENSY:
{
frequensy(in);
break;
}
}
}
result get_result() { return m_plugin.get_result(); }
private:
void swap_buffer(fvec_t& in)
{
size_t i = 0;
for (i = 0; i < m_end; ++i) m_data[i] = m_data_old[i];
for (i = 0; i < m_plugin.m_setup.m_step_size; ++i) m_data[m_end + i] = in[i];
for (i = 0; i < m_end; ++i) m_data_old[i] = m_data[i + m_plugin.m_setup.m_step_size];
}
void frequensy(fvec_t& in)
{
swap_buffer(in);
m_hann.apply(m_data);
m_data.shift();
auto r = m_fft.process(m_data);
m_plugin.process(r, in, m_timestamp);
}
};
}

View File

@@ -0,0 +1,108 @@
#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();
}
}
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include "utils/workers/plugin.hpp"
namespace hr::plugins
{
class magnitude : public plugin
{
public:
magnitude(const setup& st);
virtual ~magnitude() = default;
private:
result m_result;
public:
void process(fvec_t& base, real_time timestamp) override;
void process(cvec_t& fft, fvec_t& base, real_time timestamp) override;
result get_result() override;
};
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include "utils/workers/plugin.hpp"
#include "utils/workers/result.hpp"
// Генерирует простую синусоиду и др. полезности см. workers/signal_type.hpp
namespace hr::plugins
{
// Формула синусоиды
// f(t) = A_m sin(2 PI t 1/T + a)
// где
// a - начальная фаза
// t - время замера
// 1/T - частота
// T - время полного цикла одного периуда колебаний
class signal_generator : public plugin
{
public:
signal_generator(const setup& st);
virtual ~signal_generator() = default;
public:
void process(fvec_t& base, real_time timestamp) override;
void process(cvec_t& fft, fvec_t& base, real_time timestamp) override;
result get_result() override;
private:
result m_result;
private:
std::vector<float> sin();
std::vector<float> square();
std::vector<float> triangle();
std::vector<float> saw();
std::vector<float> noise_only();
std::vector<float> speech_like();
std::vector<float> three_sines();
private:
};
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <vector>
namespace hr
{
using base_t = float;
using uint_t = unsigned int;
// HERE
// убрать это чтоб не было желяния превраить это по аналогии с fvec_t
using ivec_t = std::vector<int>;
}

View File

@@ -0,0 +1,4 @@
#pragma once
#include "noincl.hpp" // IWYU pragma: keep
namespace hr { }

View File

@@ -0,0 +1,39 @@
#pragma once
#include <vector>
#include "utils/real_time/real_time.hpp"
#include "utils/fvec/fvec.hpp"
#include <hack/logger/logger.hpp>
namespace hr
{
struct result
{
struct bit
{
real_time m_duration;
fvec_t m_value;
};
void set_bit(bit& b)
{
m_data.push_back(b);
}
bool empty() const
{
bool res = true;
try
{
if (!m_data.empty()) res = m_data.at(0).m_value.empty();
}
catch(std::exception& e)
{
hack::error()(e.what());
}
return res;
}
std::vector<bit> m_data;
};
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "utils/workers/signals/signal_type.hpp"
#include <filesystem>
namespace hr
{
enum class DOMAIN_PLUGIN
{
TIME,
FREQUENSY
};
struct setup
{
// Эти данные заполняются из прочитанного файла (sndfile)
int m_sample_rate;
int m_frames;
int m_channels;
std::filesystem::path m_file;
std::size_t m_block_size = 1'024;
std::size_t m_step_size = 512;
signal_type m_signal_type;
DOMAIN_PLUGIN m_domain = DOMAIN_PLUGIN::FREQUENSY;
};
}