sync
This commit is contained in:
@@ -10,7 +10,7 @@ Logger = (
|
|||||||
"Error"
|
"Error"
|
||||||
);
|
);
|
||||||
|
|
||||||
ShowTime = true;
|
ShowTime = false;
|
||||||
ShowSourceTrace = false;
|
ShowSourceTrace = false;
|
||||||
CoutEnabled = true;
|
CoutEnabled = true;
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ int main(int argc, char* argv[]) {
|
|||||||
// create app objects
|
// create app objects
|
||||||
ConfigService config = ConfigService("config/sonobulus.cfg");
|
ConfigService config = ConfigService("config/sonobulus.cfg");
|
||||||
LoggerService logger = LoggerService(&config, "Engine");
|
LoggerService logger = LoggerService(&config, "Engine");
|
||||||
NoteQueue queue = NoteQueue();
|
NoteQueue queue = NoteQueue(&config, &logger);
|
||||||
ScopeBuffer scopeBuffer = ScopeBuffer(512);
|
ScopeBuffer scopeBuffer = ScopeBuffer(&config, &logger, 2048);
|
||||||
KeyboardController keyboard(&config, &logger, &queue);
|
KeyboardController keyboard(&config, &logger, &queue);
|
||||||
MidiController midi(&config, &logger, &queue);
|
MidiController midi(&config, &logger, &queue);
|
||||||
Synth synth(&config, &logger, &scopeBuffer, &queue);
|
Synth synth(&config, &logger, &scopeBuffer, &queue);
|
||||||
@@ -43,7 +43,7 @@ int main(int argc, char* argv[]) {
|
|||||||
engine.load(QUrl::fromLocalFile("ui/Main.qml")); // ugh
|
engine.load(QUrl::fromLocalFile("ui/Main.qml")); // ugh
|
||||||
|
|
||||||
if(engine.rootObjects().isEmpty()) {
|
if(engine.rootObjects().isEmpty()) {
|
||||||
std::cout << "engine is empty" << std::endl;
|
logger.log("Main", LogFlag::Error, "Engine is empty.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,8 @@
|
|||||||
AudioEngine::AudioEngine(ConfigService* config, LoggerService* logger, Synth* synth) : config_(config), logger_(logger), synth_(synth) {
|
AudioEngine::AudioEngine(ConfigService* config, LoggerService* logger, Synth* synth) : config_(config), logger_(logger), synth_(synth) {
|
||||||
|
|
||||||
if(audioDevice_.getDeviceCount() < 1) {
|
if(audioDevice_.getDeviceCount() < 1) {
|
||||||
std::cout << "No audio devices found" << std::endl;
|
logger_->log("Audio", LogFlag::Error, "No audio devices found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(logger_ == nullptr) std::cout << "err: logger nullptr" << std::endl;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioEngine::~AudioEngine() {
|
AudioEngine::~AudioEngine() {
|
||||||
@@ -33,13 +30,13 @@ bool AudioEngine::start() {
|
|||||||
|
|
||||||
RtAudioErrorType status = audioDevice_.openStream(¶ms, nullptr, RTAUDIO_FLOAT32, sampleRate_, &bufferFrames_, &AudioEngine::audioCallback, this, &options);
|
RtAudioErrorType status = audioDevice_.openStream(¶ms, nullptr, RTAUDIO_FLOAT32, sampleRate_, &bufferFrames_, &AudioEngine::audioCallback, this, &options);
|
||||||
if(status != RTAUDIO_NO_ERROR) {
|
if(status != RTAUDIO_NO_ERROR) {
|
||||||
std::cout << "Error opening RtAudio stream" << std::endl;
|
logger_->log("Audio", LogFlag::Error, "Error opening RtAudio stream.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = audioDevice_.startStream();
|
status = audioDevice_.startStream();
|
||||||
if(status != RTAUDIO_NO_ERROR) {
|
if(status != RTAUDIO_NO_ERROR) {
|
||||||
std::cout << "Error starting RtAudio stream" << std::endl;
|
logger_->log("Audio", LogFlag::Error, "Error starting RtAudio stream.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,17 +30,19 @@ float Instrument::process(bool& scopeTrigger) {
|
|||||||
if(active_ && envelope_ < 1.0f) envelope_ += 0.01f;
|
if(active_ && envelope_ < 1.0f) envelope_ += 0.01f;
|
||||||
if(!active_ && envelope_ > 0.0f) envelope_ -= 0.0004f;
|
if(!active_ && envelope_ > 0.0f) envelope_ -= 0.0004f;
|
||||||
|
|
||||||
|
if(!isActive()) return 0.0f;
|
||||||
|
|
||||||
phase_ += phaseIncrement_;
|
phase_ += phaseIncrement_;
|
||||||
if(phase_ > 2.0f * pi) {
|
if(phase_ > 2.0f * pi) {
|
||||||
phase_ -= 2.0f * pi;
|
phase_ -= 2.0f * pi;
|
||||||
scopeTrigger = true;
|
scopeTrigger = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isActive()) return 0.0f;
|
|
||||||
|
|
||||||
// float sample = sin(phase_);
|
// float sample = sin(phase_);
|
||||||
float sample = phase_ / pi - 1.0f; // saw
|
targetSample = phase_ / pi - 1.0f; // saw
|
||||||
|
|
||||||
return sample * envelope_;
|
currentSample = (1.0f - responsiveness_) * currentSample + responsiveness_ * targetSample;
|
||||||
|
|
||||||
|
return currentSample * envelope_;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,4 +34,8 @@ private:
|
|||||||
float phaseIncrement_ = 0.0f;
|
float phaseIncrement_ = 0.0f;
|
||||||
float envelope_ = 0.0f;
|
float envelope_ = 0.0f;
|
||||||
|
|
||||||
|
float targetSample = 0.0f;
|
||||||
|
float currentSample = 0.0f;
|
||||||
|
static constexpr float responsiveness_ = 0.1f;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ MidiController::MidiController(ConfigService* config, LoggerService* logger, Not
|
|||||||
#endif
|
#endif
|
||||||
midiIn_->ignoreTypes(false, false, false);
|
midiIn_->ignoreTypes(false, false, false);
|
||||||
} catch (RtMidiError& e) {
|
} catch (RtMidiError& e) {
|
||||||
std::cout << "RtMidi init failed: " << e.getMessage() << std::endl;
|
std::string msg = "RtMidi init failed: " + e.getMessage();
|
||||||
|
logger_->log("MIDI", LogFlag::Warning, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
openDefaultPort();
|
openDefaultPort();
|
||||||
@@ -25,18 +26,21 @@ MidiController::~MidiController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// open the first for thats successful
|
// open the first for thats successful
|
||||||
|
// we could also add an option in the config for a preferred port name
|
||||||
bool MidiController::openDefaultPort() {
|
bool MidiController::openDefaultPort() {
|
||||||
if (!midiIn_) return false;
|
if (!midiIn_) return false;
|
||||||
if (midiIn_->getPortCount() == 0) {
|
if (midiIn_->getPortCount() == 0) {
|
||||||
std::cout << "No MIDI input ports available" << std::endl;
|
logger_->log("MIDI", LogFlag::Warning, "No MIDI input ports available.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: the ui will eventually need this class to expose the available midi ports so they can be chosen dynamically
|
||||||
uint32_t portCount = midiIn_->getPortCount();
|
uint32_t portCount = midiIn_->getPortCount();
|
||||||
std::cout << "Available MidiIn ports: " << portCount << std::endl;
|
std::string msg = "Available MidiIn ports: " + std::to_string(portCount);
|
||||||
|
logger_->log("MIDI", LogFlag::Info, msg);
|
||||||
for (int i = 0; i < portCount; i++) {
|
for (int i = 0; i < portCount; i++) {
|
||||||
std::cout << "#" << i << " : " << midiIn_->getPortName(i) << std::endl;
|
msg = "\t#" + std::to_string(i) + " : " + midiIn_->getPortName(i);
|
||||||
|
logger_->log("MIDI", LogFlag::Info, msg);
|
||||||
if(openPort(i)) return true;
|
if(openPort(i)) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,11 +53,13 @@ bool MidiController::openPort(unsigned int index) {
|
|||||||
try {
|
try {
|
||||||
midiIn_->openPort(index);
|
midiIn_->openPort(index);
|
||||||
midiIn_->setCallback(&MidiController::midiCallback, this);
|
midiIn_->setCallback(&MidiController::midiCallback, this);
|
||||||
std::cout << "Opened MIDI port: " << midiIn_->getPortName(index) << std::endl;
|
|
||||||
|
std::string msg = "Opened MIDI port: " + midiIn_->getPortName(index);
|
||||||
|
logger_->log("MIDI", LogFlag::Info, msg);
|
||||||
return true;
|
return true;
|
||||||
} catch (RtMidiError& e) {
|
} catch (RtMidiError& e) {
|
||||||
std::cout << "Midi Port error" << std::endl;
|
std::string msg = "Midi Port error: " + e.getMessage();
|
||||||
std::cerr << e.getMessage() << std::endl;
|
logger_->log("MIDI", LogFlag::Error, msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,15 @@
|
|||||||
#include "NoteQueue.hpp"
|
#include "NoteQueue.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
NoteQueue::NoteQueue() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteQueue::NoteQueue(ConfigService* config, LoggerService* logger) :
|
||||||
|
config_(config), logger_(logger) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// add event to noteQueue, called by MidiController or keyboardController
|
// add event to noteQueue, called by MidiController or keyboardController
|
||||||
bool NoteQueue::push(const NoteEvent& event) {
|
bool NoteQueue::push(const NoteEvent& event) {
|
||||||
size_t head = head_.load(std::memory_order_relaxed);
|
size_t head = head_.load(std::memory_order_relaxed);
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "ConfigService.hpp"
|
||||||
|
#include "LoggerService.hpp"
|
||||||
|
|
||||||
enum NoteEventType {
|
enum NoteEventType {
|
||||||
NoteOn = 0,
|
NoteOn = 0,
|
||||||
NoteOff
|
NoteOff
|
||||||
@@ -22,7 +25,8 @@ struct NoteEvent {
|
|||||||
class NoteQueue {
|
class NoteQueue {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NoteQueue() = default;
|
NoteQueue();
|
||||||
|
NoteQueue(ConfigService* config, LoggerService* logger);
|
||||||
~NoteQueue() = default;
|
~NoteQueue() = default;
|
||||||
|
|
||||||
bool push(const NoteEvent& event);
|
bool push(const NoteEvent& event);
|
||||||
@@ -30,7 +34,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static constexpr size_t SYNTH_NOTE_QUEUE_SIZE = 128;
|
ConfigService* config_;
|
||||||
|
LoggerService* logger_;
|
||||||
|
|
||||||
|
static constexpr size_t SYNTH_NOTE_QUEUE_SIZE = 128; // TODO: config
|
||||||
|
|
||||||
std::array<NoteEvent, SYNTH_NOTE_QUEUE_SIZE> buffer_;
|
std::array<NoteEvent, SYNTH_NOTE_QUEUE_SIZE> buffer_;
|
||||||
std::atomic<size_t> head_{ 0 };
|
std::atomic<size_t> head_{ 0 };
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ ScopeBuffer::ScopeBuffer(QObject *parent) : QObject(parent) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeBuffer::ScopeBuffer(size_t size) : buffer_(size) {
|
ScopeBuffer::ScopeBuffer(ConfigService* config, LoggerService* logger, size_t size) :
|
||||||
|
config_(config), logger_(logger), buffer_(size) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "ConfigService.hpp"
|
||||||
|
#include "LoggerService.hpp"
|
||||||
|
|
||||||
class ScopeBuffer : public QObject {
|
class ScopeBuffer : public QObject {
|
||||||
|
|
||||||
Q_OBJECT // needed to attach to a qml component
|
Q_OBJECT // needed to attach to a qml component
|
||||||
@@ -15,7 +18,7 @@ class ScopeBuffer : public QObject {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
explicit ScopeBuffer(QObject* parent = nullptr);
|
explicit ScopeBuffer(QObject* parent = nullptr);
|
||||||
ScopeBuffer(size_t size);
|
ScopeBuffer(ConfigService* config, LoggerService* logger, size_t size);
|
||||||
~ScopeBuffer() = default;
|
~ScopeBuffer() = default;
|
||||||
|
|
||||||
void push(float sample);
|
void push(float sample);
|
||||||
@@ -31,6 +34,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
ConfigService* config_;
|
||||||
|
LoggerService* logger_;
|
||||||
|
|
||||||
std::vector<float> buffer_;
|
std::vector<float> buffer_;
|
||||||
std::atomic<size_t> writeIndex_{0};
|
std::atomic<size_t> writeIndex_{0};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user