#include "AudioEngine.h" #include AudioEngine::AudioEngine() : synth_(params_) { if(audio_.getDeviceCount() < 1) { throw std::runtime_error("No audio devices found"); } // TODO: get audio configurations synth_.setSampleRate(sampleRate_); synth_.setScopeBuffer(&scope_); } AudioEngine::~AudioEngine() { stop(); } bool AudioEngine::start() { // initialize the audio engine RtAudio::StreamParameters params; params.deviceId = audio_.getDefaultOutputDevice(); params.nChannels = channels_; // we're doing two duplicate channels for pseudo-mono params.firstChannel = 0; RtAudio::StreamOptions options; options.flags = RTAUDIO_MINIMIZE_LATENCY; // TODO: error check this please audio_.openStream(¶ms, nullptr, RTAUDIO_FLOAT32, sampleRate_, &bufferFrames_, &AudioEngine::audioCallback, this, &options); audio_.startStream(); // sanity check std::cout << "sample rate: " << sampleRate_ << " buffer frames: " << bufferFrames_ << std::endl; return true; } void AudioEngine::stop() { if(audio_.isStreamRunning()) audio_.stopStream(); if(audio_.isStreamOpen()) audio_.closeStream(); } int32_t AudioEngine::audioCallback( void* outputBuffer, void*, uint32_t nFrames, double, RtAudioStreamStatus status, void* userData) { // error if process is too slow for the callback. If this is consistent, then need to optimize synth.process() or whatever cascades from it if (status) std::cerr << "Stream underflow" << std::endl; return static_cast(userData)->process(static_cast(outputBuffer), nFrames); } int32_t AudioEngine::process(float* out, uint32_t nFrames) { // pass note handling to synth NoteEvent event; while(noteQueue_.pop(event)) { synth_.handleNoteEvent(event); } // pass sample generation to synth synth_.process(out, nFrames, sampleRate_); return 0; }