prelim midi controller
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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
78
src/MidiController.cpp
Normal 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
28
src/MidiController.h
Normal 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_;
|
||||||
|
};
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user