@@ -1,5 +1,7 @@ | |||
#pragma once | |||
#include "util/common.hpp" | |||
#include "midi.hpp" | |||
namespace rack { | |||
@@ -7,7 +9,24 @@ namespace rack { | |||
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(); | |||
MidiInputDriver *gamepadGetInputDriver(); | |||
} // 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 { | |||
int driver = -1; | |||
@@ -104,43 +137,5 @@ struct MidiOutput : MidiIO { | |||
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 |
@@ -162,10 +162,17 @@ void systemOpenBrowser(std::string url); | |||
void loggerInit(); | |||
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 | |||
@@ -17,7 +17,7 @@ namespace rack { | |||
bool gPaused = false; | |||
std::vector<Module*> gModules; | |||
std::vector<Wire*> gWires; | |||
bool gCpuMeters = true; | |||
bool gCpuMeters = false; | |||
static bool running = false; | |||
static float sampleRate; | |||
@@ -87,7 +87,10 @@ static void engineStep() { | |||
// Step modules | |||
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(); | |||
@@ -6,6 +6,34 @@ | |||
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() { | |||
for (int i = 0; i < 16; i++) { | |||
if (glfwJoystickPresent(i)) { | |||
@@ -19,5 +47,12 @@ void gamepadStep() { | |||
} | |||
} | |||
MidiInputDriver *gamepadGetInputDriver() { | |||
if (!gamepadInputDriver) { | |||
gamepadInputDriver = new GamepadInputDriver(); | |||
} | |||
return gamepadInputDriver; | |||
} | |||
} // namespace rack |
@@ -7,6 +7,35 @@ | |||
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 | |||
//////////////////// | |||
@@ -94,6 +123,12 @@ void MidiInput::setDriver(int driver) { | |||
if (driver >= 0) { | |||
midiInputDriver = rtmidiGetInputDriver(driver); | |||
} | |||
else if (driver == BRIDGE_DRIVER) { | |||
// TODO | |||
} | |||
else if (driver == GAMEPAD_DRIVER) { | |||
midiInputDriver = gamepadGetInputDriver(); | |||
} | |||
this->driver = driver; | |||
} | |||
@@ -165,30 +200,5 @@ void MidiOutput::setDevice(int device) { | |||
// 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 |
@@ -7,10 +7,11 @@ namespace rack { | |||
static FILE *logFile = stderr; | |||
static auto startTime = std::chrono::high_resolution_clock::now(); | |||
static std::chrono::high_resolution_clock::time_point startTime; | |||
void loggerInit() { | |||
startTime = std::chrono::high_resolution_clock::now(); | |||
#ifdef RELEASE | |||
std::string logFilename = assetLocal("log.txt"); | |||
logFile = fopen(logFilename.c_str(), "w"); | |||
@@ -23,44 +24,55 @@ void loggerDestroy() { | |||
#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(); | |||
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); | |||
fprintf(logFile, "\n"); | |||
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, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
printLog("debug", format, args); | |||
loggerLogVa("debug", "", 0, format, args); | |||
va_end(args); | |||
} | |||
void info(const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
printLog("info", format, args); | |||
loggerLogVa("info", "", 0, format, args); | |||
va_end(args); | |||
} | |||
void warn(const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
printLog("warn", format, args); | |||
loggerLogVa("warn", "", 0, format, args); | |||
va_end(args); | |||
} | |||
void fatal(const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
printLog("fatal", format, args); | |||
loggerLogVa("fatal", "", 0, format, args); | |||
va_end(args); | |||
} | |||