prelim midi controller

This commit is contained in:
2025-12-29 00:44:43 -06:00
parent c045337fba
commit 4c6ec3a019
6 changed files with 144 additions and 4 deletions

View File

@@ -33,9 +33,28 @@ if (WIN32) # windows 11 x86_64
# Public alias (this is where :: belongs) # Public alias (this is where :: belongs)
add_library(RtAudio::RtAudio ALIAS rtaudio) add_library(RtAudio::RtAudio ALIAS rtaudio)
add_library(rtmidi_headers INTERFACE)
target_include_directories(rtmidi_headers INTERFACE
"C:/rtmidi/include"
"C:/rtmidi/include/rtMidi"
)
add_library(rtmidi_binary SHARED IMPORTED)
set_target_properties(rtmidi_binary PROPERTIES
IMPORTED_LOCATION "C:/rtmidi/bin/rtmidi.dll"
IMPORTED_IMPLIB "C:/rtmidi/lib/rtmidi.lib"
)
add_library(rtmidi INTERFACE)
target_link_libraries(rtmidi INTERFACE
rtmidi_headers
rtmidi_binary
)
add_library(RtMidi::RtMidi ALIAS rtmidi)
else() # debian 12 x86_64 else() # debian 12 x86_64
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(RTAUDIO REQUIRED rtaudio) pkg_check_modules(RTAUDIO REQUIRED rtaudio)
pkg_check_modules(RTMIDI REQUIRED rtmidi)
endif() endif()
qt_standard_project_setup() qt_standard_project_setup()
@@ -49,6 +68,8 @@ qt_add_executable(metabolus
src/ParameterStore.h src/ParameterStore.h
src/KeyboardController.cpp src/KeyboardController.cpp
src/KeyboardController.h src/KeyboardController.h
src/MidiController.cpp
src/MidiController.h
src/NoteQueue.cpp src/NoteQueue.cpp
src/NoteQueue.h src/NoteQueue.h
src/synth/AudioEngine.cpp src/synth/AudioEngine.cpp
@@ -89,6 +110,7 @@ if (WIN32)
PRIVATE PRIVATE
Qt6::Widgets Qt6::Widgets
RtAudio::RtAudio RtAudio::RtAudio
RtMidi::RtMidi
) )
add_custom_command(TARGET metabolus POST_BUILD add_custom_command(TARGET metabolus POST_BUILD
@@ -97,8 +119,14 @@ if (WIN32)
$<TARGET_FILE_DIR:metabolus> $<TARGET_FILE_DIR:metabolus>
) )
add_custom_command(TARGET metabolus POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"C:/rtmidi/bin/rtmidi.dll"
$<TARGET_FILE_DIR:metabolus>
)
else() else()
target_include_directories(metabolus PRIVATE ${RTAUDIO_INCLUDE_DIRS}) target_include_directories(metabolus PRIVATE ${RTAUDIO_INCLUDE_DIRS} ${RTMIDI_INCLUDE_DIRS})
target_link_libraries(metabolus PRIVATE Qt6::Widgets ${RTAUDIO_LIBRARIES}) target_link_libraries(metabolus PRIVATE Qt6::Widgets ${RTAUDIO_LIBRARIES} ${RTMIDI_LIBARARIES})
target_compile_options(metabolus PRIVATE ${RTAUDIO_CFLAGS_OTHER}) target_compile_options(metabolus PRIVATE ${RTAUDIO_CFLAGS_OTHER})
endif() endif()

View File

