@@ -13,7 +13,7 @@ const int GAMEPAD_DRIVER = -10; | |||||
struct GamepadInputDevice : MidiInputDevice { | struct GamepadInputDevice : MidiInputDevice { | ||||
int deviceId; | int deviceId; | ||||
std::vector<uint8_t> ccs; | std::vector<uint8_t> ccs; | ||||
std::vector<bool> notes; | |||||
std::vector<bool> states; | |||||
void step(); | 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 "gamepad.hpp" | ||||
#include "util/common.hpp" | |||||
#include <GLFW/glfw3.h> | #include <GLFW/glfw3.h> | ||||
@@ -34,14 +33,14 @@ void GamepadInputDevice::step() { | |||||
} | } | ||||
// Convert buttons to MIDI notes | // Convert buttons to MIDI notes | ||||
notes.resize(numButtons); | |||||
states.resize(numButtons); | |||||
for (int i = 0; i < numButtons; i++) { | 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; | MidiMessage msg; | ||||
msg.cmd = ((note ? 0x9 : 0x8) << 4); | |||||
msg.cmd = ((state ? 0x9 : 0x8) << 4); | |||||
msg.data1 = i; | msg.data1 = i; | ||||
msg.data2 = 127; | msg.data2 = 127; | ||||
onMessage(msg); | 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 "rtmidi.hpp" | ||||
#include "bridge.hpp" | #include "bridge.hpp" | ||||
#include "gamepad.hpp" | #include "gamepad.hpp" | ||||
#include "keyboard.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -45,6 +46,7 @@ std::vector<int> MidiIO::getDriverIds() { | |||||
// Add custom driverIds | // Add custom driverIds | ||||
driverIds.push_back(BRIDGE_DRIVER); | driverIds.push_back(BRIDGE_DRIVER); | ||||
driverIds.push_back(GAMEPAD_DRIVER); | driverIds.push_back(GAMEPAD_DRIVER); | ||||
driverIds.push_back(KEYBOARD_DRIVER); | |||||
return driverIds; | return driverIds; | ||||
} | } | ||||
@@ -59,6 +61,7 @@ std::string MidiIO::getDriverName(int driverId) { | |||||
case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI"; | case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI"; | ||||
case BRIDGE_DRIVER: return "Bridge"; | case BRIDGE_DRIVER: return "Bridge"; | ||||
case GAMEPAD_DRIVER: return "Gamepad"; | case GAMEPAD_DRIVER: return "Gamepad"; | ||||
case KEYBOARD_DRIVER: return "Computer keyboard"; | |||||
default: return "Unknown"; | default: return "Unknown"; | ||||
} | } | ||||
} | } | ||||
@@ -132,6 +135,9 @@ void MidiInput::setDriverId(int driverId) { | |||||
else if (driverId == GAMEPAD_DRIVER) { | else if (driverId == GAMEPAD_DRIVER) { | ||||
driver = gamepadGetInputDriver(); | driver = gamepadGetInputDriver(); | ||||
} | } | ||||
else if (driverId == KEYBOARD_DRIVER) { | |||||
driver = keyboardGetInputDriver(); | |||||
} | |||||
// Set driverId | // Set driverId | ||||
if (driver) { | if (driver) { | ||||
@@ -2,6 +2,7 @@ | |||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "asset.hpp" | #include "asset.hpp" | ||||
#include "gamepad.hpp" | #include "gamepad.hpp" | ||||
#include "keyboard.hpp" | |||||
#include "util/color.hpp" | #include "util/color.hpp" | ||||
#include <map> | #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) { | 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 (action == GLFW_PRESS || action == GLFW_REPEAT) { | ||||
if (gFocusedWidget) { | if (gFocusedWidget) { | ||||
// onKey | // onKey | ||||