@@ -1,5 +1,7 @@ | |||||
#pragma once | #pragma once | ||||
#include "util/common.hpp" | |||||
#include "midi.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -7,7 +9,24 @@ namespace rack { | |||||
const int GAMEPAD_DRIVER = -10; | const int GAMEPAD_DRIVER = -10; | ||||
struct GamepadInputDevice : MidiInputDevice { | |||||
int device; | |||||
}; | |||||
struct GamepadInputDriver : MidiInputDriver { | |||||
GamepadInputDevice gamepadInputDevices[16]; | |||||
GamepadInputDriver(); | |||||
int getDeviceCount() override; | |||||
std::string getDeviceName(int device) override; | |||||
MidiInputDevice *getDevice(int device) override; | |||||
}; | |||||
void gamepadStep(); | void gamepadStep(); | ||||
MidiInputDriver *gamepadGetInputDriver(); | |||||
} // namespace rack | } // namespace rack |
@@ -30,14 +30,47 @@ struct MidiMessage { | |||||
}; | }; | ||||
//////////////////// | //////////////////// | ||||
// MidiIO | |||||
// MidiIODevice | |||||
//////////////////// | |||||
struct MidiIODevice { | |||||
virtual ~MidiIODevice() {} | |||||
}; | |||||
struct MidiInput; | |||||
struct MidiInputDevice : MidiIODevice { | |||||
std::set<MidiInput*> subscribed; | |||||
void subscribe(MidiInput *midiInput); | |||||
void unsubscribe(MidiInput *midiInput); | |||||
void onMessage(MidiMessage message); | |||||
}; | |||||
struct MidiOutputDevice : MidiIODevice { | |||||
// TODO | |||||
}; | |||||
//////////////////// | |||||
// MidiIODriver | |||||
//////////////////// | //////////////////// | ||||
struct MidiInputDriver; | |||||
struct MidiOutputDriver; | |||||
struct MidiInputDevice; | |||||
struct MidiOutputDevice; | |||||
struct MidiIODriver { | |||||
virtual ~MidiIODriver() {} | |||||
virtual int getDeviceCount() = 0; | |||||
virtual std::string getDeviceName(int device) = 0; | |||||
}; | |||||
struct MidiInputDriver : MidiIODriver { | |||||
virtual MidiInputDevice *getDevice(int device) = 0; | |||||
}; | |||||
struct MidiOutputDriver : MidiIODriver { | |||||
virtual MidiOutputDevice *getDevice(int device) = 0; | |||||
}; | |||||
//////////////////// | |||||
// MidiIO | |||||
//////////////////// | |||||
struct MidiIO { | struct MidiIO { | ||||
int driver = -1; | int driver = -1; | ||||
@@ -104,43 +137,5 @@ struct MidiOutput : MidiIO { | |||||
void setDevice(int device) override; | void setDevice(int device) override; | ||||
}; | }; | ||||
//////////////////// | |||||
// MidiIODriver | |||||
//////////////////// | |||||
struct MidiIODriver { | |||||
virtual ~MidiIODriver() {} | |||||
virtual int getDeviceCount() = 0; | |||||
virtual std::string getDeviceName(int device) = 0; | |||||
}; | |||||
struct MidiInputDriver : MidiIODriver { | |||||
virtual MidiInputDevice *getDevice(int device) = 0; | |||||
}; | |||||
struct MidiOutputDriver : MidiIODriver { | |||||
virtual MidiOutputDevice *getDevice(int device) = 0; | |||||
}; | |||||
//////////////////// | |||||
// MidiIODevice | |||||
//////////////////// | |||||
struct MidiIODevice { | |||||
virtual ~MidiIODevice() {} | |||||
}; | |||||
struct MidiInputDevice : MidiIODevice { | |||||
std::set<MidiInput*> subscribed; | |||||
void subscribe(MidiInput *midiInput); | |||||
/** Deletes itself if nothing is subscribed */ | |||||
void unsubscribe(MidiInput *midiInput); | |||||
void onMessage(MidiMessage message); | |||||
}; | |||||
struct MidiOutputDevice : MidiIODevice { | |||||
// TODO | |||||
}; | |||||
} // namespace rack | } // namespace rack |
@@ -162,10 +162,17 @@ void systemOpenBrowser(std::string url); | |||||
void loggerInit(); | void loggerInit(); | ||||
void loggerDestroy(); | void loggerDestroy(); | ||||
void debug(const char *format, ...); | |||||
void info(const char *format, ...); | |||||
void warn(const char *format, ...); | |||||
void fatal(const char *format, ...); | |||||
/** Do not use this function directly. Use the macros below. */ | |||||
void loggerLog(const char *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__) | |||||
//////////////////// | //////////////////// | ||||
// Thread functions | // Thread functions | ||||
@@ -17,7 +17,7 @@ namespace rack { | |||||
bool gPaused = false; | bool gPaused = false; | ||||
std::vector<Module*> gModules; | std::vector<Module*> gModules; | ||||
std::vector<Wire*> gWires; | std::vector<Wire*> gWires; | ||||
bool gCpuMeters = true; | |||||
bool gCpuMeters = false; | |||||
static bool running = false; | static bool running = false; | ||||
static float sampleRate; | static float sampleRate; | ||||
@@ -87,7 +87,10 @@ static void engineStep() { | |||||
// Step modules | // Step modules | ||||
for (Module *module : gModules) { | for (Module *module : gModules) { | ||||
auto startTime = std::chrono::high_resolution_clock::now(); | |||||
std::chrono::high_resolution_clock::time_point startTime; | |||||
if (gCpuMeters) { | |||||
startTime = std::chrono::high_resolution_clock::now(); | |||||
} | |||||
module->step(); | module->step(); | ||||
@@ -6,6 +6,34 @@ | |||||
namespace rack { | namespace rack { | ||||
GamepadInputDriver::GamepadInputDriver() { | |||||
for (int i = 0; i < 16; i++) { | |||||
gamepadInputDevices[i].device = i; | |||||
} | |||||
} | |||||
int GamepadInputDriver::getDeviceCount() { | |||||
return 16; | |||||
} | |||||
std::string GamepadInputDriver::getDeviceName(int device) { | |||||
assert(0 <= device && device < 16); | |||||
const char *name = glfwGetJoystickName(device); | |||||
if (name) { | |||||
return name; | |||||
} | |||||
return stringf("Gamepad %d (unavailable)", device + 1); | |||||
} | |||||
MidiInputDevice *GamepadInputDriver::getDevice(int device) { | |||||
assert(0 <= device && device < 16); | |||||
return &gamepadInputDevices[device]; | |||||
} | |||||
static GamepadInputDriver *gamepadInputDriver = NULL; | |||||
void gamepadStep() { | void gamepadStep() { | ||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
if (glfwJoystickPresent(i)) { | if (glfwJoystickPresent(i)) { | ||||
@@ -19,5 +47,12 @@ void gamepadStep() { | |||||
} | } | ||||
} | } | ||||
MidiInputDriver *gamepadGetInputDriver() { | |||||
if (!gamepadInputDriver) { | |||||
gamepadInputDriver = new GamepadInputDriver(); | |||||
} | |||||
return gamepadInputDriver; | |||||
} | |||||
} // namespace rack | } // namespace rack |
@@ -7,6 +7,35 @@ | |||||
namespace rack { | namespace rack { | ||||
//////////////////// | |||||
// MidiIODevice | |||||
//////////////////// | |||||
void MidiInputDevice::subscribe(MidiInput *midiInput) { | |||||
subscribed.insert(midiInput); | |||||
} | |||||
void MidiInputDevice::unsubscribe(MidiInput *midiInput) { | |||||
auto it = subscribed.find(midiInput); | |||||
if (it != subscribed.end()) | |||||
subscribed.erase(it); | |||||
if (subscribed.size() == 0) { | |||||
warn("TODO: Fix memory leak"); | |||||
} | |||||
} | |||||
void MidiInputDevice::onMessage(MidiMessage message) { | |||||
for (MidiInput *midiInput : subscribed) { | |||||
midiInput->onMessage(message); | |||||
} | |||||
} | |||||
//////////////////// | |||||
// MidiIODriver | |||||
//////////////////// | |||||
//////////////////// | //////////////////// | ||||
// MidiIO | // MidiIO | ||||
//////////////////// | //////////////////// | ||||
@@ -94,6 +123,12 @@ void MidiInput::setDriver(int driver) { | |||||
if (driver >= 0) { | if (driver >= 0) { | ||||
midiInputDriver = rtmidiGetInputDriver(driver); | midiInputDriver = rtmidiGetInputDriver(driver); | ||||
} | } | ||||
else if (driver == BRIDGE_DRIVER) { | |||||
// TODO | |||||
} | |||||
else if (driver == GAMEPAD_DRIVER) { | |||||
midiInputDriver = gamepadGetInputDriver(); | |||||
} | |||||
this->driver = driver; | this->driver = driver; | ||||
} | } | ||||
@@ -165,30 +200,5 @@ void MidiOutput::setDevice(int device) { | |||||
// TODO | // TODO | ||||
} | } | ||||
//////////////////// | |||||
// MidiIODevice | |||||
//////////////////// | |||||
void MidiInputDevice::subscribe(MidiInput *midiInput) { | |||||
subscribed.insert(midiInput); | |||||
} | |||||
void MidiInputDevice::unsubscribe(MidiInput *midiInput) { | |||||
auto it = subscribed.find(midiInput); | |||||
if (it != subscribed.end()) | |||||
subscribed.erase(it); | |||||
// Delete self if nothing is subscribed | |||||
if (subscribed.size() == 0) { | |||||
delete this; | |||||
} | |||||
} | |||||
void MidiInputDevice::onMessage(MidiMessage message) { | |||||
for (MidiInput *midiInput : subscribed) { | |||||
midiInput->onMessage(message); | |||||
} | |||||
} | |||||
} // namespace rack | } // namespace rack |
@@ -7,10 +7,11 @@ namespace rack { | |||||
static FILE *logFile = stderr; | static FILE *logFile = stderr; | ||||
static auto startTime = std::chrono::high_resolution_clock::now(); | |||||
static std::chrono::high_resolution_clock::time_point startTime; | |||||
void loggerInit() { | void loggerInit() { | ||||
startTime = std::chrono::high_resolution_clock::now(); | |||||
#ifdef RELEASE | #ifdef RELEASE | ||||
std::string logFilename = assetLocal("log.txt"); | std::string logFilename = assetLocal("log.txt"); | ||||
logFile = fopen(logFilename.c_str(), "w"); | logFile = fopen(logFilename.c_str(), "w"); | ||||
@@ -23,44 +24,55 @@ void loggerDestroy() { | |||||
#endif | #endif | ||||
} | } | ||||
static void printTimestamp() { | |||||
} | |||||
static void loggerLogVa(const char *level, const char *file, int line, const char *format, va_list args) { | |||||
static void printLog(const char *type, 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(); | ||||
printTimestamp(); | |||||
fprintf(logFile, "[%.03f %s] ", duration / 1000.0, type); | |||||
fprintf(logFile, "[%.03f %s %s:%d] ", duration / 1000.0, level, file, line); | |||||
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, ...) { | |||||
va_list args; | |||||
va_start(args, format); | |||||
loggerLogVa(level, file, line, format, args); | |||||
va_end(args); | |||||
} | |||||
/** Deprecated. Included for ABI compatibility */ | |||||
#undef debug | |||||
#undef info | |||||
#undef warn | |||||
#undef fatal | |||||
void debug(const char *format, ...) { | void debug(const char *format, ...) { | ||||
va_list args; | va_list args; | ||||
va_start(args, format); | va_start(args, format); | ||||
printLog("debug", format, args); | |||||
loggerLogVa("debug", "", 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); | ||||
printLog("info", format, args); | |||||
loggerLogVa("info", "", 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); | ||||
printLog("warn", format, args); | |||||
loggerLogVa("warn", "", 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); | ||||
printLog("fatal", format, args); | |||||
loggerLogVa("fatal", "", 0, format, args); | |||||
va_end(args); | va_end(args); | ||||
} | } | ||||