@@ -58,6 +58,7 @@ T *construct(F f, V v, Args... args) { | |||
// RNG | |||
//////////////////// | |||
/** Seeds the RNG with the current time */ | |||
void randomSeedTime(); | |||
uint32_t randomu32(); | |||
uint64_t randomu64(); | |||
@@ -126,5 +127,18 @@ struct VIPLock { | |||
} | |||
}; | |||
//////////////////// | |||
// logger | |||
//////////////////// | |||
enum LogLevel { | |||
INFO, | |||
WARN, | |||
ERROR, | |||
}; | |||
extern FILE *gLogFile; | |||
void log(LogLevel level, const char *format, ...); | |||
} // namespace rack |
@@ -83,7 +83,7 @@ void RackWidget::saveAsDialog() { | |||
void RackWidget::savePatch(std::string path) { | |||
printf("Saving patch %s\n", path.c_str()); | |||
log(INFO, "Saving patch %s", path.c_str()); | |||
FILE *file = fopen(path.c_str(), "w"); | |||
if (!file) | |||
return; | |||
@@ -98,7 +98,7 @@ void RackWidget::savePatch(std::string path) { | |||
} | |||
void RackWidget::loadPatch(std::string path) { | |||
printf("Loading patch %s\n", path.c_str()); | |||
log(INFO, "Loading patch %s", path.c_str()); | |||
FILE *file = fopen(path.c_str(), "r"); | |||
if (!file) { | |||
// Exit silently | |||
@@ -17,7 +17,7 @@ void audioInit() { | |||
PaError err = Pa_Initialize(); | |||
if (err) { | |||
fprintf(stderr, "Failed to initialize PortAudio: %s\n", Pa_GetErrorText(err)); | |||
log(WARN, "Failed to initialize PortAudio: %s", Pa_GetErrorText(err)); | |||
return; | |||
} | |||
initialized = true; | |||
@@ -244,7 +244,7 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { | |||
PaError err; | |||
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(deviceId); | |||
if (!deviceInfo) { | |||
fprintf(stderr, "Failed to query audio device\n"); | |||
log(WARN, "Failed to query audio device"); | |||
return; | |||
} | |||
@@ -271,13 +271,13 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { | |||
numOutputs == 0 ? NULL : &outputParameters, | |||
sampleRate, blockSize, paNoFlag, paCallback, this); | |||
if (err) { | |||
fprintf(stderr, "Failed to open audio stream: %s\n", Pa_GetErrorText(err)); | |||
log(WARN, "Failed to open audio stream: %s", Pa_GetErrorText(err)); | |||
return; | |||
} | |||
err = Pa_StartStream(stream); | |||
if (err) { | |||
fprintf(stderr, "Failed to start audio stream: %s\n", Pa_GetErrorText(err)); | |||
log(WARN, "Failed to start audio stream: %s", Pa_GetErrorText(err)); | |||
return; | |||
} | |||
// This should go after Pa_StartStream because sometimes it will call the callback once synchronously, and that time it should return early | |||
@@ -299,12 +299,12 @@ void AudioInterface::closeDevice() { | |||
err = Pa_AbortStream(stream); | |||
// err = Pa_StopStream(stream); | |||
if (err) { | |||
fprintf(stderr, "Failed to stop audio stream: %s\n", Pa_GetErrorText(err)); | |||
log(WARN, "Failed to stop audio stream: %s", Pa_GetErrorText(err)); | |||
} | |||
err = Pa_CloseStream(stream); | |||
if (err) { | |||
fprintf(stderr, "Failed to close audio stream: %s\n", Pa_GetErrorText(err)); | |||
log(WARN, "Failed to close audio stream: %s", Pa_GetErrorText(err)); | |||
} | |||
} | |||
@@ -17,9 +17,9 @@ MidiIO::MidiIO(bool isOut) { | |||
channel = -1; | |||
this->isOut = isOut; | |||
if (isOut) { | |||
fprintf(stderr, "Midi Out is currently not supported (will be added soon)"); | |||
} | |||
// TODO | |||
// Support MIDI out | |||
assert(!isOut); | |||
}; | |||
void MidiIO::setChannel(int channel) { | |||
@@ -60,7 +60,7 @@ std::vector<std::string> MidiIO::getDevices() { | |||
try { | |||
m = new RtMidiIn(); | |||
} catch (RtMidiError &error) { | |||
fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str()); | |||
log(WARN, "Failed to create RtMidiIn: %s", error.getMessage().c_str()); | |||
return names; | |||
} | |||
@@ -96,14 +96,14 @@ void MidiIO::openDevice(std::string deviceName) { | |||
} | |||
if (!mw->isPortOpen()) { | |||
fprintf(stderr, "Failed to create RtMidiIn: No such device %s\n", deviceName.c_str()); | |||
log(WARN, "Failed to create RtMidiIn: No such device %s", deviceName.c_str()); | |||
this->deviceName = ""; | |||
this->id = -1; | |||
return; | |||
} | |||
} | |||
catch (RtMidiError &error) { | |||
fprintf(stderr, "Failed to create RtMidiIn: %s\n", error.getMessage().c_str()); | |||
log(WARN, "Failed to create RtMidiIn: %s", error.getMessage().c_str()); | |||
this->deviceName = ""; | |||
this->id = -1; | |||
return; | |||
@@ -144,7 +144,7 @@ double MidiIO::getMessage(std::vector<unsigned char> *msg) { | |||
MidiInWrapper *mw = midiInMap[deviceName]; | |||
if (!mw) { | |||
fprintf(stderr, "Device not opened!: %s\n", deviceName.c_str()); | |||
log(WARN, "Device not opened!: %s", deviceName.c_str()); | |||
return 0; | |||
} | |||
@@ -176,7 +176,7 @@ void MidiIO::close() { | |||
MidiInWrapper *mw = midiInMap[deviceName]; | |||
if (!mw || id < 0) { | |||
//fprintf(stderr, "Trying to close already closed device!\n"); | |||
//log(WARN, "Trying to close already closed device!"); | |||
return; | |||
} | |||
@@ -279,7 +279,7 @@ void dropCallback(GLFWwindow *window, int count, const char **paths) { | |||
} | |||
void errorCallback(int error, const char *description) { | |||
fprintf(stderr, "GLFW error %d: %s\n", error, description); | |||
log(WARN, "GLFW error %d: %s", error, description); | |||
} | |||
void renderGui() { | |||
@@ -446,7 +446,7 @@ void guiRun() { | |||
std::this_thread::sleep_for(std::chrono::duration<double>(minTime - frameTime)); | |||
} | |||
endTime = glfwGetTime(); | |||
// printf("%lf fps\n", 1.0 / (endTime - startTime)); | |||
// log(INFO, "%lf fps", 1.0 / (endTime - startTime)); | |||
} | |||
} | |||
@@ -519,10 +519,10 @@ bool guiIsMaximized() { | |||
Font::Font(const std::string &filename) { | |||
handle = nvgCreateFont(gVg, filename.c_str(), filename.c_str()); | |||
if (handle >= 0) { | |||
fprintf(stderr, "Loaded font %s\n", filename.c_str()); | |||
log(INFO, "Loaded font %s", filename.c_str()); | |||
} | |||
else { | |||
fprintf(stderr, "Failed to load font %s\n", filename.c_str()); | |||
log(WARN, "Failed to load font %s", filename.c_str()); | |||
} | |||
} | |||
@@ -545,10 +545,10 @@ std::shared_ptr<Font> Font::load(const std::string &filename) { | |||
Image::Image(const std::string &filename) { | |||
handle = nvgCreateImage(gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||
if (handle > 0) { | |||
fprintf(stderr, "Loaded image %s\n", filename.c_str()); | |||
log(INFO, "Loaded image %s", filename.c_str()); | |||
} | |||
else { | |||
fprintf(stderr, "Failed to load image %s\n", filename.c_str()); | |||
log(WARN, "Failed to load image %s", filename.c_str()); | |||
} | |||
} | |||
@@ -572,10 +572,10 @@ std::shared_ptr<Image> Image::load(const std::string &filename) { | |||
SVG::SVG(const std::string &filename) { | |||
handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI); | |||
if (handle) { | |||
fprintf(stderr, "Loaded SVG %s\n", filename.c_str()); | |||
log(INFO, "Loaded SVG %s", filename.c_str()); | |||
} | |||
else { | |||
fprintf(stderr, "Failed to load SVG %s\n", filename.c_str()); | |||
log(WARN, "Failed to load SVG %s", filename.c_str()); | |||
} | |||
} | |||
@@ -12,18 +12,23 @@ using namespace rack; | |||
int main(int argc, char* argv[]) { | |||
randomSeedTime(); | |||
#ifdef VERSION | |||
std::string logFilename = assetLocal("log.txt"); | |||
gLogFile = fopen(logFilename.c_str()); | |||
#endif | |||
if (!gApplicationVersion.empty()) { | |||
printf("Rack v%s\n", gApplicationVersion.c_str()); | |||
log(INFO, "Rack v%s", gApplicationVersion.c_str()); | |||
} | |||
{ | |||
char *cwd = getcwd(NULL, 0); | |||
printf("Current working directory: %s\n", cwd); | |||
log(INFO, "Current working directory: %s", cwd); | |||
free(cwd); | |||
std::string globalDir = assetGlobal(""); | |||
std::string localDir = assetLocal(""); | |||
printf("Global directory: %s\n", globalDir.c_str()); | |||
printf("Local directory: %s\n", localDir.c_str()); | |||
log(INFO, "Global directory: %s", globalDir.c_str()); | |||
log(INFO, "Local directory: %s", localDir.c_str()); | |||
} | |||
pluginInit(); | |||
@@ -49,5 +54,10 @@ int main(int argc, char* argv[]) { | |||
guiDestroy(); | |||
engineDestroy(); | |||
pluginDestroy(); | |||
#ifdef VERSION | |||
fclose(gLogFile); | |||
#endif | |||
return 0; | |||
} |
@@ -112,13 +112,13 @@ static int loadPlugin(std::string path) { | |||
HINSTANCE handle = LoadLibrary(libraryFilename.c_str()); | |||
if (!handle) { | |||
int error = GetLastError(); | |||
fprintf(stderr, "Failed to load library %s: %d\n", libraryFilename.c_str(), error); | |||
log(WARN, "Failed to load library %s: %d", libraryFilename.c_str(), error); | |||
return -1; | |||
} | |||
#elif ARCH_LIN || ARCH_MAC | |||
void *handle = dlopen(libraryFilename.c_str(), RTLD_NOW); | |||
if (!handle) { | |||
fprintf(stderr, "Failed to load library %s: %s\n", libraryFilename.c_str(), dlerror()); | |||
log(WARN, "Failed to load library %s: %s", libraryFilename.c_str(), dlerror()); | |||
return -1; | |||
} | |||
#endif | |||
@@ -132,7 +132,7 @@ static int loadPlugin(std::string path) { | |||
initCallback = (InitCallback) dlsym(handle, "init"); | |||
#endif | |||
if (!initCallback) { | |||
fprintf(stderr, "Failed to read init() symbol in %s\n", libraryFilename.c_str()); | |||
log(WARN, "Failed to read init() symbol in %s", libraryFilename.c_str()); | |||
return -2; | |||
} | |||
@@ -144,7 +144,7 @@ static int loadPlugin(std::string path) { | |||
// Add plugin to list | |||
gPlugins.push_back(plugin); | |||
fprintf(stderr, "Loaded plugin %s\n", libraryFilename.c_str()); | |||
log(INFO, "Loaded plugin %s", libraryFilename.c_str()); | |||
return 0; | |||
} | |||
@@ -277,14 +277,14 @@ void pluginInit() { | |||
// Load plugins from global directory | |||
std::string globalPlugins = assetGlobal("plugins"); | |||
printf("Loading plugins from %s\n", globalPlugins.c_str()); | |||
log(INFO, "Loading plugins from %s", globalPlugins.c_str()); | |||
loadPlugins(globalPlugins); | |||
// Load plugins from local directory | |||
std::string localPlugins = assetLocal("plugins"); | |||
if (globalPlugins != localPlugins) { | |||
mkdir(localPlugins.c_str(), 0755); | |||
printf("Loading plugins from %s\n", localPlugins.c_str()); | |||
log(INFO, "Loading plugins from %s", localPlugins.c_str()); | |||
loadPlugins(localPlugins); | |||
} | |||
} | |||
@@ -353,7 +353,7 @@ void pluginRefresh() { | |||
json_t *errorJ = json_object_get(resJ, "error"); | |||
if (errorJ) { | |||
const char *errorStr = json_string_value(errorJ); | |||
fprintf(stderr, "Plugin refresh error: %s\n", errorStr); | |||
log(WARN, "Plugin refresh error: %s", errorStr); | |||
} | |||
else { | |||
json_t *purchasesJ = json_object_get(resJ, "purchases"); | |||
@@ -127,7 +127,7 @@ static void settingsFromJson(json_t *rootJ) { | |||
void settingsSave(std::string filename) { | |||
printf("Saving settings %s\n", filename.c_str()); | |||
log(INFO, "Saving settings %s", filename.c_str()); | |||
FILE *file = fopen(filename.c_str(), "w"); | |||
if (!file) | |||
return; | |||
@@ -142,7 +142,7 @@ void settingsSave(std::string filename) { | |||
} | |||
void settingsLoad(std::string filename) { | |||
printf("Loading settings %s\n", filename.c_str()); | |||
log(INFO, "Loading settings %s", filename.c_str()); | |||
FILE *file = fopen(filename.c_str(), "r"); | |||
if (!file) | |||
return; | |||
@@ -154,7 +154,7 @@ void settingsLoad(std::string filename) { | |||
json_decref(rootJ); | |||
} | |||
else { | |||
printf("JSON parsing error at %s %d:%d %s\n", error.source, error.line, error.column, error.text); | |||
log(WARN, "JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); | |||
} | |||
fclose(file); | |||
@@ -1,5 +1,4 @@ | |||
#include "util.hpp" | |||
#include <stdio.h> | |||
#include <stdarg.h> | |||
#include <string.h> | |||
#include <random> | |||
@@ -15,6 +14,10 @@ | |||
namespace rack { | |||
//////////////////// | |||
// RNG | |||
//////////////////// | |||
// xoroshiro128+ | |||
// from http://xoroshiro.di.unimi.it/xoroshiro128plus.c | |||
@@ -36,11 +39,6 @@ static uint64_t xoroshiro128plus_next(void) { | |||
return result; | |||
} | |||
static std::random_device rd; | |||
static std::mt19937 rng(rd()); | |||
static std::normal_distribution<float> normalDist; | |||
void randomSeedTime() { | |||
struct timeval tv; | |||
gettimeofday(&tv, NULL); | |||
@@ -80,6 +78,9 @@ float randomNormal() { | |||
// return (sum - n / 2.f) / sqrtf(n / 12.f); | |||
} | |||
//////////////////// | |||
// String functions | |||
//////////////////// | |||
std::string stringf(const char *format, ...) { | |||
va_list args; | |||
@@ -136,6 +137,10 @@ std::string extractExtension(std::string path) { | |||
return ext + 1; | |||
} | |||
//////////////////// | |||
// Operating system functions | |||
//////////////////// | |||
void openBrowser(std::string url) { | |||
#if ARCH_LIN | |||
std::string command = "xdg-open " + url; | |||
@@ -150,5 +155,32 @@ void openBrowser(std::string url) { | |||
#endif | |||
} | |||
//////////////////// | |||
// logger | |||
//////////////////// | |||
FILE *gLogFile = stderr; | |||
void log(LogLevel level, const char *format, ...) { | |||
va_list args; | |||
va_start(args, format); | |||
switch (level) { | |||
case INFO: | |||
fprintf(gLogFile, "[info] "); | |||
break; | |||
case WARN: | |||
fprintf(gLogFile, "[warning] "); | |||
break; | |||
case ERROR: | |||
fprintf(gLogFile, "[error] "); | |||
break; | |||
default: | |||
break; | |||
} | |||
vfprintf(gLogFile, format, args); | |||
fprintf(gLogFile, "\n"); | |||
va_end(args); | |||
} | |||
} // namespace rack |
@@ -1,4 +1,5 @@ | |||
#include "util/request.hpp" | |||
#include "util.hpp" | |||
#include <assert.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
@@ -82,7 +83,7 @@ json_t *requestJson(RequestMethod method, std::string url, json_t *dataJ) { | |||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resText); | |||
// Perform request | |||
printf("Requesting %s\n", url.c_str()); | |||
log(INFO, "Requesting %s", url.c_str()); | |||
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); | |||
CURLcode res = curl_easy_perform(curl); | |||
@@ -130,7 +131,7 @@ bool requestDownload(std::string url, std::string filename, float *progress) { | |||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferInfoCallback); | |||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, progress); | |||
printf("Downloading %s\n", url.c_str()); | |||
log(INFO, "Downloading %s", url.c_str()); | |||
CURLcode res = curl_easy_perform(curl); | |||
curl_easy_cleanup(curl); | |||
@@ -64,7 +64,7 @@ void FramebufferWidget::draw(NVGcontext *vg) { | |||
if (fbSize.isZero()) | |||
return; | |||
// printf("rendering framebuffer %f %f\n", fbSize.x, fbSize.y); | |||
// log(INFO, "rendering framebuffer %f %f", fbSize.x, fbSize.y); | |||
// Delete old one first to free up GPU memory | |||
internal->setFramebuffer(NULL); | |||
// Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context. | |||
@@ -8,7 +8,7 @@ void SpriteWidget::draw(NVGcontext *vg) { | |||
nvgImageSize(vg, spriteImage->handle, &width, &height); | |||
int stride = width / spriteSize.x; | |||
if (stride == 0) { | |||
printf("Size of SpriteWidget is %d, %d but spriteSize is %f, %f\n", width, height, spriteSize.x, spriteSize.y); | |||
log(WARN, "Size of SpriteWidget is %d, %d but spriteSize is %f, %f", width, height, spriteSize.x, spriteSize.y); | |||
return; | |||
} | |||
Vec offset = Vec((index % stride) * spriteSize.x, (index / stride) * spriteSize.y); | |||
@@ -14,7 +14,6 @@ Rect TransformWidget::getChildrenBoundingBox() { | |||
Vec bottomRight = bound.getBottomRight(); | |||
nvgTransformPoint(&topLeft.x, &topLeft.y, transform, topLeft.x, topLeft.y); | |||
nvgTransformPoint(&bottomRight.x, &bottomRight.y, transform, bottomRight.x, bottomRight.y); | |||
printf("%f\n", 42.1); | |||
return Rect(topLeft, bottomRight.minus(topLeft)); | |||
} | |||