#include "AudioEngine.hpp" #include #include #include #include AudioEngine::AudioEngine(ConfigService* config, LoggerService* logger, NoteQueue* noteQueue) : config_(config), logger_(logger), noteQueue_(noteQueue) { if(audioDevice_.getDeviceCount() < 1) { std::cout << "No audio devices found" << std::endl; } if(logger_ == nullptr) std::cout << "err: logger nullptr" << std::endl; } AudioEngine::~AudioEngine() { (void)stop(); } bool AudioEngine::start() { // initialize the audio engine RtAudio::StreamParameters params; params.deviceId = audioDevice_.getDefaultOutputDevice(); params.nChannels = channels_; // we're doing two duplicate channels for pseudo-mono params.firstChannel = 0; RtAudio::StreamOptions options; options.flags = RTAUDIO_MINIMIZE_LATENCY; RtAudioErrorType status = audioDevice_.openStream(¶ms, nullptr, RTAUDIO_FLOAT32, sampleRate_, &bufferFrames_, &AudioEngine::audioCallback, this, &options); if(status != RTAUDIO_NO_ERROR) { std::cout << "Error opening RtAudio stream" << std::endl; return false; } status = audioDevice_.startStream(); if(status != RTAUDIO_NO_ERROR) { std::cout << "Error starting RtAudio stream" << std::endl; return false; } // sanity check std::string msg = "sample rate: " + std::to_string(sampleRate_) + ", buffer frames: " + std::to_string(bufferFrames_); logger_->log("AudioEngine", LogFlag::Info, msg); return true; } bool AudioEngine::stop() { if(audioDevice_.isStreamRunning()) audioDevice_.stopStream(); if(audioDevice_.isStreamOpen()) audioDevice_.closeStream(); return true; } int32_t AudioEngine::audioCallback(void* outputBuffer, void* inputBuffer, uint32_t nFrames, double, RtAudioStreamStatus status, void* userData) { // error if the callback is late if(status) static_cast(userData)->logger_->log("AudioEngine", LogFlag::Warning, "Audio buffer underflow"); return static_cast(userData)->process(static_cast(outputBuffer), static_cast(nFrames)); } int32_t AudioEngine::process(float* out, size_t nFrames) { NoteEvent noteEvent; while(noteQueue_->pop(noteEvent)) { //std::string msg = "[NoteEvent] Type: " + std::to_string(noteEvent.type) +" Velocity: " + std::to_string(noteEvent.velocity) + " Note:" + std::to_string(noteEvent.note); //logger_->log("Audio", LogFlag::Debug, msg); noteOn_ = (noteEvent.type == NoteEventType::NoteOn) ? true : false; freq_ = 440.0f * pow(2.0f, (static_cast(noteEvent.note) - 69.0f) / 12.0f); } const float twoPi = 2.0f*std::numbers::pi_v; float phaseIncrement = twoPi * freq_ / sampleRate_; for(size_t i = 0; i < nFrames; i++) { // simulate a sine wave phase_ += phaseIncrement; if(phase_ > twoPi) { phase_ -= twoPi; } float outSample = std::sin(phase_) / 4.0f * noteOn_; out[2*i] = outSample; out[2*i+1] = outSample; } return 0; }