@@ -10,6 +10,7 @@ set CONFIG=Release
set QT_ROOT=C:\Qt\6.10.1\msvc2022_64 set QT_ROOT=C:\Qt\6.10.1\msvc2022_64
set RTAUDIO_ROOT=C:\rtaudio set RTAUDIO_ROOT=C:\rtaudio
set RTMIDI_ROOT=C:\rtmidi
REM ================================ REM ================================
REM Environment setup REM Environment setup
@@ -30,7 +31,8 @@ if not exist %BUILD_DIR% (
cmake -S . -B %BUILD_DIR% ^ cmake -S . -B %BUILD_DIR% ^
-G Ninja ^ -G Ninja ^
-DCMAKE_BUILD_TYPE=%CONFIG% ^ -DCMAKE_BUILD_TYPE=%CONFIG% ^
-DRTAUDIO_ROOT=%RTAUDIO_ROOT% -DRTAUDIO_ROOT=%RTAUDIO_ROOT% ^
-DRTMIDI_ROOT=%RTMIDI_ROOT%
if errorlevel 1 goto error if errorlevel 1 goto error
@@ -51,6 +53,7 @@ cd %BUILD_DIR%
windeployqt metabolus.exe windeployqt metabolus.exe
copy "%RTAUDIO_ROOT%\bin\rtaudio.dll" . copy "%RTAUDIO_ROOT%\bin\rtaudio.dll" .
copy "%RTMIDI_ROOT%\bin\rtmidi.dll" .
echo. echo.
echo Build successful. echo Build successful.

78
src/MidiController.cpp Normal file
View File

@@ -0,0 +1,78 @@
#include "MidiController.h"
#include <iostream>
MidiController::MidiController(NoteQueue& queue) : noteQueue_(queue) {
try {
midiIn_ = std::make_unique<RtMidiIn>();
midiIn_->ignoreTypes(false, false, false);
} catch (RtMidiError& e) {
std::cerr << "RtMidi init failed: " << e.getMessage() << std::endl;
}
}
MidiController::~MidiController() {
close();
}
bool MidiController::openDefaultPort() {
if (!midiIn_) return false;
if (midiIn_->getPortCount() == 0) {
std::cerr << "No MIDI input ports available\n";
return false;
}
return openPort(0);
}
bool MidiController::openPort(unsigned int index) {
if (!midiIn_) return false;
try {
midiIn_->openPort(index);
midiIn_->setCallback(&MidiController::midiCallback, this);
std::cout << "Opened MIDI port: "
<< midiIn_->getPortName(index) << "\n";
return true;
} catch (RtMidiError& e) {
std::cerr << e.getMessage() << std::endl;
return false;
}
}
void MidiController::close() {
if (midiIn_ && midiIn_->isPortOpen()) {
midiIn_->closePort();
}
}
void MidiController::midiCallback(double /*deltaTime*/, std::vector<unsigned char>* message, void* userData) {
auto* self = static_cast<MidiController*>(userData);
if (!message || message->empty()) return;
self->handleMessage(*message);
}
void MidiController::handleMessage(const std::vector<unsigned char>& msg) {
unsigned char status = msg[0] & 0xF0;
unsigned char note = msg.size() > 1 ? msg[1] : 0;
unsigned char vel = msg.size() > 2 ? msg[2] : 0;
// Note On (velocity > 0)
if (status == 0x90 && vel > 0) {
noteQueue_.push({
NoteEventType::NoteOn,
static_cast<uint8_t>(note),
vel / 127.0f
});
}
// Note Off (or Note On with velocity 0)
else if (status == 0x80 || (status == 0x90 && vel == 0)) {
noteQueue_.push({
NoteEventType::NoteOff,
static_cast<uint8_t>(note),
0.0f
});
}
// to have a peak :)
std::cout << msg[0] << std::endl;
}

28
src/MidiController.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <RtMidi.h>
#include <memory>
#include "NoteQueue.h"
class MidiController {
public:
explicit MidiController(NoteQueue& queue);
~MidiController();
bool openDefaultPort();
bool openPort(unsigned int index);
void close();
private:
static void midiCallback(
double deltaTime,
std::vector<unsigned char>* message,
void* userData
);
void handleMessage(const std::vector<unsigned char>& msg);
std::unique_ptr<RtMidiIn> midiIn_;
NoteQueue& noteQueue_;
};

View File

@@ -9,7 +9,8 @@ MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui_(new Ui::MainWindow), ui_(new Ui::MainWindow),
audio_(new AudioEngine()), audio_(new AudioEngine()),
keyboard_(audio_->noteQueue()) { keyboard_(audio_->noteQueue()),
midi_(audio_->noteQueue()) {
// initialize ui // initialize ui
ui_->setupUi(this); ui_->setupUi(this);

View File

@@ -5,6 +5,7 @@
#include <QKeyEvent> #include <QKeyEvent>
#include "../synth/AudioEngine.h" #include "../synth/AudioEngine.h"
#include "../MidiController.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; } namespace Ui { class MainWindow; }
@@ -30,5 +31,6 @@ private:
AudioEngine* audio_ = nullptr; AudioEngine* audio_ = nullptr;
KeyboardController keyboard_; KeyboardController keyboard_;
MidiController midi_;
}; };