buttons instead of CCtags/v0.6.1
@@ -13,8 +13,8 @@ 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; | |||||
void step(); | void step(); | ||||
void updateCc(int index, uint8_t cc); | |||||
}; | }; | ||||
@@ -160,19 +160,26 @@ void systemOpenBrowser(std::string url); | |||||
// logger.cpp | // logger.cpp | ||||
//////////////////// | //////////////////// | ||||
enum LoggerLevel { | |||||
DEBUG_LEVEL = 0, | |||||
INFO_LEVEL, | |||||
WARN_LEVEL, | |||||
FATAL_LEVEL | |||||
}; | |||||
void loggerInit(); | void loggerInit(); | ||||
void loggerDestroy(); | void loggerDestroy(); | ||||
/** Do not use this function directly. Use the macros below. */ | /** 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: | /** Example usage: | ||||
debug("error: %d", errno); | debug("error: %d", errno); | ||||
will print something like | will print something like | ||||
[0.123 debug myfile.cpp:45] error: 67 | [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 | // Thread functions | ||||
@@ -95,6 +95,7 @@ struct MIDITriggerToCVInterface : Module { | |||||
pressNote(msg.note()); | pressNote(msg.note()); | ||||
} | } | ||||
else { | else { | ||||
// Many stupid keyboards send a "note on" command with 0 velocity to mean "note release" | |||||
releaseNote(msg.note()); | releaseNote(msg.note()); | ||||
} | } | ||||
} break; | } break; | ||||
@@ -14,31 +14,38 @@ void GamepadInputDevice::step() { | |||||
const float *axes = glfwGetJoystickAxes(deviceId, &numAxes); | const float *axes = glfwGetJoystickAxes(deviceId, &numAxes); | ||||
int numButtons; | int numButtons; | ||||
const unsigned char *buttons = glfwGetJoystickButtons(deviceId, &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++) { | for (int i = 0; i < numAxes; i++) { | ||||
// Allow CC value to go negative, but clamp at -127 instead of -128 for symmetry | // 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[]) { | int main(int argc, char* argv[]) { | ||||
randomInit(); | randomInit(); | ||||
loggerInit(); | loggerInit(); | ||||
debug("Hello world!"); | |||||
info("Hello world!"); | |||||
warn("Hello world!"); | |||||
fatal("Hello world!"); | |||||
info("Rack %s", gApplicationVersion.c_str()); | info("Rack %s", gApplicationVersion.c_str()); | ||||
@@ -24,17 +24,34 @@ void loggerDestroy() { | |||||
#endif | #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(); | auto nowTime = std::chrono::high_resolution_clock::now(); | ||||
int duration = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - startTime).count(); | 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); | vfprintf(logFile, format, args); | ||||
fprintf(logFile, "\n"); | fprintf(logFile, "\n"); | ||||
fflush(logFile); | 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_list args; | ||||
va_start(args, format); | va_start(args, format); | ||||
loggerLogVa(level, file, line, format, args); | 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, ...) { | void debug(const char *format, ...) { | ||||
va_list args; | va_list args; | ||||
va_start(args, format); | va_start(args, format); | ||||
loggerLogVa("debug", "", 0, format, args); | |||||
loggerLogVa(DEBUG_LEVEL, "", 0, format, args); | |||||
va_end(args); | va_end(args); | ||||
} | } | ||||
void info(const char *format, ...) { | void info(const char *format, ...) { | ||||
va_list args; | va_list args; | ||||
va_start(args, format); | va_start(args, format); | ||||
loggerLogVa("info", "", 0, format, args); | |||||
loggerLogVa(INFO_LEVEL, "", 0, format, args); | |||||
va_end(args); | va_end(args); | ||||
} | } | ||||
void warn(const char *format, ...) { | void warn(const char *format, ...) { | ||||
va_list args; | va_list args; | ||||
va_start(args, format); | va_start(args, format); | ||||
loggerLogVa("warn", "", 0, format, args); | |||||
loggerLogVa(WARN_LEVEL, "", 0, format, args); | |||||
va_end(args); | va_end(args); | ||||
} | } | ||||
void fatal(const char *format, ...) { | void fatal(const char *format, ...) { | ||||
va_list args; | va_list args; | ||||
va_start(args, format); | va_start(args, format); | ||||
loggerLogVa("fatal", "", 0, format, args); | |||||
loggerLogVa(FATAL_LEVEL, "", 0, format, args); | |||||
va_end(args); | va_end(args); | ||||
} | } | ||||