add fft plugin
This commit is contained in:
10
bin/main.cpp
10
bin/main.cpp
@@ -8,18 +8,16 @@ auto main() -> int
|
|||||||
// данных для чтения m_block_size; см. установки по умолчанию.
|
// данных для чтения m_block_size; см. установки по умолчанию.
|
||||||
// Передается по ссылке и заполняется необходимыми данными
|
// Передается по ссылке и заполняется необходимыми данными
|
||||||
hr::setup setup;
|
hr::setup setup;
|
||||||
// setup.m_domain = hr::DOMAIN_PLUGIN::FREQUENSY;
|
setup.m_domain = hr::DOMAIN_PLUGIN::FREQUENSY;
|
||||||
setup.m_file = "./sin.wav";
|
setup.m_file = "./sin.wav";
|
||||||
|
|
||||||
auto r = hr::run<hr::plugins::raw_data>(setup);
|
auto r = hr::run<hr::plugins::fft>(setup);
|
||||||
hack::log()("size:", r.size());
|
hack::log()("size:", r.size());
|
||||||
|
hack::log()("grad:", r.m_grad);
|
||||||
|
|
||||||
if (!r.empty())
|
if (!r.empty())
|
||||||
{
|
{
|
||||||
std::vector<float> res;
|
|
||||||
for (auto& p : r.m_data)
|
for (auto& p : r.m_data)
|
||||||
for (auto s : p)
|
hack::log()(p[0].m_values);
|
||||||
res.push_back(s.m_value);
|
|
||||||
hack::log()(res);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "plugins/raw_data/raw_data.hpp" // IWYU pragma: keep
|
#include "plugins/raw_data/raw_data.hpp" // IWYU pragma: keep
|
||||||
#include "plugins/magnitude/magnitude.hpp" // IWYU pragma: keep
|
#include "plugins/magnitude/magnitude.hpp" // IWYU pragma: keep
|
||||||
|
#include "plugins/fft/fft.hpp" // IWYU pragma: keep
|
||||||
|
|
||||||
namespace hr
|
namespace hr
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ headers = [
|
|||||||
# plugins
|
# plugins
|
||||||
'plugins/raw_data/raw_data.hpp',
|
'plugins/raw_data/raw_data.hpp',
|
||||||
'plugins/magnitude/magnitude.hpp',
|
'plugins/magnitude/magnitude.hpp',
|
||||||
|
'plugins/fft/fft.hpp',
|
||||||
|
|
||||||
'harmonica.hpp'
|
'harmonica.hpp'
|
||||||
]
|
]
|
||||||
@@ -30,6 +31,7 @@ sources = [
|
|||||||
# plugins
|
# plugins
|
||||||
'plugins/raw_data/raw_data.cpp',
|
'plugins/raw_data/raw_data.cpp',
|
||||||
'plugins/magnitude/magnitude.cpp',
|
'plugins/magnitude/magnitude.cpp',
|
||||||
|
'plugins/fft/fft.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
lib = library(
|
lib = library(
|
||||||
|
|||||||
50
src/plugins/fft/fft.cpp
Normal file
50
src/plugins/fft/fft.cpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#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 элементов.
|
||||||
|
m_frames = m_setup.m_step_size + 1;
|
||||||
|
m_result.m_grad.reserve(m_frames);
|
||||||
|
for (size_t i = 0; i < m_frames; ++i)
|
||||||
|
m_result.m_grad.push_back(static_cast<float>(i) * m_setup.m_sample_rate / m_setup.m_block_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fft::process(fvec_t& base, real_time timestamp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void fft::process(cvec_t& fft, fvec_t& base, real_time timestamp)
|
||||||
|
{
|
||||||
|
result::bit b;
|
||||||
|
b.m_name = "Amplitudes";
|
||||||
|
b.m_duration = timestamp;
|
||||||
|
b.m_values.reserve(m_frames);
|
||||||
|
for (size_t i = 0; i < m_frames; ++i)
|
||||||
|
{
|
||||||
|
// Конвертация в децибелы
|
||||||
|
auto a = fft.m_norm[i];
|
||||||
|
if (a > 0.000001f) a = 20.0f * log10(a);
|
||||||
|
else a = -120.0f; // Минимальное значение для логарифмической шкалы
|
||||||
|
b.m_values.push_back(a);
|
||||||
|
}
|
||||||
|
m_result.set_bit(0, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
result fft::get_result()
|
||||||
|
{
|
||||||
|
return m_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/plugins/fft/fft.hpp
Normal file
22
src/plugins/fft/fft.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#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;
|
||||||
|
std::size_t m_frames;
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,13 @@ namespace hr
|
|||||||
{
|
{
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
real_time m_duration;
|
real_time m_duration;
|
||||||
|
// когда в расчете только одно значение. да может быть и нужно это использовать как
|
||||||
|
// массив с индексом 0 типа m_values[0], но как-то вот так. Потому как отрисовка графиков тот еще праздник...
|
||||||
|
// конечно в боевой задаче это можно и нужно оптимизировать, но в данном случае для вывода на экран и понимания процесса
|
||||||
|
// это можно опустить и использовать так как есть...
|
||||||
base_t m_value;
|
base_t m_value;
|
||||||
|
// когда у тебя получается на один бин большоймассив данных, типа расчет fft (см. комент выше)
|
||||||
|
std::vector<base_t> m_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_bit(std::size_t index, bit& b)
|
void set_bit(std::size_t index, bit& b)
|
||||||
@@ -53,5 +59,8 @@ namespace hr
|
|||||||
// если захотелось увидеть их
|
// если захотелось увидеть их
|
||||||
// Второй вектор - данные для каждой линии, т.е. именно сими биты
|
// Второй вектор - данные для каждой линии, т.е. именно сими биты
|
||||||
std::vector<std::vector<bit>> m_data;
|
std::vector<std::vector<bit>> m_data;
|
||||||
|
|
||||||
|
// иногда нужна градуировка одна и тажа для всех бинов
|
||||||
|
std::vector<base_t> m_grad;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ namespace hr
|
|||||||
int m_channels;
|
int m_channels;
|
||||||
|
|
||||||
std::filesystem::path m_file;
|
std::filesystem::path m_file;
|
||||||
|
// Количество семплов, которые обрабатываются за один раз
|
||||||
std::size_t m_block_size = 1'024;
|
std::size_t m_block_size = 1'024;
|
||||||
|
// На сколько семплов сдвигается окно при следующей обработке
|
||||||
std::size_t m_step_size = 512;
|
std::size_t m_step_size = 512;
|
||||||
|
|
||||||
std::string m_plugin_name;
|
std::string m_plugin_name;
|
||||||
|
|||||||
Reference in New Issue
Block a user