add audio generate and audio example
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,4 +2,5 @@ build
|
|||||||
.cache
|
.cache
|
||||||
subprojects/*
|
subprojects/*
|
||||||
!subprojects/catch2.wrap
|
!subprojects/catch2.wrap
|
||||||
|
bin/test
|
||||||
|
|
||||||
|
|||||||
30
bin/main.cpp
30
bin/main.cpp
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
56
src/hack/audio/generate.hpp
Normal file
56
src/hack/audio/generate.hpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -34,5 +34,3 @@ namespace hack::audio
|
|||||||
sf_close(outfile);
|
sf_close(outfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user