buttons instead of CCpull/1639/head
| @@ -13,8 +13,8 @@ const int GAMEPAD_DRIVER = -10; | |||
| struct GamepadInputDevice : MidiInputDevice { | |||
| int deviceId; | |||
| std::vector<uint8_t> ccs; | |||
| std::vector<bool> notes; | |||
| void step(); | |||
| void updateCc(int index, uint8_t cc); | |||
| }; | |||
| @@ -160,19 +160,26 @@ void systemOpenBrowser(std::string url); | |||
| // logger.cpp | |||
| //////////////////// | |||
| enum LoggerLevel { | |||
| DEBUG_LEVEL = 0, | |||
| INFO_LEVEL, | |||
| WARN_LEVEL, | |||
| FATAL_LEVEL | |||
| }; | |||
| void loggerInit(); | |||
| void loggerDestroy(); | |||
| /** Do not use this function directly. Use the macros below. */ | |||
| void loggerLog(const char *level, const char *file, int line, const char *format, ...); | |||
| void loggerLog(LoggerLevel level, const char *file, int line, const char *format, ...); | |||
| /** Example usage: | |||
| debug("error: %d", errno); | |||
| will print something like | |||
| [0.123 debug myfile.cpp:45] error: 67 | |||
| */ | |||
| #define debug(format, ...) loggerLog("debug", __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
| #define info(format, ...) loggerLog("info", __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
| #define warn(format, ...) loggerLog("warn", __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
| #define fatal(format, ...) loggerLog("fatal", __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
| #define debug(format, ...) loggerLog(DEBUG_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
| #define info(format, ...) loggerLog(INFO_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
| #define warn(format, ...) loggerLog(WARN_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
| #define fatal(format, ...) loggerLog(FATAL_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
| //////////////////// | |||
| // Thread functions | |||
| @@ -95,6 +95,7 @@ struct MIDITriggerToCVInterface : Module { | |||
| pressNote(msg.note()); | |||
| } | |||
| else { | |||
| // Many stupid keyboards send a "note on" command with 0 velocity to mean "note release" | |||
| releaseNote(msg.note()); | |||
| } | |||
| } break; | |||
| @@ -14,31 +14,38 @@ void GamepadInputDevice::step() { | |||
| const float *axes = glfwGetJoystickAxes(deviceId, &numAxes); | |||
| int numButtons; | |||
| const unsigned char *buttons = glfwGetJoystickButtons(deviceId, &numButtons); | |||
| // Update state | |||
| ccs.resize(numAxes + numButtons); | |||
| // Convert axes to MIDI CC | |||
| ccs.resize(numAxes); | |||
| for (int i = 0; i < numAxes; i++) { | |||
| // Allow CC value to go negative, but clamp at -127 instead of -128 for symmetry | |||
| updateCc(i, clamp((int) (axes[i] * 127), -127, 127)); | |||
| } | |||
| for (int i = 0; i < numButtons; i++) { | |||
| updateCc(numAxes + i, buttons[i] ? 127 : 0); | |||
| int8_t cc = clamp((int) (axes[i] * 127), -127, 127); | |||
| if (cc != ccs[i]) { | |||
| ccs[i] = cc; | |||
| // Send MIDI message | |||
| MidiMessage msg; | |||
| // MIDI channel 1 | |||
| msg.cmd = (0xb << 4) | 0; | |||
| msg.data1 = i; | |||
| msg.data2 = ccs[i]; | |||
| onMessage(msg); | |||
| } | |||
| } | |||
| } | |||
| void GamepadInputDevice::updateCc(int index, uint8_t cc) { | |||
| if ((int) ccs.size() < index) | |||
| return; | |||
| if (cc != ccs[index]) { | |||
| ccs[index] = cc; | |||
| // Send MIDI message | |||
| MidiMessage msg; | |||
| // MIDI channel 1 | |||
| msg.cmd = (0xb << 4) | 0; | |||
| msg.data1 = index; | |||
| msg.data2 = ccs[index]; | |||
| onMessage(msg); | |||
| // Convert buttons to MIDI notes | |||
| notes.resize(numButtons); | |||
| for (int i = 0; i < numButtons; i++) { | |||
| bool note = !!buttons[i]; | |||
| if (note != notes[i]) { | |||
| notes[i] = note; | |||
| MidiMessage msg; | |||
| msg.cmd = ((note ? 0x9 : 0x8) << 4); | |||
| msg.data1 = i; | |||
| msg.data2 = 127; | |||
| onMessage(msg); | |||
| } | |||
| } | |||
| } | |||
| @@ -17,6 +17,10 @@ using namespace rack; | |||
| int main(int argc, char* argv[]) { | |||
| randomInit(); | |||
| loggerInit(); | |||
| debug("Hello world!"); | |||
| info("Hello world!"); | |||
| warn("Hello world!"); | |||
| fatal("Hello world!"); | |||
| info("Rack %s", gApplicationVersion.c_str()); | |||
| @@ -24,17 +24,34 @@ void loggerDestroy() { | |||
| #endif | |||
| } | |||
| static void loggerLogVa(const char *level, const char *file, int line, const char *format, va_list args) { | |||
| static const char* const loggerText[] = { | |||
| "debug", | |||
| "info", | |||
| "warn", | |||
| "fatal" | |||
| }; | |||
| static const int loggerColor[] = { | |||
| 35, | |||
| 34, | |||
| 33, | |||
| 31 | |||
| }; | |||
| static void loggerLogVa(LoggerLevel level, const char *file, int line, const char *format, va_list args) { | |||
| auto nowTime = std::chrono::high_resolution_clock::now(); | |||
| int duration = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - startTime).count(); | |||
| fprintf(logFile, "[%.03f %s %s:%d] ", duration / 1000.0, level, file, line); | |||
| if (logFile == stderr) | |||
| fprintf(logFile, "\x1B[%dm", loggerColor[level]); | |||
| fprintf(logFile, "[%.03f %s %s:%d] ", duration / 1000.0, loggerText[level], file, line); | |||
| if (logFile == stderr) | |||
| fprintf(logFile, "\x1B[0m"); | |||
| vfprintf(logFile, format, args); | |||
| fprintf(logFile, "\n"); | |||
| fflush(logFile); | |||
| } | |||
| void loggerLog(const char *level, const char *file, int line, const char *format, ...) { | |||
| void loggerLog(LoggerLevel level, const char *file, int line, const char *format, ...) { | |||
| va_list args; | |||
| va_start(args, format); | |||
| loggerLogVa(level, file, line, format, args); | |||
| @@ -51,28 +68,28 @@ void loggerLog(const char *level, const char *file, int line, const char *format | |||
| void debug(const char *format, ...) { | |||
| va_list args; | |||
| va_start(args, format); | |||
| loggerLogVa("debug", "", 0, format, args); | |||
| loggerLogVa(DEBUG_LEVEL, "", 0, format, args); | |||
| va_end(args); | |||
| } | |||
| void info(const char *format, ...) { | |||
| va_list args; | |||
| va_start(args, format); | |||
| loggerLogVa("info", "", 0, format, args); | |||
| loggerLogVa(INFO_LEVEL, "", 0, format, args); | |||
| va_end(args); | |||
| } | |||
| void warn(const char *format, ...) { | |||
| va_list args; | |||
| va_start(args, format); | |||
| loggerLogVa("warn", "", 0, format, args); | |||
| loggerLogVa(WARN_LEVEL, "", 0, format, args); | |||
| va_end(args); | |||
| } | |||
| void fatal(const char *format, ...) { | |||
| va_list args; | |||
| va_start(args, format); | |||
| loggerLogVa("fatal", "", 0, format, args); | |||
| loggerLogVa(FATAL_LEVEL, "", 0, format, args); | |||
| va_end(args); | |||
| } | |||