@@ -13,7 +13,7 @@ const int GAMEPAD_DRIVER = -10; | |||
struct GamepadInputDevice : MidiInputDevice { | |||
int deviceId; | |||
std::vector<uint8_t> ccs; | |||
std::vector<bool> notes; | |||
std::vector<bool> states; | |||
void step(); | |||
}; | |||
@@ -0,0 +1,33 @@ | |||
#pragma once | |||
#include "util/common.hpp" | |||
#include "midi.hpp" | |||
namespace rack { | |||
const int KEYBOARD_DRIVER = -11; | |||
struct KeyboardInputDevice : MidiInputDevice { | |||
int octave = 5; | |||
void processKey(int key, bool released); | |||
}; | |||
struct KeyboardInputDriver : MidiInputDriver { | |||
KeyboardInputDevice device; | |||
std::vector<int> getDeviceIds() override; | |||
std::string getDeviceName(int deviceId) override; | |||
MidiInputDevice *getDevice(int deviceId) override; | |||
}; | |||
void keyboardPress(int key); | |||
void keyboardRelease(int key); | |||
KeyboardInputDriver *keyboardGetInputDriver(); | |||
} // namespace rack |
@@ -1,5 +1,4 @@ | |||
#include "gamepad.hpp" | |||
#include "util/common.hpp" | |||
#include <GLFW/glfw3.h> | |||
@@ -34,14 +33,14 @@ void GamepadInputDevice::step() { | |||
} | |||
// Convert buttons to MIDI notes | |||
notes.resize(numButtons); | |||
states.resize(numButtons); | |||
for (int i = 0; i < numButtons; i++) { | |||
bool note = !!buttons[i]; | |||
if (note != notes[i]) { | |||
notes[i] = note; | |||
bool state = !!buttons[i]; | |||
if (state != states[i]) { | |||
states[i] = state; | |||
MidiMessage msg; | |||
msg.cmd = ((note ? 0x9 : 0x8) << 4); | |||
msg.cmd = ((state ? 0x9 : 0x8) << 4); | |||
msg.data1 = i; | |||
msg.data2 = 127; | |||
onMessage(msg); | |||
@@ -0,0 +1,115 @@ | |||
#include "keyboard.hpp" | |||
#include <GLFW/glfw3.h> | |||
namespace rack { | |||
void KeyboardInputDevice::processKey(int key, bool released) { | |||
int note = -1; | |||
switch (key) { | |||
case GLFW_KEY_Z: note = 0; break; | |||
case GLFW_KEY_S: note = 1; break; | |||
case GLFW_KEY_X: note = 2; break; | |||
case GLFW_KEY_D: note = 3; break; | |||
case GLFW_KEY_C: note = 4; break; | |||
case GLFW_KEY_V: note = 5; break; | |||
case GLFW_KEY_G: note = 6; break; | |||
case GLFW_KEY_B: note = 7; break; | |||
case GLFW_KEY_H: note = 8; break; | |||
case GLFW_KEY_N: note = 9; break; | |||
case GLFW_KEY_J: note = 10; break; | |||
case GLFW_KEY_M: note = 11; break; | |||
case GLFW_KEY_COMMA: note = 12; break; | |||
case GLFW_KEY_L: note = 13; break; | |||
case GLFW_KEY_PERIOD: note = 14; break; | |||
case GLFW_KEY_SEMICOLON: note = 15; break; | |||
case GLFW_KEY_SLASH: note = 16; break; | |||
case GLFW_KEY_Q: note = 12; break; | |||
case GLFW_KEY_2: note = 13; break; | |||
case GLFW_KEY_W: note = 14; break; | |||
case GLFW_KEY_3: note = 15; break; | |||
case GLFW_KEY_E: note = 16; break; | |||
case GLFW_KEY_R: note = 17; break; | |||
case GLFW_KEY_5: note = 18; break; | |||
case GLFW_KEY_T: note = 19; break; | |||
case GLFW_KEY_6: note = 20; break; | |||
case GLFW_KEY_Y: note = 21; break; | |||
case GLFW_KEY_7: note = 22; break; | |||
case GLFW_KEY_U: note = 23; break; | |||
case GLFW_KEY_I: note = 24; break; | |||
case GLFW_KEY_9: note = 25; break; | |||
case GLFW_KEY_O: note = 26; break; | |||
case GLFW_KEY_0: note = 27; break; | |||
case GLFW_KEY_P: note = 28; break; | |||
case GLFW_KEY_LEFT_BRACKET: note = 29; break; | |||
case GLFW_KEY_EQUAL: note = 30; break; | |||
case GLFW_KEY_RIGHT_BRACKET: note = 31; break; | |||
case GLFW_KEY_GRAVE_ACCENT: { | |||
if (!released) | |||
octave--; | |||
} break; | |||
case GLFW_KEY_1: { | |||
if (!released) | |||
octave++; | |||
} break; | |||
default: break; | |||
} | |||
octave = clamp(octave, 0, 9); | |||
if (note < 0) | |||
return; | |||
note += 12 * octave; | |||
if (note > 127) | |||
return; | |||
MidiMessage msg; | |||
msg.cmd = ((!released ? 0x9 : 0x8) << 4); | |||
msg.data1 = note; | |||
msg.data2 = 127; | |||
onMessage(msg); | |||
} | |||
std::vector<int> KeyboardInputDriver::getDeviceIds() { | |||
return {0}; | |||
} | |||
std::string KeyboardInputDriver::getDeviceName(int deviceId) { | |||
if (deviceId == 0) | |||
return "QWERTY keyboard (US)"; | |||
return ""; | |||
} | |||
MidiInputDevice *KeyboardInputDriver::getDevice(int deviceId) { | |||
return &device; | |||
} | |||
static KeyboardInputDriver *driver = NULL; | |||
void keyboardPress(int key) { | |||
if (!driver) | |||
return; | |||
driver->device.processKey(key, false); | |||
} | |||
void keyboardRelease(int key) { | |||
if (!driver) | |||
return; | |||
driver->device.processKey(key, true); | |||
} | |||
KeyboardInputDriver *keyboardGetInputDriver() { | |||
// Lazily create driver | |||
if (!driver) { | |||
driver = new KeyboardInputDriver(); | |||
} | |||
return driver; | |||
} | |||
} // namespace rack |
@@ -2,6 +2,7 @@ | |||
#include "rtmidi.hpp" | |||
#include "bridge.hpp" | |||
#include "gamepad.hpp" | |||
#include "keyboard.hpp" | |||
namespace rack { | |||
@@ -45,6 +46,7 @@ std::vector<int> MidiIO::getDriverIds() { | |||
// Add custom driverIds | |||
driverIds.push_back(BRIDGE_DRIVER); | |||
driverIds.push_back(GAMEPAD_DRIVER); | |||
driverIds.push_back(KEYBOARD_DRIVER); | |||
return driverIds; | |||
} | |||
@@ -59,6 +61,7 @@ std::string MidiIO::getDriverName(int driverId) { | |||
case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI"; | |||
case BRIDGE_DRIVER: return "Bridge"; | |||
case GAMEPAD_DRIVER: return "Gamepad"; | |||
case KEYBOARD_DRIVER: return "Computer keyboard"; | |||
default: return "Unknown"; | |||
} | |||
} | |||
@@ -132,6 +135,9 @@ void MidiInput::setDriverId(int driverId) { | |||
else if (driverId == GAMEPAD_DRIVER) { | |||
driver = gamepadGetInputDriver(); | |||
} | |||
else if (driverId == KEYBOARD_DRIVER) { | |||
driver = keyboardGetInputDriver(); | |||
} | |||
// Set driverId | |||
if (driver) { | |||
@@ -2,6 +2,7 @@ | |||
#include "app.hpp" | |||
#include "asset.hpp" | |||
#include "gamepad.hpp" | |||
#include "keyboard.hpp" | |||
#include "util/color.hpp" | |||
#include <map> | |||
@@ -262,6 +263,16 @@ void charCallback(GLFWwindow *window, unsigned int codepoint) { | |||
} | |||
void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { | |||
// Keyboard MIDI driver | |||
if (1 || glfwGetInputMode(gWindow, GLFW_LOCK_KEY_MODS) & GLFW_MOD_CAPS_LOCK) { | |||
if (action == GLFW_PRESS) { | |||
keyboardPress(key); | |||
} | |||
else if (action == GLFW_RELEASE) { | |||
keyboardRelease(key); | |||
} | |||
} | |||
if (action == GLFW_PRESS || action == GLFW_REPEAT) { | |||
if (gFocusedWidget) { | |||
// onKey | |||