add play and save audio
This commit is contained in:
@@ -62,4 +62,6 @@ auto main(int argc, char *argv[]) -> int
|
|||||||
hack::log()(hack::math::max(4, 5));
|
hack::log()(hack::math::max(4, 5));
|
||||||
hack::log()(hack::math::max(c, b));
|
hack::log()(hack::math::max(c, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hack::warn()("TEST_WARN");
|
||||||
}
|
}
|
||||||
|
|||||||
76
src/hack/audio/play.hpp
Normal file
76
src/hack/audio/play.hpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "hack/logger/logger.hpp"
|
||||||
|
#include <portaudio.h>
|
||||||
|
|
||||||
|
namespace hack::utils
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const int FRAMES_PER_BUFFER = 256;
|
||||||
|
|
||||||
|
// callback - вызывается, когда нужны новые аудио-данные
|
||||||
|
static int callback(const void*, void* output_buffer, unsigned long frames, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void* data)
|
||||||
|
{
|
||||||
|
auto& samples = *static_cast<std::vector<double>*>(data);
|
||||||
|
static size_t pos = 0;
|
||||||
|
auto* out = static_cast<float*>(output_buffer);
|
||||||
|
|
||||||
|
for (unsigned long i = 0; i < frames; ++i)
|
||||||
|
{
|
||||||
|
// передаем даннеы если есть, иначе - тишина.
|
||||||
|
if (pos < samples.size()) out[i] = static_cast<float>(samples[pos++]);
|
||||||
|
else out[i] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pos >= samples.size()) ? paComplete : paContinue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// пока только wav
|
||||||
|
inline void play(std::vector<double>& samples, int sample_rate)
|
||||||
|
{
|
||||||
|
PaError err = Pa_Initialize();
|
||||||
|
if (err != paNoError)
|
||||||
|
{
|
||||||
|
hack::error()("PortAudio error: ", Pa_GetErrorText(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// открытие потока
|
||||||
|
PaStream* stream;
|
||||||
|
err = Pa_OpenDefaultStream(&stream,
|
||||||
|
0, // Нет входных каналов
|
||||||
|
1, // 1 выходной канал (моно)
|
||||||
|
paFloat32, // 32-bit floating-point output
|
||||||
|
sample_rate,
|
||||||
|
FRAMES_PER_BUFFER,
|
||||||
|
callback,
|
||||||
|
samples.data());
|
||||||
|
|
||||||
|
if (err != paNoError)
|
||||||
|
{
|
||||||
|
std::cerr << "PortAudio error: " << Pa_GetErrorText(err) << std::endl;
|
||||||
|
Pa_Terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// запуск потока
|
||||||
|
err = Pa_StartStream(stream);
|
||||||
|
if (err != paNoError)
|
||||||
|
{
|
||||||
|
std::cerr << "PortAudio error: " << Pa_GetErrorText(err) << std::endl;
|
||||||
|
Pa_CloseStream(stream);
|
||||||
|
Pa_Terminate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ждём окончания воспроизведения
|
||||||
|
while (Pa_IsStreamActive(stream)) Pa_Sleep(100); // Пауза 100 мс между проверками
|
||||||
|
|
||||||
|
// очистка
|
||||||
|
Pa_CloseStream(stream);
|
||||||
|
Pa_Terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
namespace hack::utils
|
namespace hack::utils
|
||||||
{
|
{
|
||||||
inline void save_wav(const std::string& path, const std::vector<float>& samples, int sample_rate)
|
// пока только wav
|
||||||
|
inline void save(const std::string& path, const std::vector<float>& samples, int sample_rate)
|
||||||
{
|
{
|
||||||
SF_INFO sf_info;
|
SF_INFO sf_info;
|
||||||
sf_info.samplerate = sample_rate;
|
sf_info.samplerate = sample_rate;
|
||||||
@@ -34,3 +35,4 @@ namespace hack::utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user