Compare commits
17 Commits
ab16418dad
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 69e8f5e75b | |||
| 45215c1529 | |||
| ec1bd2f376 | |||
| 39b62d6ccb | |||
| 3afccda759 | |||
| 83ae62ce19 | |||
| 8d860ce409 | |||
| a18cefb671 | |||
| b7f68f97c4 | |||
| cab65a93ad | |||
| f21a17b6c9 | |||
| f904e78792 | |||
| 901c71f4eb | |||
| dce15d23bd | |||
| a49fc7d5e3 | |||
| afe54548a0 | |||
| 84701bcfde |
24
bin/main.fft.cpp
Normal file
24
bin/main.fft.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#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 = "/mnt/raid/projects/dsp/songs/base/MakSim: Знаешь ли ты?.mp3";
|
||||
|
||||
auto r = hr::run<hr::plugins::fft>(setup);
|
||||
hack::log()("grad:", r.m_grad.size());
|
||||
hack::log()("min:", r.m_min, "max:", r.m_max);
|
||||
hack::log()("size:", r.m_size);
|
||||
|
||||
if (!r.empty())
|
||||
{
|
||||
for (auto& p : r.m_data)
|
||||
hack::log()(p[10].m_values.size(), p[10].m_min, p[10].m_max);
|
||||
}
|
||||
}
|
||||
@@ -8,16 +8,17 @@ auto main() -> int
|
||||
// данных для чтения m_block_size; см. установки по умолчанию.
|
||||
// Передается по ссылке и заполняется необходимыми данными
|
||||
hr::setup setup;
|
||||
// setup.m_domain = hr::DOMAIN_PLUGIN::FREQUENSY;
|
||||
setup.m_domain = hr::DOMAIN_PLUGIN::TIME;
|
||||
setup.m_file = "./sin.wav";
|
||||
|
||||
auto r = hr::run<hr::plugins::raw_data>(setup);
|
||||
hack::log()("size:", r.m_data.size());
|
||||
hack::log()("grad:", r.m_grad);
|
||||
hack::log()("min:", r.m_min, "max:", r.m_max);
|
||||
hack::log()("size", r.m_size);
|
||||
|
||||
// if (!r.empty())
|
||||
// {
|
||||
// std::vector<float> s;
|
||||
// for (auto p : r.m_data) s.push_back(p.m_value[0]);
|
||||
// hack::log()(s);
|
||||
// }
|
||||
if (!r.empty())
|
||||
{
|
||||
for (auto& p : r.m_data)
|
||||
hack::log()(p[0].m_value);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
executable(
|
||||
meson.project_name(),
|
||||
'main.cpp',
|
||||
'main.fft.cpp',
|
||||
dependencies : deps,
|
||||
cpp_args: args,
|
||||
include_directories : inc
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace hr
|
||||
private:
|
||||
void swap_buffer(fvec_t& in)
|
||||
{
|
||||
size_t i = 0;
|
||||
std::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];
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "plugins/raw_data/raw_data.hpp" // IWYU pragma: keep
|
||||
#include "plugins/magnitude/magnitude.hpp" // IWYU pragma: keep
|
||||
#include "plugins/fft/fft.hpp" // IWYU pragma: keep
|
||||
|
||||
namespace hr
|
||||
{
|
||||
@@ -23,36 +24,32 @@ namespace hr
|
||||
template<typename Plugin>
|
||||
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)
|
||||
auto deleter = [&](SNDFILE* f) { if (f) sf_close(f); };
|
||||
std::unique_ptr<SNDFILE, decltype(deleter)> sf_file(sf_open(setup.m_file.c_str(), SFM_READ, &sf_info), deleter);
|
||||
|
||||
if (!sf_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.description(sf_strerror(sf_file.get()));
|
||||
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;
|
||||
setup.check();
|
||||
|
||||
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 };
|
||||
|
||||
@@ -60,7 +57,7 @@ namespace hr
|
||||
{
|
||||
// Определение длины читаемого блока (защита от выхода за границы)
|
||||
auto length = hack::math::min(setup.m_step_size, in.size());
|
||||
auto read_samples = sf_read_float(file, read_data.data(), read_data.size());
|
||||
auto read_samples = sf_read_float(sf_file.get(), read_data.data(), read_data.size());
|
||||
|
||||
uint_t read_length = read_samples / setup.m_channels; // Перевод в кадры
|
||||
read_length = hack::math::min(length, read_length); // Ограничение длиной буфера
|
||||
@@ -70,26 +67,23 @@ namespace hr
|
||||
{
|
||||
in[i] = 0.0;
|
||||
// Суммирование всех каналов
|
||||
for (int c = 0; c < setup.m_channels; ++c)
|
||||
in[i] += read_data[setup.m_channels * i + c];
|
||||
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)));
|
||||
read = hack::math::min(length, static_cast<uint_t>(std::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);
|
||||
real_time timestamp = real_time::frame2rt(read, setup.m_sample_rate);
|
||||
ad.process(in, timestamp);
|
||||
}
|
||||
while (read == setup.m_step_size); // Продолжать пока читаются полные блоки
|
||||
while (read == setup.m_step_size);
|
||||
|
||||
// Закрытие файла и возврат результата
|
||||
sf_close(file);
|
||||
return ad.get_result();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ headers = [
|
||||
# plugins
|
||||
'plugins/raw_data/raw_data.hpp',
|
||||
'plugins/magnitude/magnitude.hpp',
|
||||
'plugins/fft/fft.hpp',
|
||||
|
||||
'harmonica.hpp'
|
||||
]
|
||||
@@ -30,6 +31,7 @@ sources = [
|
||||
# plugins
|
||||
'plugins/raw_data/raw_data.cpp',
|
||||
'plugins/magnitude/magnitude.cpp',
|
||||
'plugins/fft/fft.cpp',
|
||||
]
|
||||
|
||||
lib = library(
|
||||
|
||||
55
src/plugins/fft/fft.cpp
Normal file
55
src/plugins/fft/fft.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "fft.hpp"
|
||||
#include "utils/var.hpp"
|
||||
#include "utils/math.hpp"
|
||||
|
||||
namespace hr::plugins
|
||||
{
|
||||
fft::fft(const setup& st) : plugin{ st }
|
||||
{
|
||||
m_setup.m_plugin_name = "FFT";
|
||||
m_setup.m_plugin_description = "Вычисляет FFT и прокидывает данные дальше в вашу программу.";
|
||||
GUARD_DOMAIN(FREQUENSY);
|
||||
|
||||
// Данные - амплитуда частот
|
||||
m_result.init(1);
|
||||
|
||||
// заполняем градацию по частотам
|
||||
// тут не нужно делить на 2. получаем = 513 исходя из базового m_setup
|
||||
// т.к. реализация FFT (rdft) уже возвращает только уникальную часть спектра, а не полный симметричный массив из 1024 элементов.
|
||||
auto step = m_setup.m_step_size + 1;
|
||||
m_result.m_grad.reserve(step);
|
||||
for (size_t i = 0; i < step; ++i)
|
||||
m_result.m_grad.push_back(static_cast<float>(i) * m_setup.m_sample_rate / m_setup.m_block_size / 1'000);
|
||||
}
|
||||
|
||||
void fft::process(fvec_t& base, real_time timestamp)
|
||||
{
|
||||
}
|
||||
|
||||
void fft::process(cvec_t& fft, fvec_t& base, real_time timestamp)
|
||||
{
|
||||
auto step = fft.size();
|
||||
|
||||
result::bit b;
|
||||
b.m_name = "Amplitudes";
|
||||
b.m_duration = timestamp;
|
||||
b.m_values.reserve(step);
|
||||
for (size_t i = 0; i < step; ++i)
|
||||
{
|
||||
// Конвертация в децибелы
|
||||
auto v = fft.m_norm[i];
|
||||
if (v > 0.000001f) v = 20.0f * log10(v);
|
||||
else v = -120.0f; // Минимальное значение для логарифмической шкалы
|
||||
b.m_values.push_back(v);
|
||||
b.set_min_max(v);
|
||||
m_result.set_min_max(v);
|
||||
}
|
||||
m_result.set_bit(0, b);
|
||||
++m_result.m_size;
|
||||
}
|
||||
|
||||
result fft::get_result()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
}
|
||||
21
src/plugins/fft/fft.hpp
Normal file
21
src/plugins/fft/fft.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/workers/plugin.hpp"
|
||||
|
||||
namespace hr::plugins
|
||||
{
|
||||
class fft : public plugin
|
||||
{
|
||||
public:
|
||||
fft(const setup& st);
|
||||
virtual ~fft() = 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;
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,16 @@
|
||||
#include "magnitude.hpp"
|
||||
#include "utils/var.hpp"
|
||||
|
||||
namespace hr::plugins
|
||||
{
|
||||
magnitude::magnitude(const setup& st) : plugin{ st }
|
||||
{
|
||||
m_setup.m_plugin_name = "Magnitude";
|
||||
m_setup.m_plugin_description = "Средняя амплитуда спектра (общая энергия сигнала).";
|
||||
|
||||
GUARD_DOMAIN(FREQUENSY);
|
||||
|
||||
m_result.init(1);
|
||||
}
|
||||
|
||||
void magnitude::process(fvec_t& base, real_time timestamp)
|
||||
@@ -13,15 +20,20 @@ namespace hr::plugins
|
||||
void magnitude::process(cvec_t& fft, fvec_t& base, real_time timestamp)
|
||||
{
|
||||
std::size_t frames = fft.size();
|
||||
base_t m = 0.f;
|
||||
for (std::size_t i = 0; i < frames; ++i) m += fft.m_norm[i];
|
||||
m /= frames;
|
||||
base_t v = 0.f;
|
||||
for (std::size_t i = 0; i < frames; ++i) v += fft.m_norm[i];
|
||||
v /= frames;
|
||||
|
||||
m_result.m_max = hack::math::max(m_result.m_max, v);
|
||||
m_result.m_min = hack::math::min(m_result.m_min, v);
|
||||
|
||||
result::bit b;
|
||||
b.m_value.push_back(m);
|
||||
b.m_value = v;
|
||||
b.m_duration = timestamp;
|
||||
|
||||
m_result.set_bit(b);
|
||||
++m_result.m_size;
|
||||
m_result.set_bit(0, b);
|
||||
m_result.set_min_max(v);
|
||||
}
|
||||
|
||||
result magnitude::get_result()
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
#include "raw_data.hpp"
|
||||
#include "utils/var.hpp"
|
||||
|
||||
namespace hr::plugins
|
||||
{
|
||||
// Этот плагин ни чего не делает и предназначен при сохранении единственности интерфейса просто
|
||||
// передавать сырые необработанные данные. Например дял отрисовки базового сигнала.
|
||||
// передавать сырые необработанные данные. Например для отрисовки базового сигнала.
|
||||
// Он не работает в частотной области
|
||||
raw_data::raw_data(const setup& st) : plugin{ st }
|
||||
{
|
||||
if (st.m_domain != DOMAIN_PLUGIN::TIME)
|
||||
hack::error()("Этот плагин работает только во временной области!");
|
||||
m_setup.m_plugin_name = "Raw Data";
|
||||
m_setup.m_plugin_description = "Ни чего не вычисляет, просто прокидывает сырые данные дальше в вашу программу, для сохранения единой концепции.";
|
||||
GUARD_DOMAIN(TIME);
|
||||
|
||||
// Только 1 тип данных будет в этом плагине, а имеено
|
||||
// сырые данные из файла
|
||||
m_result.init(1);
|
||||
}
|
||||
|
||||
void raw_data::process(fvec_t& base, real_time timestamp)
|
||||
{
|
||||
for (auto& v : base)
|
||||
{
|
||||
result::bit b;
|
||||
b.m_value = base;
|
||||
b.m_value = v;
|
||||
b.m_duration = timestamp;
|
||||
m_tmp.set_bit(b);
|
||||
m_size += base.size();
|
||||
m_result.set_bit(0, b);
|
||||
m_result.set_min_max(v);
|
||||
}
|
||||
m_result.m_size += base.size();
|
||||
}
|
||||
|
||||
void raw_data::process(cvec_t& fft, fvec_t& base, real_time timestamp)
|
||||
@@ -26,23 +36,6 @@ namespace hr::plugins
|
||||
|
||||
result raw_data::get_result()
|
||||
{
|
||||
if (m_tmp.m_data.empty())
|
||||
return m_result;
|
||||
|
||||
m_result.m_data.reserve(m_size);
|
||||
|
||||
std::size_t index = 0;
|
||||
for (auto& t : m_tmp.m_data)
|
||||
{
|
||||
for (auto s : t.m_value)
|
||||
{
|
||||
result::bit b;
|
||||
b.m_value.push_back(s);
|
||||
b.m_duration = t.m_duration;
|
||||
m_result.set_bit(b);
|
||||
}
|
||||
}
|
||||
|
||||
return m_result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace hr::plugins
|
||||
|
||||
private:
|
||||
result m_result;
|
||||
result m_tmp;
|
||||
std::size_t m_size = 0;
|
||||
|
||||
public:
|
||||
void process(fvec_t& base, real_time timestamp) override;
|
||||
|
||||
@@ -41,6 +41,12 @@ namespace hr
|
||||
m_data.reserve(size);
|
||||
}
|
||||
|
||||
// очищает данные с сохранением выделенной под них памяти
|
||||
void fvec_t::clear()
|
||||
{
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
// Циклический сдвиг вектора: первая половина меняется местами со второй
|
||||
// Пример: [1,2,3,4,5,6] -> [4,5,6,1,2,3]
|
||||
// Для нечетных размеров: [1,2,3,4,5,6,7] -> [5,6,7,1,2,3,4]
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace hr
|
||||
void resize(std::size_t new_size, const base_t el);
|
||||
void reserve(std::size_t size);
|
||||
void shift();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::vector<base_t> m_data;
|
||||
|
||||
23
src/utils/math.hpp
Normal file
23
src/utils/math.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <cmath>
|
||||
|
||||
namespace hr
|
||||
{
|
||||
template<typename T>
|
||||
T log10(T value)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, float>)
|
||||
return std::log10f(value);
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
return std::log10(value);
|
||||
else if constexpr (std::is_same_v<T, long double>)
|
||||
return std::log10l(value);
|
||||
else
|
||||
{
|
||||
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double> || std::is_same_v<T, long double>, "Unsupported type for log10");
|
||||
return std::log10(value); // fallback
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace hr { }
|
||||
#define GUARD_DOMAIN(x) if (m_setup.m_domain != DOMAIN_PLUGIN::x) \
|
||||
{\
|
||||
hack::error()("plugin name:", m_setup.m_plugin_name);\
|
||||
hack::warn()("Этот плагин работает только в " #x " области!"); \
|
||||
std::terminate();\
|
||||
}
|
||||
|
||||
namespace hr {
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "utils/real_time/real_time.hpp"
|
||||
#include "utils/fvec/fvec.hpp"
|
||||
#include <hack/math/math.hpp>
|
||||
#include <hack/logger/logger.hpp>
|
||||
#include "utils/real_time/real_time.hpp"
|
||||
#include "utils/using.hpp"
|
||||
|
||||
namespace hr
|
||||
{
|
||||
@@ -11,29 +12,80 @@ namespace hr
|
||||
{
|
||||
struct bit
|
||||
{
|
||||
std::string m_name;
|
||||
real_time m_duration;
|
||||
fvec_t m_value;
|
||||
|
||||
// когда в расчете только одно значение. да может быть и нужно это использовать как
|
||||
// массив с индексом 0 типа m_values[0], но как-то вот так.
|
||||
// Потому как отрисовка графиков тот еще праздник...
|
||||
// конечно в боевой задаче это можно и нужно оптимизировать, но в данном случае для вывода на экран и понимания процесса
|
||||
// это можно опустить и использовать так как есть...
|
||||
base_t m_value;
|
||||
|
||||
// когда у тебя получается на один бин большой массив данных, типа расчет fft (см. комент выше)
|
||||
std::vector<base_t> m_values;
|
||||
|
||||
// максимальные и минимальные элементы в конкретном бине
|
||||
// в основном нужны для графической реализации
|
||||
// соответственно метод ниже в попощь
|
||||
base_t m_max = std::numeric_limits<base_t>::min();
|
||||
base_t m_min = std::numeric_limits<base_t>::max();
|
||||
void set_min_max(base_t v)
|
||||
{
|
||||
m_max = hack::math::max(m_max, v);
|
||||
m_min = hack::math::min(m_min, v);
|
||||
}
|
||||
};
|
||||
|
||||
void set_bit(bit& b)
|
||||
void set_bit(std::size_t index, bit& b)
|
||||
{
|
||||
m_data.push_back(b);
|
||||
try
|
||||
{
|
||||
m_data.at(index).push_back(b);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
hack::error()("Хрень какая-то с массивом данных");
|
||||
hack::warn()(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return m_data.empty();
|
||||
}
|
||||
|
||||
std::vector<bit> m_data;
|
||||
// инициализирует кол-во данных для расчета в плагине
|
||||
// см. ниже
|
||||
void init(std::size_t count_data)
|
||||
{
|
||||
for (std::size_t i = 0; i < count_data; ++i)
|
||||
m_data.push_back(std::vector<bit>{});
|
||||
}
|
||||
|
||||
// схема такая:
|
||||
// Первый вектор - кол-во типов замеров, например 7 т.е можно выстроить 7 линий на графике
|
||||
// если захотелось увидеть их
|
||||
// Второй вектор - данные для каждой линии, т.е. именно сими биты
|
||||
std::vector<std::vector<bit>> m_data;
|
||||
|
||||
// максимальные и минимальные элементы в принципе в данном расчете
|
||||
// в основном нужны для графической реализации
|
||||
// соответственно метод ниже в попощь
|
||||
base_t m_max = std::numeric_limits<base_t>::min();
|
||||
base_t m_min = std::numeric_limits<base_t>::max();
|
||||
void set_min_max(base_t v)
|
||||
{
|
||||
m_max = hack::math::max(m_max, v);
|
||||
m_min = hack::math::min(m_min, v);
|
||||
}
|
||||
|
||||
// в данном случае вы сами решаете, что для вас значит размер
|
||||
// это может быть размер всего массива m_data или размер массива данных хранящихся в каждом бине
|
||||
// или этот же массив, но помноженный на размер m_data
|
||||
std::size_t m_size = 0;
|
||||
|
||||
// иногда нужна градуировка одна и тажа для всех бинов
|
||||
std::vector<base_t> m_grad;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <sndfile.h>
|
||||
#include <hack/exception/exception.hpp>
|
||||
#include <hack/logger/logger.hpp>
|
||||
|
||||
namespace hr
|
||||
{
|
||||
@@ -18,9 +21,29 @@ namespace hr
|
||||
int m_channels;
|
||||
|
||||
std::filesystem::path m_file;
|
||||
// Количество семплов, которые обрабатываются за один раз
|
||||
std::size_t m_block_size = 1'024;
|
||||
// На сколько семплов сдвигается окно при следующей обработке
|
||||
std::size_t m_step_size = 512;
|
||||
|
||||
std::string m_plugin_name;
|
||||
std::string m_plugin_description;
|
||||
|
||||
DOMAIN_PLUGIN m_domain = DOMAIN_PLUGIN::TIME;
|
||||
|
||||
void check()
|
||||
{
|
||||
if (m_channels == 0)
|
||||
{
|
||||
hack::exception ex;
|
||||
hack::log().on_file();
|
||||
hack::log().on_func();
|
||||
hack::log().on_row();
|
||||
ex.title("Нет каналов в аудиофайле");
|
||||
ex.set("file", m_file);
|
||||
hack::error()(ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user