#include "AudioEngine.hpp" #include "Signal.hpp" namespace muz { /*explicit*/ AudioEngine::AudioEngine(AudioConf const& conf) : m_conf { conf } { 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) { std::lock_guard mtx(m_sig_mtx); m_sig_queue.push_back(std::move(signal)); } void AudioEngine::pop_signal() { std::lock_guard 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 AudioEngine::next() { std::lock_guard mtx(m_sig_mtx); if (m_sig_queue.empty()) { return {0.0f, 0.0f}; } auto frame = m_sig_queue.back()->next(); if (frame.empty()) { pop_signal(); return next(); } return frame; } /*static*/ int AudioEngine::callback(void const*, void* output, unsigned long frames_per_buffer, PaStreamCallbackTimeInfo const*, PaStreamCallbackFlags, void* data) { AudioEngine* engine = static_cast(data); float* out = static_cast(output); size_t k = 0; for (size_t i=0; inext(); for (float val: frame) { out[k++] = val; } } return paContinue; } }