add audio generate and audio example

This commit is contained in:
2025-08-31 12:02:29 +03:00
parent e217920fe8
commit 7832b2095b
9 changed files with 99 additions and 12 deletions

1
.gitignore vendored
View File

@@ -2,4 +2,5 @@ build
.cache .cache
subprojects/* subprojects/*
!subprojects/catch2.wrap !subprojects/catch2.wrap
bin/test

View File

@@ -1,6 +1,10 @@
#include <vector> #include <vector>
#include <forward_list> #include <forward_list>
#include "hack/audio/generate.hpp"
#include "hack/audio/play.hpp"
#include "hack/audio/save.hpp"
#include "hack/logger/logger.hpp" #include "hack/logger/logger.hpp"
#include "hack/range/sort.hpp" #include "hack/range/sort.hpp"
@@ -14,6 +18,28 @@
auto main(int argc, char *argv[]) -> int auto main(int argc, char *argv[]) -> int
{ {
{
int sample_rate = 44100;
// Воспроизведение последовательности нот
hack::warn()("Пример использования: audio");
std::vector<double> frequencies = { 130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94 };
std::vector<double> melody;
for (double freq : frequencies)
{
auto note = hack::audio::generate::sine(freq, 0.3, sample_rate);
melody.insert(melody.end(), note.begin(), note.end());
// Добавляем небольшую паузу между нотами. Т.е. вставляем кол-во с нулевым значением.
melody.insert(melody.end(), sample_rate * 0.05, 0.0);
}
hack::log()("Воспроизведение последовательности нот...");
hack::audio::play(melody, sample_rate);
hack::log()("Запись последовательности нот в файл");
hack::audio::save("/mnt/raid/projects/hack/hack/bin/test/note.wav", melody, sample_rate);
}
// patterns::ring_buffer // patterns::ring_buffer
{ {
hack::patterns::ring_buffer<int> rb; hack::patterns::ring_buffer<int> rb;
@@ -55,8 +81,8 @@ auto main(int argc, char *argv[]) -> int
hack::log()(v); hack::log()(v);
hack::log()(l); hack::log()(l);
// hack::range::save_to_file("/mnt/raid/projects/hack/hack/test.txt", v); hack::range::save_to_file("/mnt/raid/projects/hack/hack/bin/test/range.txt", v);
// hack::range::save_to_file("/mnt/raid/projects/hack/hack/test.txt", v, ":"); hack::range::save_to_file("/mnt/raid/projects/hack/hack/bin/test/range.delemiter.txt", v, ":");
} }
// math::max // math::max

View File

@@ -31,6 +31,7 @@ args = []
inc = [] inc = []
deps = [ deps = [
dependency('uuid'), dependency('uuid'),
dependency('sndfile'),
dependency('portaudio-2.0', required: true) dependency('portaudio-2.0', required: true)
] ]

View File

@@ -0,0 +1,56 @@
#pragma once
#include <vector>
#include <math.h>
// Генерация разнообразных звуковых волн
namespace hack::audio::generate
{
// Генерация синусоидального сигнала
inline std::vector<double> sine(double frequency, double duration, int sample_rate)
{
std::vector<double> samples;
int total_samples = static_cast<int>(duration * sample_rate);
for (int i = 0; i < total_samples; ++i)
{
double time = static_cast<double>(i) / sample_rate;
double sample = 0.5 * std::sin(2.0 * M_PI * frequency * time);
samples.push_back(sample);
}
return samples;
}
// Генерация прямоугольного сигнала
inline std::vector<double> square_wave(double frequency, double duration, int sample_rate)
{
std::vector<double> samples;
int total_samples = static_cast<int>(duration * sample_rate);
int samples_per_period = sample_rate / frequency;
for (int i = 0; i < total_samples; ++i)
{
double sample = ((i / samples_per_period) % 2 == 0) ? 0.5 : -0.5;
samples.push_back(sample);
}
return samples;
}
// Генерация белого шума
inline std::vector<double> white_noise(double duration, int sample_rate)
{
std::vector<double> samples;
int total_samples = static_cast<int>(duration * sample_rate);
for (int i = 0; i < total_samples; ++i)
{
double sample = (static_cast<double>(rand()) / RAND_MAX) * 2.0 - 1.0;
samples.push_back(sample * 0.3); // Уменьшаем громкость
}
return samples;
}
}

View File

@@ -1,13 +1,13 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include "hack/logger/logger.hpp"
#include <portaudio.h> #include <portaudio.h>
#include "hack/logger/logger.hpp"
namespace hack::audio namespace hack::audio
{ {
// namespace namespace
// { {
const int FRAMES_PER_BUFFER = 256; const int FRAMES_PER_BUFFER = 256;
// callback - вызывается, когда нужны новые аудио-данные // callback - вызывается, когда нужны новые аудио-данные
@@ -26,7 +26,7 @@ namespace hack::audio
return (pos >= samples.size()) ? paComplete : paContinue; return (pos >= samples.size()) ? paComplete : paContinue;
} }
// } }
// пока только wav // пока только wav
inline void play(std::vector<double>& samples, int sample_rate) inline void play(std::vector<double>& samples, int sample_rate)

View File

@@ -34,5 +34,3 @@ namespace hack::audio
sf_close(outfile); sf_close(outfile);
} }
} }

View File

@@ -5,12 +5,15 @@
#include <iostream> #include <iostream>
#include "hack/logger/logger.hpp" #include "hack/logger/logger.hpp"
// Записывает массив в файл с указанным разделителем
namespace hack::range namespace hack::range
{ {
namespace { namespace {
template<typename T> template<typename T>
void save_to_file_impl(const std::filesystem::path& p, T& v, std::string delemiter = ", ") void save_to_file_impl(const std::filesystem::path& p, T& v, std::string delemiter = ", ")
{ {
// Создаем директорию, если ее нет.
std::filesystem::create_directories(p.parent_path());
std::ofstream file(p); std::ofstream file(p);
if (!file) if (!file)
{ {

View File

@@ -1,6 +1,11 @@
inc += include_directories('.') inc += include_directories('.')
headers = [ headers = [
'hack/audio/generate.hpp',
'hack/audio/play.hpp',
'hack/audio/save.hpp',
'hack/concepts/concepts.hpp', 'hack/concepts/concepts.hpp',
'hack/iterators/associative_ostream_iterator.hpp', 'hack/iterators/associative_ostream_iterator.hpp',
@@ -18,12 +23,10 @@ headers = [
'hack/utils/color.hpp' 'hack/utils/color.hpp'
] ]
sources = []
lib = library( lib = library(
meson.project_name(), meson.project_name(),
include_directories : inc, include_directories : inc,
sources: [headers, sources], sources: [headers],
dependencies : deps, dependencies : deps,
cpp_args: args cpp_args: args
) )

View File

@@ -1 +0,0 @@
1, 2, 3, 4, 4, 4, 6