@@ -1,7 +1,7 @@ | |||
#pragma once | |||
#include "util/common.hpp" | |||
#include "string.hpp" | |||
#include "nanovg.h" | |||
@@ -87,9 +87,9 @@ inline std::string toHexString(NVGcolor c) { | |||
uint8_t b = std::round(c.b * 255); | |||
uint8_t a = std::round(c.a * 255); | |||
if (a == 255) | |||
return stringf("#%02x%02x%02x", r, g, b); | |||
return string::stringf("#%02x%02x%02x", r, g, b); | |||
else | |||
return stringf("#%02x%02x%02x%02x", r, g, b, a); | |||
return string::stringf("#%02x%02x%02x%02x", r, g, b, a); | |||
} | |||
@@ -0,0 +1,40 @@ | |||
#pragma once | |||
/** Example usage: | |||
debug("error: %d", errno); | |||
will print something like | |||
[0.123 debug myfile.cpp:45] error: 67 | |||
*/ | |||
#define DEBUG(format, ...) rack::logger::log(rack::logger::DEBUG_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
#define INFO(format, ...) rack::logger::log(rack::logger::INFO_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
#define WARN(format, ...) rack::logger::log(rack::logger::WARN_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
#define FATAL(format, ...) rack::logger::log(rack::logger::FATAL_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__) | |||
/** Deprecated lowercase log functions */ | |||
#define debug(...) DEBUG(__VA_ARGS__) | |||
#define info(...) INFO(__VA_ARGS__) | |||
#define warn(...) WARN(__VA_ARGS__) | |||
#define fatal(...) FATAL(__VA_ARGS__) | |||
namespace rack { | |||
namespace logger { | |||
enum Level { | |||
DEBUG_LEVEL, | |||
INFO_LEVEL, | |||
WARN_LEVEL, | |||
FATAL_LEVEL | |||
}; | |||
void init(bool devMode); | |||
void destroy(); | |||
/** Do not use this function directly. Use the macros below. */ | |||
void log(Level level, const char *filename, int line, const char *format, ...); | |||
} // namespace logger | |||
} // namespace rack |
@@ -0,0 +1,67 @@ | |||
#pragma once | |||
/** Concatenates two literals or two macros | |||
Example: | |||
#define COUNT 42 | |||
CONCAT(myVariable, COUNT) | |||
expands to | |||
myVariable42 | |||
*/ | |||
#define CONCAT_LITERAL(x, y) x ## y | |||
#define CONCAT(x, y) CONCAT_LITERAL(x, y) | |||
/** Surrounds raw text with quotes | |||
Example: | |||
#define NAME "world" | |||
printf("Hello " TOSTRING(NAME)) | |||
expands to | |||
printf("Hello " "world") | |||
and of course the C++ lexer/parser then concatenates the string literals. | |||
*/ | |||
#define TOSTRING_LITERAL(x) #x | |||
#define TOSTRING(x) TOSTRING_LITERAL(x) | |||
/** Produces the length of a static array in number of elements */ | |||
#define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0])) | |||
/** Reserve space for `count` enums starting with `name`. | |||
Example: | |||
enum Foo { | |||
ENUMS(BAR, 14), | |||
BAZ | |||
}; | |||
BAR + 0 to BAR + 13 is reserved. BAZ has a value of 14. | |||
*/ | |||
#define ENUMS(name, count) name, name ## _LAST = name + (count) - 1 | |||
/** Deprecation notice for GCC */ | |||
#define DEPRECATED __attribute__ ((deprecated)) | |||
/** References binary files compiled into the program. | |||
For example, to include a file "Test.dat" directly into your program binary, add | |||
BINARIES += Test.dat | |||
to your Makefile and declare | |||
BINARY(Test_dat); | |||
at the root of a .c or .cpp source file. Note that special characters are replaced with "_". Then use | |||
BINARY_START(Test_dat) | |||
BINARY_END(Test_dat) | |||
to reference the data beginning and end as a void* array, and | |||
BINARY_SIZE(Test_dat) | |||
to get its size in bytes. | |||
*/ | |||
#ifdef ARCH_MAC | |||
// Use output from `xxd -i` | |||
#define BINARY(sym) extern unsigned char sym[]; extern unsigned int sym##_len | |||
#define BINARY_START(sym) ((const void*) sym) | |||
#define BINARY_END(sym) ((const void*) sym + sym##_len) | |||
#define BINARY_SIZE(sym) (sym##_len) | |||
#else | |||
#define BINARY(sym) extern char _binary_##sym##_start, _binary_##sym##_end, _binary_##sym##_size | |||
#define BINARY_START(sym) ((const void*) &_binary_##sym##_start) | |||
#define BINARY_END(sym) ((const void*) &_binary_##sym##_end) | |||
// The symbol "_binary_##sym##_size" doesn't seem to be valid after a plugin is dynamically loaded, so simply take the difference between the two addresses. | |||
#define BINARY_SIZE(sym) ((size_t) (&_binary_##sym##_end - &_binary_##sym##_start)) | |||
#endif |
@@ -1,8 +1,8 @@ | |||
#pragma once | |||
#include "util/common.hpp" | |||
#include <cmath> | |||
#include <cstdlib> | |||
#include <algorithm> // for std::min, max | |||
#include "macros.hpp" | |||
namespace rack { | |||
@@ -15,6 +15,8 @@ namespace rack { | |||
using namespace math; | |||
using namespace string; | |||
using namespace logger; | |||
} // namespace rack |
@@ -1,13 +1,16 @@ | |||
#pragma once | |||
#include "util/common.hpp" | |||
#include <stdarg.h> | |||
#include <algorithm> | |||
#include <cstdarg> | |||
#include <libgen.h> // for dirname and basename | |||
namespace rack { | |||
namespace string { | |||
std::string stringf(const char *format, ...) { | |||
/** Converts a printf format string and optional arguments into a std::string */ | |||
inline std::string stringf(const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
// Compute size of required buffer | |||
@@ -24,51 +27,60 @@ std::string stringf(const char *format, ...) { | |||
return s; | |||
} | |||
std::string stringLowercase(std::string s) { | |||
inline std::string lowercase(std::string s) { | |||
std::transform(s.begin(), s.end(), s.begin(), ::tolower); | |||
return s; | |||
} | |||
std::string stringUppercase(std::string s) { | |||
inline std::string uppercase(std::string s) { | |||
std::transform(s.begin(), s.end(), s.begin(), ::toupper); | |||
return s; | |||
} | |||
std::string stringEllipsize(std::string s, size_t len) { | |||
/** Truncates and adds "..." to a string, not exceeding `len` characters */ | |||
inline std::string ellipsize(std::string s, size_t len) { | |||
if (s.size() <= len) | |||
return s; | |||
else | |||
return s.substr(0, len - 3) + "..."; | |||
} | |||
bool stringStartsWith(std::string str, std::string prefix) { | |||
inline bool startsWith(std::string str, std::string prefix) { | |||
return str.substr(0, prefix.size()) == prefix; | |||
} | |||
bool stringEndsWith(std::string str, std::string suffix) { | |||
inline bool endsWith(std::string str, std::string suffix) { | |||
return str.substr(str.size() - suffix.size(), suffix.size()) == suffix; | |||
} | |||
std::string stringDirectory(std::string path) { | |||
/** Extracts portions of a path */ | |||
inline std::string directory(std::string path) { | |||
char *pathDup = strdup(path.c_str()); | |||
std::string directory = dirname(pathDup); | |||
free(pathDup); | |||
return directory; | |||
} | |||
std::string stringFilename(std::string path) { | |||
inline std::string filename(std::string path) { | |||
char *pathDup = strdup(path.c_str()); | |||
std::string filename = basename(pathDup); | |||
free(pathDup); | |||
return filename; | |||
} | |||
std::string stringExtension(std::string path) { | |||
const char *ext = strrchr(stringFilename(path).c_str(), '.'); | |||
inline std::string extension(std::string path) { | |||
const char *ext = strrchr(filename(path).c_str(), '.'); | |||
if (!ext) | |||
return ""; | |||
return ext + 1; | |||
} | |||
struct CaseInsensitiveCompare { | |||
bool operator()(const std::string &a, const std::string &b) const { | |||
return lowercase(a) < lowercase(b); | |||
} | |||
}; | |||
} // namespace string | |||
} // namespace rack |
@@ -13,77 +13,10 @@ | |||
#include <condition_variable> | |||
#include <mutex> | |||
//////////////////// | |||
// Handy macros | |||
//////////////////// | |||
/** Concatenates two literals or two macros | |||
Example: | |||
#define COUNT 42 | |||
CONCAT(myVariable, COUNT) | |||
expands to | |||
myVariable42 | |||
*/ | |||
#define CONCAT_LITERAL(x, y) x ## y | |||
#define CONCAT(x, y) CONCAT_LITERAL(x, y) | |||
/** Surrounds raw text with quotes | |||
Example: | |||
#define NAME "world" | |||
printf("Hello " TOSTRING(NAME)) | |||
expands to | |||
printf("Hello " "world") | |||
and of course the C++ lexer/parser then concatenates the string literals. | |||
*/ | |||
#define TOSTRING_LITERAL(x) #x | |||
#define TOSTRING(x) TOSTRING_LITERAL(x) | |||
/** Produces the length of a static array in number of elements */ | |||
#define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0])) | |||
/** Reserve space for `count` enums starting with `name`. | |||
Example: | |||
enum Foo { | |||
ENUMS(BAR, 14), | |||
BAZ | |||
}; | |||
BAR + 0 to BAR + 13 is reserved. BAZ has a value of 14. | |||
*/ | |||
#define ENUMS(name, count) name, name ## _LAST = name + (count) - 1 | |||
/** Deprecation notice for GCC */ | |||
#define DEPRECATED __attribute__ ((deprecated)) | |||
/** References binary files compiled into the program. | |||
For example, to include a file "Test.dat" directly into your program binary, add | |||
BINARIES += Test.dat | |||
to your Makefile and declare | |||
BINARY(Test_dat); | |||
at the root of a .c or .cpp source file. Note that special characters are replaced with "_". Then use | |||
BINARY_START(Test_dat) | |||
BINARY_END(Test_dat) | |||
to reference the data beginning and end as a void* array, and | |||
BINARY_SIZE(Test_dat) | |||
to get its size in bytes. | |||
*/ | |||
#ifdef ARCH_MAC | |||
// Use output from `xxd -i` | |||
#define BINARY(sym) extern unsigned char sym[]; extern unsigned int sym##_len | |||
#define BINARY_START(sym) ((const void*) sym) | |||
#define BINARY_END(sym) ((const void*) sym + sym##_len) | |||
#define BINARY_SIZE(sym) (sym##_len) | |||
#else | |||
#define BINARY(sym) extern char _binary_##sym##_start, _binary_##sym##_end, _binary_##sym##_size | |||
#define BINARY_START(sym) ((const void*) &_binary_##sym##_start) | |||
#define BINARY_END(sym) ((const void*) &_binary_##sym##_end) | |||
// The symbol "_binary_##sym##_size" doesn't seem to be valid after a plugin is dynamically loaded, so simply take the difference between the two addresses. | |||
#define BINARY_SIZE(sym) ((size_t) (&_binary_##sym##_end - &_binary_##sym##_start)) | |||
#endif | |||
#include "macros.hpp" | |||
#include "math.hpp" | |||
#include "string.hpp" | |||
#include "logger.hpp" | |||
namespace rack { | |||
@@ -148,32 +81,6 @@ float randomNormal(); | |||
DEPRECATED inline float randomf() {return randomUniform();} | |||
//////////////////// | |||
// String utilities | |||
// string.cpp | |||
//////////////////// | |||
/** Converts a printf format string and optional arguments into a std::string */ | |||
std::string stringf(const char *format, ...); | |||
std::string stringLowercase(std::string s); | |||
std::string stringUppercase(std::string s); | |||
/** Truncates and adds "..." to a string, not exceeding `len` characters */ | |||
std::string stringEllipsize(std::string s, size_t len); | |||
bool stringStartsWith(std::string str, std::string prefix); | |||
bool stringEndsWith(std::string str, std::string suffix); | |||
/** Extracts portions of a path */ | |||
std::string stringDirectory(std::string path); | |||
std::string stringFilename(std::string path); | |||
std::string stringExtension(std::string path); | |||
struct StringCaseInsensitiveCompare { | |||
bool operator()(const std::string &a, const std::string &b) const { | |||
return stringLowercase(a) < stringLowercase(b); | |||
} | |||
}; | |||
//////////////////// | |||
// Operating-system specific utilities | |||
// system.cpp | |||
@@ -196,26 +103,6 @@ void systemOpenBrowser(std::string url); | |||
// logger.cpp | |||
//////////////////// | |||
enum LoggerLevel { | |||
DEBUG_LEVEL = 0, | |||
INFO_LEVEL, | |||
WARN_LEVEL, | |||
FATAL_LEVEL | |||
}; | |||
void loggerInit(bool devMode); | |||
void loggerDestroy(); | |||
/** Do not use this function directly. Use the macros below. */ | |||
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_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 | |||
@@ -7,7 +7,7 @@ | |||
#include "util/common.hpp" | |||
#include "events.hpp" | |||
#include "util/color.hpp" | |||
#include "color.hpp" | |||
namespace rack { | |||
@@ -121,13 +121,13 @@ struct MidiCcChoice : GridChoice { | |||
void step() override { | |||
if (module->learningId == id) { | |||
if (0 <= focusCc) | |||
text = stringf("%d", focusCc); | |||
text = string::stringf("%d", focusCc); | |||
else | |||
text = "LRN"; | |||
color.a = 0.5; | |||
} | |||
else { | |||
text = stringf("%d", module->learnedCcs[id]); | |||
text = string::stringf("%d", module->learnedCcs[id]); | |||
color.a = 1.0; | |||
if (gFocusedWidget == this) | |||
gFocusedWidget = NULL; | |||
@@ -317,7 +317,7 @@ struct MIDIToCVInterfaceWidget : ModuleWidget { | |||
menu->addChild(construct<MenuLabel>()); | |||
for (int i = 0; i < 2; i++) { | |||
ClockItem *item = MenuItem::create<ClockItem>(stringf("CLK %d rate", i + 1)); | |||
ClockItem *item = MenuItem::create<ClockItem>(string::stringf("CLK %d rate", i + 1)); | |||
item->module = module; | |||
item->index = i; | |||
menu->addChild(item); | |||
@@ -168,7 +168,7 @@ struct MidiTrigChoice : GridChoice { | |||
}; | |||
int oct = note / 12 - 1; | |||
int semi = note % 12; | |||
text = stringf("%s%d", noteNames[semi], oct); | |||
text = string::stringf("%s%d", noteNames[semi], oct); | |||
color.a = 1.0; | |||
if (gFocusedWidget == this) | |||
@@ -106,13 +106,13 @@ struct AudioSampleRateChoice : LedDisplayChoice { | |||
AudioSampleRateItem *item = new AudioSampleRateItem(); | |||
item->audioIO = audioWidget->audioIO; | |||
item->sampleRate = sampleRate; | |||
item->text = stringf("%d Hz", sampleRate); | |||
item->text = string::stringf("%d Hz", sampleRate); | |||
item->rightText = CHECKMARK(item->sampleRate == audioWidget->audioIO->sampleRate); | |||
menu->addChild(item); | |||
} | |||
} | |||
void step() override { | |||
text = stringf("%g kHz", audioWidget->audioIO->sampleRate / 1000.f); | |||
text = string::stringf("%g kHz", audioWidget->audioIO->sampleRate / 1000.f); | |||
} | |||
}; | |||
@@ -139,13 +139,13 @@ struct AudioBlockSizeChoice : LedDisplayChoice { | |||
item->audioIO = audioWidget->audioIO; | |||
item->blockSize = blockSize; | |||
float latency = (float) blockSize / audioWidget->audioIO->sampleRate * 1000.0; | |||
item->text = stringf("%d (%.1f ms)", blockSize, latency); | |||
item->text = string::stringf("%d (%.1f ms)", blockSize, latency); | |||
item->rightText = CHECKMARK(item->blockSize == audioWidget->audioIO->blockSize); | |||
menu->addChild(item); | |||
} | |||
} | |||
void step() override { | |||
text = stringf("%d", audioWidget->audioIO->blockSize); | |||
text = string::stringf("%d", audioWidget->audioIO->blockSize); | |||
} | |||
}; | |||
@@ -1,5 +1,5 @@ | |||
#include "app.hpp" | |||
#include "util/color.hpp" | |||
#include "color.hpp" | |||
namespace rack { | |||
@@ -18,8 +18,8 @@ static ModelTag sTagFilter = NO_TAG; | |||
bool isMatch(std::string s, std::string search) { | |||
s = stringLowercase(s); | |||
search = stringLowercase(search); | |||
s = string::lowercase(s); | |||
search = string::lowercase(search); | |||
return (s.find(search) != std::string::npos); | |||
} | |||
@@ -279,7 +279,7 @@ struct ModuleBrowser : OpaqueWidget { | |||
SearchModuleField *searchField; | |||
ScrollWidget *moduleScroll; | |||
BrowserList *moduleList; | |||
std::set<std::string, StringCaseInsensitiveCompare> availableAuthors; | |||
std::set<std::string, string::CaseInsensitiveCompare> availableAuthors; | |||
std::set<ModelTag> availableTags; | |||
ModuleBrowser() { | |||
@@ -203,7 +203,7 @@ void ModuleWidget::load(std::string filename) { | |||
json_decref(moduleJ); | |||
} | |||
else { | |||
std::string message = stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | |||
std::string message = string::stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | |||
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); | |||
} | |||
@@ -248,7 +248,7 @@ void ModuleWidget::saveDialog() { | |||
if (path) { | |||
std::string pathStr = path; | |||
free(path); | |||
std::string extension = stringExtension(pathStr); | |||
std::string extension = string::extension(pathStr); | |||
if (extension.empty()) { | |||
pathStr += ".vcvm"; | |||
} | |||
@@ -304,7 +304,7 @@ void ModuleWidget::draw(NVGcontext *vg) { | |||
nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.5)); | |||
nvgFill(vg); | |||
std::string cpuText = stringf("%.0f mS", module->cpuTime * 1000.f); | |||
std::string cpuText = string::stringf("%.0f mS", module->cpuTime * 1000.f); | |||
nvgFontFaceId(vg, gGuiFont->handle); | |||
nvgFontSize(vg, 12); | |||
nvgFillColor(vg, nvgRGBf(1, 1, 1)); | |||
@@ -1,5 +1,5 @@ | |||
#include "app.hpp" | |||
#include "util/color.hpp" | |||
#include "color.hpp" | |||
namespace rack { | |||
@@ -44,7 +44,7 @@ void RackScene::step() { | |||
// Version popup message | |||
if (!gLatestVersion.empty()) { | |||
std::string versionMessage = stringf("Rack %s is available.\n\nYou have Rack %s.\n\nClose Rack and download new version on the website?", gLatestVersion.c_str(), gApplicationVersion.c_str()); | |||
std::string versionMessage = string::stringf("Rack %s is available.\n\nYou have Rack %s.\n\nClose Rack and download new version on the website?", gLatestVersion.c_str(), gApplicationVersion.c_str()); | |||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, versionMessage.c_str())) { | |||
std::thread t(systemOpenBrowser, "https://vcvrack.com/"); | |||
t.detach(); | |||
@@ -116,7 +116,7 @@ void RackScene::onHoverKey(EventHoverKey &e) { | |||
void RackScene::onPathDrop(EventPathDrop &e) { | |||
if (e.paths.size() >= 1) { | |||
const std::string &firstPath = e.paths.front(); | |||
if (stringExtension(firstPath) == "vcv") { | |||
if (string::extension(firstPath) == "vcv") { | |||
gRackWidget->load(firstPath); | |||
e.consumed = true; | |||
} | |||
@@ -75,7 +75,7 @@ void RackWidget::loadDialog() { | |||
systemCreateDirectory(dir); | |||
} | |||
else { | |||
dir = stringDirectory(lastPath); | |||
dir = string::directory(lastPath); | |||
} | |||
osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str()); | |||
char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, filters); | |||
@@ -104,8 +104,8 @@ void RackWidget::saveAsDialog() { | |||
systemCreateDirectory(dir); | |||
} | |||
else { | |||
dir = stringDirectory(lastPath); | |||
filename = stringFilename(lastPath); | |||
dir = string::directory(lastPath); | |||
filename = string::filename(lastPath); | |||
} | |||
osdialog_filters *filters = osdialog_filters_parse(PATCH_FILTERS.c_str()); | |||
char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), filename.c_str(), filters); | |||
@@ -113,7 +113,7 @@ void RackWidget::saveAsDialog() { | |||
if (path) { | |||
std::string pathStr = path; | |||
free(path); | |||
std::string extension = stringExtension(pathStr); | |||
std::string extension = string::extension(pathStr); | |||
if (extension.empty()) { | |||
pathStr += ".vcv"; | |||
} | |||
@@ -155,7 +155,7 @@ void RackWidget::load(std::string filename) { | |||
json_decref(rootJ); | |||
} | |||
else { | |||
std::string message = stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | |||
std::string message = string::stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | |||
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str()); | |||
} | |||
@@ -259,7 +259,7 @@ void RackWidget::fromJson(json_t *rootJ) { | |||
// Detect old patches with ModuleWidget::params/inputs/outputs indices. | |||
// (We now use Module::params/inputs/outputs indices.) | |||
int legacy = 0; | |||
if (stringStartsWith(version, "0.3.") || stringStartsWith(version, "0.4.") || stringStartsWith(version, "0.5.") || version == "" || version == "dev") { | |||
if (string::startsWith(version, "0.3.") || string::startsWith(version, "0.4.") || string::startsWith(version, "0.5.") || version == "" || version == "dev") { | |||
legacy = 1; | |||
} | |||
if (legacy) { | |||
@@ -300,7 +300,7 @@ void RackWidget::fromJson(json_t *rootJ) { | |||
json_t *modelSlugJ = json_object_get(moduleJ, "model"); | |||
std::string pluginSlug = json_string_value(pluginSlugJ); | |||
std::string modelSlug = json_string_value(modelSlugJ); | |||
message += stringf("Could not find module \"%s\" of plugin \"%s\"\n", modelSlug.c_str(), pluginSlug.c_str()); | |||
message += string::stringf("Could not find module \"%s\" of plugin \"%s\"\n", modelSlug.c_str(), pluginSlug.c_str()); | |||
} | |||
} | |||
@@ -132,7 +132,7 @@ struct SampleRateButton : TooltipIconButton { | |||
std::vector<float> sampleRates = {44100, 48000, 88200, 96000, 176400, 192000}; | |||
for (float sampleRate : sampleRates) { | |||
SampleRateItem *item = new SampleRateItem(); | |||
item->text = stringf("%.0f Hz", sampleRate); | |||
item->text = string::stringf("%.0f Hz", sampleRate); | |||
item->rightText = CHECKMARK(engineGetSampleRate() == sampleRate); | |||
item->sampleRate = sampleRate; | |||
menu->addChild(item); | |||
@@ -18,8 +18,9 @@ std::vector<int> AudioIO::getDrivers() { | |||
std::vector<RtAudio::Api> apis; | |||
RtAudio::getCompiledApi(apis); | |||
std::vector<int> drivers; | |||
for (RtAudio::Api api : apis) | |||
for (RtAudio::Api api : apis) { | |||
drivers.push_back((int) api); | |||
} | |||
// Add fake Bridge driver | |||
drivers.push_back(BRIDGE_DRIVER); | |||
return drivers; | |||
@@ -121,7 +122,7 @@ std::string AudioIO::getDeviceName(int device) { | |||
return deviceInfo.name; | |||
} | |||
else if (driver == BRIDGE_DRIVER) { | |||
return stringf("%d", device + 1); | |||
return string::stringf("%d", device + 1); | |||
} | |||
return ""; | |||
} | |||
@@ -133,19 +134,19 @@ std::string AudioIO::getDeviceDetail(int device, int offset) { | |||
if (rtAudio) { | |||
RtAudio::DeviceInfo deviceInfo; | |||
if (getDeviceInfo(device, &deviceInfo)) { | |||
std::string deviceDetail = stringf("%s (", deviceInfo.name.c_str()); | |||
std::string deviceDetail = string::stringf("%s (", deviceInfo.name.c_str()); | |||
if (offset < (int) deviceInfo.inputChannels) | |||
deviceDetail += stringf("%d-%d in", offset + 1, std::min(offset + maxChannels, (int) deviceInfo.inputChannels)); | |||
deviceDetail += string::stringf("%d-%d in", offset + 1, std::min(offset + maxChannels, (int) deviceInfo.inputChannels)); | |||
if (offset < (int) deviceInfo.inputChannels && offset < (int) deviceInfo.outputChannels) | |||
deviceDetail += ", "; | |||
if (offset < (int) deviceInfo.outputChannels) | |||
deviceDetail += stringf("%d-%d out", offset + 1, std::min(offset + maxChannels, (int) deviceInfo.outputChannels)); | |||
deviceDetail += string::stringf("%d-%d out", offset + 1, std::min(offset + maxChannels, (int) deviceInfo.outputChannels)); | |||
deviceDetail += ")"; | |||
return deviceDetail; | |||
} | |||
} | |||
else if (driver == BRIDGE_DRIVER) { | |||
return stringf("Port %d", device + 1); | |||
return string::stringf("Port %d", device + 1); | |||
} | |||
return ""; | |||
} | |||
@@ -384,7 +384,7 @@ std::vector<int> BridgeMidiDriver::getInputDeviceIds() { | |||
std::string BridgeMidiDriver::getInputDeviceName(int deviceId) { | |||
if (deviceId < 0) | |||
return ""; | |||
return stringf("Port %d", deviceId + 1); | |||
return string::stringf("Port %d", deviceId + 1); | |||
} | |||
MidiInputDevice *BridgeMidiDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||
@@ -1,5 +1,5 @@ | |||
#include "gamepad.hpp" | |||
#include <GLFW/glfw3.h> | |||
#include "gamepad.hpp" | |||
namespace rack { | |||
@@ -22,7 +22,7 @@ void GamepadInputDevice::step() { | |||
ccs.resize(numAxes); | |||
for (int i = 0; i < numAxes; i++) { | |||
// Allow CC value to go negative, but math::clamp at -127 instead of -128 for symmetry | |||
int8_t cc = math::clamp((int) roundf(axes[i] * 127), -127, 127); | |||
int8_t cc = math::clamp((int) std::round(axes[i] * 127), -127, 127); | |||
if (cc != ccs[i]) { | |||
ccs[i] = cc; | |||
@@ -77,7 +77,7 @@ std::string GamepadDriver::getInputDeviceName(int deviceId) { | |||
if (name) { | |||
return name; | |||
} | |||
return stringf("Gamepad %d (unavailable)", deviceId + 1); | |||
return string::stringf("Gamepad %d (unavailable)", deviceId + 1); | |||
} | |||
MidiInputDevice *GamepadDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||
@@ -0,0 +1,68 @@ | |||
#include <cstdarg> | |||
#include <chrono> | |||
#include "logger.hpp" | |||
#include "asset.hpp" | |||
namespace rack { | |||
namespace logger { | |||
static FILE *outputFile = NULL; | |||
static std::chrono::high_resolution_clock::time_point startTime; | |||
void init(bool devMode) { | |||
startTime = std::chrono::high_resolution_clock::now(); | |||
if (devMode) { | |||
outputFile = stderr; | |||
} | |||
else { | |||
std::string logFilename = assetLocal("log.txt"); | |||
outputFile = fopen(logFilename.c_str(), "w"); | |||
} | |||
} | |||
void destroy() { | |||
if (outputFile != stderr) { | |||
fclose(outputFile); | |||
} | |||
} | |||
static const char* const levelLabels[] = { | |||
"debug", | |||
"info", | |||
"warn", | |||
"fatal" | |||
}; | |||
static const int levelColors[] = { | |||
35, | |||
34, | |||
33, | |||
31 | |||
}; | |||
static void logVa(Level level, const char *filename, 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(); | |||
if (outputFile == stderr) | |||
fprintf(outputFile, "\x1B[%dm", levelColors[level]); | |||
fprintf(outputFile, "[%.03f %s %s:%d] ", duration / 1000.0, levelLabels[level], filename, line); | |||
if (outputFile == stderr) | |||
fprintf(outputFile, "\x1B[0m"); | |||
vfprintf(outputFile, format, args); | |||
fprintf(outputFile, "\n"); | |||
fflush(outputFile); | |||
} | |||
void log(Level level, const char *filename, int line, const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
logVa(level, filename, line, format, args); | |||
va_end(args); | |||
} | |||
} // namespace logger | |||
} // namespace rack |
@@ -10,7 +10,7 @@ | |||
#include "rtmidi.hpp" | |||
#include "keyboard.hpp" | |||
#include "gamepad.hpp" | |||
#include "util/color.hpp" | |||
#include "color.hpp" | |||
#include "osdialog.h" | |||
#include <unistd.h> | |||
@@ -61,7 +61,7 @@ int main(int argc, char* argv[]) { | |||
// Initialize environment | |||
randomInit(); | |||
assetInit(devMode); | |||
loggerInit(devMode); | |||
logger::init(devMode); | |||
// Log environment | |||
info("%s %s", gApplicationName.c_str(), gApplicationVersion.c_str()); | |||
@@ -116,7 +116,7 @@ int main(int argc, char* argv[]) { | |||
engineDestroy(); | |||
midiDestroy(); | |||
pluginDestroy(); | |||
loggerDestroy(); | |||
logger::destroy(); | |||
return 0; | |||
} |
@@ -79,7 +79,7 @@ std::string MidiIO::getChannelName(int channel) { | |||
if (channel == -1) | |||
return "All channels"; | |||
else | |||
return stringf("Channel %d", channel + 1); | |||
return string::stringf("Channel %d", channel + 1); | |||
} | |||
json_t *MidiIO::toJson() { | |||
@@ -216,7 +216,7 @@ static void loadPlugins(std::string path) { | |||
if (!systemIsDirectory(pluginPath)) | |||
continue; | |||
if (!loadPlugin(pluginPath)) { | |||
message += stringf("Could not load plugin %s\n", pluginPath.c_str()); | |||
message += string::stringf("Could not load plugin %s\n", pluginPath.c_str()); | |||
} | |||
} | |||
if (!message.empty()) { | |||
@@ -298,13 +298,13 @@ static void extractPackages(std::string path) { | |||
std::string message; | |||
for (std::string packagePath : systemListEntries(path)) { | |||
if (stringExtension(packagePath) != "zip") | |||
if (string::extension(packagePath) != "zip") | |||
continue; | |||
info("Extracting package %s", packagePath.c_str()); | |||
// Extract package | |||
if (extractZip(packagePath.c_str(), path.c_str())) { | |||
warn("Package %s failed to extract", packagePath.c_str()); | |||
message += stringf("Could not extract package %s\n", packagePath.c_str()); | |||
message += string::stringf("Could not extract package %s\n", packagePath.c_str()); | |||
continue; | |||
} | |||
// Remove package | |||
@@ -1,6 +1,6 @@ | |||
#include "ui.hpp" | |||
#include "window.hpp" | |||
#include "util/color.hpp" | |||
#include "color.hpp" | |||
namespace rack { | |||
@@ -1,100 +0,0 @@ | |||
#include "util/common.hpp" | |||
#include "asset.hpp" | |||
#include <stdarg.h> | |||
namespace rack { | |||
static FILE *logFile = NULL; | |||
static std::chrono::high_resolution_clock::time_point startTime; | |||
void loggerInit(bool devMode) { | |||
startTime = std::chrono::high_resolution_clock::now(); | |||
if (devMode) { | |||
logFile = stderr; | |||
} | |||
else { | |||
std::string logFilename = assetLocal("log.txt"); | |||
logFile = fopen(logFilename.c_str(), "w"); | |||
} | |||
} | |||
void loggerDestroy() { | |||
if (logFile != stderr) { | |||
fclose(logFile); | |||
} | |||
} | |||
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(); | |||
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(LoggerLevel 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); | |||
loggerLogVa(DEBUG_LEVEL, "", 0, format, args); | |||
va_end(args); | |||
} | |||
void info(const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
loggerLogVa(INFO_LEVEL, "", 0, format, args); | |||
va_end(args); | |||
} | |||
void warn(const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
loggerLogVa(WARN_LEVEL, "", 0, format, args); | |||
va_end(args); | |||
} | |||
void fatal(const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
loggerLogVa(FATAL_LEVEL, "", 0, format, args); | |||
va_end(args); | |||
} | |||
} // namespace rack |
@@ -27,7 +27,7 @@ void QuantityWidget::setDefaultValue(float defaultValue) { | |||
std::string QuantityWidget::getText() { | |||
std::string text = label; | |||
text += ": "; | |||
text += stringf("%.*f", precision, value); | |||
text += string::stringf("%.*f", precision, value); | |||
text += unit; | |||
return text; | |||
} | |||
@@ -3,7 +3,7 @@ | |||
#include "asset.hpp" | |||
#include "gamepad.hpp" | |||
#include "keyboard.hpp" | |||
#include "util/color.hpp" | |||
#include "color.hpp" | |||
#include <map> | |||
#include <queue> | |||
@@ -454,7 +454,7 @@ void windowRun() { | |||
windowTitle += gApplicationVersion; | |||
if (!gRackWidget->lastPath.empty()) { | |||
windowTitle += " - "; | |||
windowTitle += stringFilename(gRackWidget->lastPath); | |||
windowTitle += string::filename(gRackWidget->lastPath); | |||
} | |||
if (windowTitle != lastWindowTitle) { | |||
glfwSetWindowTitle(gWindow, windowTitle.c_str()); | |||