2024-01-30 18:09:57 +00:00
|
|
|
#include "AudioEngine.hpp"
|
|
|
|
#include "Signal.hpp"
|
|
|
|
|
|
|
|
namespace muz
|
|
|
|
{
|
|
|
|
/*explicit*/ AudioEngine::AudioEngine(AudioConf const& conf)
|
|
|
|
: m_conf { conf }
|
2024-02-01 03:15:07 +00:00
|
|
|
, m_frame { std::vector<float>(m_conf.channels(), 0.0f) }
|
2024-01-30 18:09:57 +00:00
|
|
|
{
|
|
|
|
check_error(Pa_Initialize());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/ AudioEngine::~AudioEngine()
|
|
|
|
{
|
|
|
|
check_error(Pa_Terminate());
|
|
|
|
}
|
|
|
|
|
|
|
|
void AudioEngine::init()
|
|
|
|
{
|
|
|
|
PaError err = Pa_OpenDefaultStream(&m_stream,
|
|
|
|
0 /*input*/,
|
|
|
|
m_conf.channels() /*output*/,
|
|
|
|
paFloat32,
|
|
|
|
m_conf.samplerate(),
|
|
|
|
m_conf.frames_per_buffer() ,
|
|
|
|
&AudioEngine::callback,
|
|
|
|
this);
|
|
|
|
check_error(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AudioEngine::run()
|
|
|
|
{
|
|
|
|
if (!m_stream)
|
|
|
|
{
|
|
|
|
throw audio_error {"audio engine not initialized"};
|
|
|
|
}
|
|
|
|
|
|
|
|
Pa_StartStream(m_stream);
|
|
|
|
|
|
|
|
while (!m_sig_queue.empty())
|
|
|
|
{
|
|
|
|
std::cin.get();
|
|
|
|
pop_signal();
|
|
|
|
}
|
|
|
|
|
|
|
|
Pa_StopStream(m_stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AudioEngine::push_signal(std::unique_ptr<Signal> signal)
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> mtx(m_sig_mtx);
|
|
|
|
|
|
|
|
m_sig_queue.push_back(std::move(signal));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AudioEngine::pop_signal()
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> mtx(m_sig_mtx);
|
|
|
|
|
|
|
|
if (!m_sig_queue.empty())
|
|
|
|
{
|
|
|
|
m_sig_queue.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AudioEngine::check_error(PaError err)
|
|
|
|
{
|
|
|
|
if (err != paNoError)
|
|
|
|
{
|
|
|
|
std::string msg = Pa_GetErrorText(err);
|
|
|
|
throw audio_error {"cannot initalize portaudio: " + msg};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<float> AudioEngine::next()
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> mtx(m_sig_mtx);
|
|
|
|
|
|
|
|
if (m_sig_queue.empty())
|
|
|
|
{
|
|
|
|
return {0.0f, 0.0f};
|
|
|
|
}
|
|
|
|
|
2024-02-01 03:15:07 +00:00
|
|
|
m_sig_queue.back()->next(m_frame);
|
2024-01-30 18:09:57 +00:00
|
|
|
|
2024-02-01 03:15:07 +00:00
|
|
|
return m_frame;
|
2024-01-30 18:09:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ int AudioEngine::callback(void const*, void* output,
|
|
|
|
unsigned long frames_per_buffer,
|
|
|
|
PaStreamCallbackTimeInfo const*,
|
|
|
|
PaStreamCallbackFlags,
|
|
|
|
void* data)
|
|
|
|
{
|
|
|
|
AudioEngine* engine = static_cast<AudioEngine*>(data);
|
|
|
|
float* out = static_cast<float*>(output);
|
|
|
|
size_t k = 0;
|
|
|
|
|
|
|
|
for (size_t i=0; i<frames_per_buffer; i++)
|
|
|
|
{
|
2024-02-01 03:15:07 +00:00
|
|
|
auto const& frame = engine->next();
|
2024-01-30 18:09:57 +00:00
|
|
|
|
|
|
|
for (float val: frame)
|
|
|
|
{
|
|
|
|
out[k++] = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return paContinue;
|
|
|
|
}
|
|
|
|
}
|