allow audio engine to react to keyboard inputs
This commit is contained in:
@@ -75,7 +75,8 @@ struct KeymapConfig {
|
||||
if(item.getType() == libconfig::Setting::TypeString) note = std::string(item.c_str());
|
||||
|
||||
int8_t noteId = static_cast<int>(notesGroup[note]) % INT8_MAX;
|
||||
int32_t keyId = static_cast<int>(keysGroup[key]) % INT8_MAX;
|
||||
int32_t keyId = static_cast<int>(keysGroup[key]) % INT32_MAX;
|
||||
|
||||
keymap.emplace(keyId, noteId);
|
||||
}
|
||||
|
||||
|
||||
22
src/main.cpp
22
src/main.cpp
@@ -17,8 +17,20 @@ int main(int argc, char* argv[]) {
|
||||
QGuiApplication app(argc, argv);
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
|
||||
// create app objects
|
||||
ConfigService config = ConfigService("config/sonobulus.cfg");
|
||||
LoggerService logger = LoggerService(&config, "Engine");
|
||||
NoteQueue queue = NoteQueue();
|
||||
KeyboardController keyboard(&config, &logger, &queue);
|
||||
|
||||
// audio synthesizer doohickey
|
||||
AudioEngine audioEngine = AudioEngine(&config, &logger, &queue);
|
||||
audioEngine.start();
|
||||
|
||||
// attach backend gui components
|
||||
qmlRegisterType<TimerComponent>("AppDemo", 1, 0, "TimerComponent");
|
||||
engine.rootContext()->setContextProperty("keyboardController", &keyboard);
|
||||
// adds the TimerComponent type (exposed in qml as "TimerComponent") to the module named"AppDemo" (numbers mean version 1.0)
|
||||
|
||||
// load qml
|
||||
@@ -31,16 +43,6 @@ int main(int argc, char* argv[]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// create app objects
|
||||
ConfigService config = ConfigService("config/sonobulus.cfg");
|
||||
LoggerService logger = LoggerService(&config, "Engine");
|
||||
NoteQueue queue = NoteQueue();
|
||||
KeyboardController keyboard = KeyboardController(&config, &logger, &queue);
|
||||
|
||||
// audio synthesizer doohickey
|
||||
AudioEngine audioEngine = AudioEngine(&logger);
|
||||
audioEngine.start();
|
||||
|
||||
// execute app
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
#include <string>
|
||||
|
||||
AudioEngine::AudioEngine(LoggerService* logger) : logger_(logger) {
|
||||
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;
|
||||
@@ -69,6 +70,12 @@ int32_t AudioEngine::audioCallback(void* outputBuffer, void* inputBuffer, uint32
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < nFrames; i++) {
|
||||
|
||||
// simulate a sine wave
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <RtAudio.h>
|
||||
|
||||
#include "LoggerService.hpp"
|
||||
#include "ConfigService.hpp"
|
||||
#include "NoteQueue.hpp"
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
@@ -18,7 +20,7 @@ class AudioEngine {
|
||||
|
||||
public:
|
||||
|
||||
AudioEngine(LoggerService* logger);
|
||||
AudioEngine(ConfigService* config, LoggerService* logger, NoteQueue* noteQueue);
|
||||
~AudioEngine();
|
||||
|
||||
bool start();
|
||||
@@ -40,5 +42,7 @@ private:
|
||||
float phase_ = 0.0f;
|
||||
|
||||
LoggerService* logger_;
|
||||
ConfigService* config_;
|
||||
NoteQueue* noteQueue_;
|
||||
|
||||
};
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
// #include <yaml-cpp/yaml.h>
|
||||
#include <filesystem>
|
||||
|
||||
KeyboardController::KeyboardController(QObject* parent) : QObject(parent) {
|
||||
|
||||
}
|
||||
|
||||
KeyboardController::KeyboardController(ConfigService* config, LoggerService* logger, NoteQueue* queue) : config_(config), logger_(logger), queue_(queue) {
|
||||
|
||||
// load keymap from config service
|
||||
@@ -15,11 +19,10 @@ KeyboardController::KeyboardController(ConfigService* config, LoggerService* log
|
||||
|
||||
}
|
||||
|
||||
void KeyboardController::handleKeyPress(QKeyEvent* e) {
|
||||
if (e->isAutoRepeat()) return;
|
||||
void KeyboardController::keyDownEvent(int key, int modifiers, const QString& text) {
|
||||
|
||||
auto it = keymap_.find(e->key());
|
||||
if (it == keymap_.end()) return;
|
||||
auto it = configuration_.keymap.find(key);
|
||||
if (it == configuration_.keymap.end()) return;
|
||||
|
||||
queue_->push({
|
||||
NoteEventType::NoteOn,
|
||||
@@ -27,13 +30,13 @@ void KeyboardController::handleKeyPress(QKeyEvent* e) {
|
||||
0.8f,
|
||||
std::chrono::high_resolution_clock::now()
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void KeyboardController::handleKeyRelease(QKeyEvent* e) {
|
||||
if (e->isAutoRepeat()) return;
|
||||
void KeyboardController::keyUpEvent(int key, int modifiers, const QString& text) {
|
||||
|
||||
auto it = keymap_.find(e->key());
|
||||
if (it == keymap_.end()) return;
|
||||
auto it = configuration_.keymap.find(key);
|
||||
if (it == configuration_.keymap.end()) return;
|
||||
|
||||
queue_->push({
|
||||
NoteEventType::NoteOff,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// the keyboard controller acts as an instrument input device for creating note events from a computer keyboard
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QKeyEvent>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -10,14 +11,17 @@
|
||||
#include "LoggerService.hpp"
|
||||
|
||||
// The keyboardcontroller handles user inputs from a keyboard and maps them to note events
|
||||
class KeyboardController {
|
||||
class KeyboardController : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit KeyboardController(ConfigService* config, LoggerService* logger, NoteQueue* queue);
|
||||
explicit KeyboardController(QObject* parent = nullptr);
|
||||
KeyboardController(ConfigService* config, LoggerService* logger, NoteQueue* queue);
|
||||
~KeyboardController() = default;
|
||||
|
||||
void handleKeyPress(QKeyEvent* e);
|
||||
void handleKeyRelease(QKeyEvent* e);
|
||||
Q_INVOKABLE void keyDownEvent(int key, int modifiers, const QString& text);
|
||||
Q_INVOKABLE void keyUpEvent(int key, int modifiers, const QString& text);
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,8 +30,6 @@ private:
|
||||
LoggerService* logger_;
|
||||
|
||||
// keymap is key -> midi note id
|
||||
std::unordered_map<int32_t, uint8_t> keymap_;
|
||||
|
||||
KeymapConfig configuration_;
|
||||
|
||||
};
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
#define SYNTH_NOTE_QUEUE_SIZE 128
|
||||
|
||||
enum class NoteEventType {
|
||||
NoteOn,
|
||||
enum NoteEventType {
|
||||
NoteOn = 0,
|
||||
NoteOff
|
||||
};
|
||||
|
||||
|
||||
19
ui/Main.qml
19
ui/Main.qml
@@ -30,4 +30,23 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if(!event.isAutoRepeat) {
|
||||
keyboardController.keyDownEvent(event.key, event.modifiers, event.text)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReleased: (event) => {
|
||||
if(!event.isAutoRepeat) {
|
||||
keyboardController.keyUpEvent(event.key, event.modifiers, event.text)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user