| @@ -16,3 +16,6 @@ | |||
| [submodule "dep/rtaudio"] | |||
| path = dep/rtaudio | |||
| url = https://github.com/thestk/rtaudio.git | |||
| [submodule "dep/argagg"] | |||
| path = dep/argagg | |||
| url = https://github.com/vietjtnguyen/argagg.git | |||
| @@ -50,8 +50,9 @@ nanosvg = include/nanosvg.h | |||
| oui-blendish = include/blendish.h | |||
| osdialog = include/osdialog.h | |||
| pffft = include/pffft.h | |||
| argagg = include/argagg.hpp | |||
| DEPS += $(glew) $(glfw) $(jansson) $(libspeexdsp) $(libcurl) $(libzip) $(rtmidi) $(rtaudio) $(nanovg) $(nanosvg) $(oui-blendish) $(osdialog) $(pffft) | |||
| DEPS += $(glew) $(glfw) $(jansson) $(libspeexdsp) $(libcurl) $(libzip) $(rtmidi) $(rtaudio) $(nanovg) $(nanosvg) $(oui-blendish) $(osdialog) $(pffft) $(argagg) | |||
| include $(RACK_DIR)/dep.mk | |||
| @@ -163,6 +164,9 @@ $(pffft): | |||
| $(WGET) "https://bitbucket.org/jpommier/pffft/get/29e4f76ac53b.zip" | |||
| $(UNZIP) 29e4f76ac53b.zip | |||
| cp jpommier-pffft-29e4f76ac53b/*.h include/ | |||
| $(argagg): $(wildcard argagg/include/argagg/*.hpp) | |||
| cp argagg/include/argagg/*.hpp include/ | |||
| clean: | |||
| git clean -fdx | |||
| @@ -0,0 +1 @@ | |||
| Subproject commit 24f1dd7fd222b2c70b1f02109761f6bc698e5f68 | |||
| @@ -7,7 +7,7 @@ | |||
| namespace rack { | |||
| void assetInit(bool devMode); | |||
| void assetInit(bool devMode, std::string customGlobalDir = std::string(), std::string customLocalDir = std::string()); | |||
| /** Returns the path of a global resource. Should only read files from this location. */ | |||
| std::string assetGlobal(std::string filename); | |||
| /** Returns the path of a local resource. Can read and write files to this location. */ | |||
| @@ -22,7 +22,7 @@ struct BridgeMidiDriver : MidiDriver { | |||
| }; | |||
| void bridgeInit(); | |||
| void bridgeInit(int customPort = BRIDGE_PORT); | |||
| void bridgeDestroy(); | |||
| void bridgeAudioSubscribe(int channel, AudioIO *audio); | |||
| void bridgeAudioUnsubscribe(int channel, AudioIO *audio); | |||
| @@ -19,6 +19,7 @@ | |||
| #include <pwd.h> | |||
| #endif | |||
| #include <iostream> | |||
| namespace rack { | |||
| @@ -27,58 +28,88 @@ static std::string globalDir; | |||
| static std::string localDir; | |||
| void assetInit(bool devMode) { | |||
| void assetInit(bool devMode, std::string customGlobalDir, std::string customLocalDir) { | |||
| if (devMode) { | |||
| // Use current working directory if running in development mode | |||
| globalDir = "."; | |||
| localDir = "."; | |||
| return; | |||
| // Use current working directory by default if running in development mode | |||
| if (customGlobalDir.empty()) { | |||
| customGlobalDir = "."; | |||
| } | |||
| if (customLocalDir.empty()) { | |||
| customLocalDir = "."; | |||
| } | |||
| } | |||
| if (customGlobalDir.empty()) { | |||
| #if ARCH_MAC | |||
| CFBundleRef bundle = CFBundleGetMainBundle(); | |||
| assert(bundle); | |||
| CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(bundle); | |||
| char resourcesBuf[PATH_MAX]; | |||
| Boolean success = CFURLGetFileSystemRepresentation(resourcesUrl, TRUE, (UInt8*) resourcesBuf, sizeof(resourcesBuf)); | |||
| assert(success); | |||
| CFRelease(resourcesUrl); | |||
| globalDir = resourcesBuf; | |||
| // Get home directory | |||
| struct passwd *pw = getpwuid(getuid()); | |||
| assert(pw); | |||
| localDir = pw->pw_dir; | |||
| localDir += "/Documents/Rack"; | |||
| CFBundleRef bundle = CFBundleGetMainBundle(); | |||
| assert(bundle); | |||
| CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(bundle); | |||
| char resourcesBuf[PATH_MAX]; | |||
| Boolean success = CFURLGetFileSystemRepresentation(resourcesUrl, TRUE, (UInt8*) resourcesBuf, sizeof(resourcesBuf)); | |||
| assert(success); | |||
| CFRelease(resourcesUrl); | |||
| globalDir = resourcesBuf; | |||
| #endif | |||
| #if ARCH_WIN | |||
| char moduleBuf[MAX_PATH]; | |||
| DWORD length = GetModuleFileName(NULL, moduleBuf, sizeof(moduleBuf)); | |||
| assert(length > 0); | |||
| PathRemoveFileSpec(moduleBuf); | |||
| globalDir = moduleBuf; | |||
| // Get "My Documents" folder | |||
| char documentsBuf[MAX_PATH]; | |||
| HRESULT result = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, documentsBuf); | |||
| assert(result == S_OK); | |||
| localDir = documentsBuf; | |||
| localDir += "/Rack"; | |||
| char moduleBuf[MAX_PATH]; | |||
| DWORD length = GetModuleFileName(NULL, moduleBuf, sizeof(moduleBuf)); | |||
| assert(length > 0); | |||
| PathRemoveFileSpec(moduleBuf); | |||
| globalDir = moduleBuf; | |||
| #endif | |||
| #if ARCH_LIN | |||
| // TODO For now, users should launch Rack from their terminal in the global directory | |||
| globalDir = "."; | |||
| // TODO For now, users should launch Rack from their terminal in the global directory | |||
| globalDir = "."; | |||
| #endif | |||
| } | |||
| else { | |||
| if (!systemIsDirectory(customGlobalDir)) { | |||
| std::cerr << "Selected global directory \"" << customGlobalDir << "\" does not exist or is not a directory, default to current directory." << std::endl; | |||
| globalDir = "."; | |||
| } | |||
| else { | |||
| globalDir = customGlobalDir; | |||
| } | |||
| } | |||
| // Get home directory | |||
| const char *homeBuf = getenv("HOME"); | |||
| if (!homeBuf) { | |||
| if (customLocalDir.empty()) { | |||
| #if ARCH_MAC | |||
| // Get home directory | |||
| struct passwd *pw = getpwuid(getuid()); | |||
| assert(pw); | |||
| homeBuf = pw->pw_dir; | |||
| } | |||
| localDir = homeBuf; | |||
| localDir += "/.Rack"; | |||
| localDir = pw->pw_dir; | |||
| localDir += "/Documents/Rack"; | |||
| #endif | |||
| #if ARCH_WIN | |||
| // Get "My Documents" folder | |||
| char documentsBuf[MAX_PATH]; | |||
| HRESULT result = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, documentsBuf); | |||
| assert(result == S_OK); | |||
| localDir = documentsBuf; | |||
| localDir += "/Rack"; | |||
| #endif | |||
| #if ARCH_LIN | |||
| // Get home directory | |||
| const char *homeBuf = getenv("HOME"); | |||
| if (!homeBuf) { | |||
| struct passwd *pw = getpwuid(getuid()); | |||
| assert(pw); | |||
| homeBuf = pw->pw_dir; | |||
| } | |||
| localDir = homeBuf; | |||
| localDir += "/.Rack"; | |||
| #endif | |||
| } | |||
| else { | |||
| if (!systemIsDirectory(customLocalDir)) { | |||
| std::cerr << "Selected local directory \"" << customLocalDir << "\" does not exist or is not a directory, default to current directory." << std::endl; | |||
| localDir = "."; | |||
| } | |||
| else { | |||
| localDir = customLocalDir; | |||
| } | |||
| } | |||
| } | |||
| @@ -282,7 +282,7 @@ static void clientRun(int client) { | |||
| } | |||
| static void serverConnect() { | |||
| static void serverConnect(int customPort) { | |||
| // Initialize sockets | |||
| #if ARCH_WIN | |||
| WSADATA wsaData; | |||
| @@ -299,7 +299,8 @@ static void serverConnect() { | |||
| struct sockaddr_in addr; | |||
| memset(&addr, 0, sizeof(addr)); | |||
| addr.sin_family = AF_INET; | |||
| addr.sin_port = htons(BRIDGE_PORT); | |||
| warn("Bridge server port: %i", customPort); | |||
| addr.sin_port = htons(customPort); | |||
| #if ARCH_WIN | |||
| addr.sin_addr.s_addr = inet_addr(BRIDGE_HOST); | |||
| #else | |||
| @@ -365,10 +366,10 @@ static void serverConnect() { | |||
| } | |||
| } | |||
| static void serverRun() { | |||
| static void serverRun(int customPort) { | |||
| while (serverRunning) { | |||
| std::this_thread::sleep_for(std::chrono::duration<double>(0.1)); | |||
| serverConnect(); | |||
| serverConnect(customPort); | |||
| } | |||
| } | |||
| @@ -403,9 +404,9 @@ void BridgeMidiDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput | |||
| } | |||
| void bridgeInit() { | |||
| void bridgeInit(int customPort) { | |||
| serverRunning = true; | |||
| serverThread = std::thread(serverRun); | |||
| serverThread = std::thread(serverRun, customPort); | |||
| driver = new BridgeMidiDriver(); | |||
| midiDriverAdd(BRIDGE_DRIVER, driver); | |||
| @@ -13,6 +13,8 @@ | |||
| #include "util/color.hpp" | |||
| #include "osdialog.h" | |||
| #include "argagg.hpp" | |||
| #include <unistd.h> | |||
| @@ -22,25 +24,58 @@ using namespace rack; | |||
| int main(int argc, char* argv[]) { | |||
| bool devMode = false; | |||
| std::string patchFile; | |||
| std::string customLocalDir; | |||
| std::string customGlobalDir; | |||
| int customBridgePort = -1; | |||
| // Parse command line arguments | |||
| int c; | |||
| opterr = 0; | |||
| while ((c = getopt(argc, argv, "d")) != -1) { | |||
| switch (c) { | |||
| case 'd': { | |||
| devMode = true; | |||
| } break; | |||
| default: break; | |||
| } | |||
| argagg::parser argparser {{ | |||
| { "help", {"-h", "--help"}, "shows this help message", 0}, | |||
| { "devmod", {"-d", "--devmod"}, "enables dev mode (will default local/global folders to current folder)", 0}, | |||
| { "global", {"-g", "--globaldir"}, "set golbalDir", 1}, | |||
| { "local", {"-l", "--localdir"}, "set localDir", 1}, | |||
| { "port", {"-p", "--port"}, "Bridge port number", 1}, | |||
| }}; | |||
| argagg::parser_results args; | |||
| try { | |||
| args = argparser.parse(argc, argv); | |||
| } catch (const std::exception& e) { | |||
| std::cerr << "Encountered exception while parsing arguments: " << e.what() << std::endl; | |||
| return EXIT_FAILURE; | |||
| } | |||
| if (args["help"]) { | |||
| std::cerr << "Usage: program [options] [FILENAME]" << std::endl; | |||
| std::cerr << argparser; | |||
| return EXIT_SUCCESS; | |||
| } | |||
| if (args["devmod"]) { | |||
| devMode = true; | |||
| } | |||
| if (args["global"]) { | |||
| customGlobalDir = args["global"].as<std::string>(); | |||
| } | |||
| if (optind < argc) { | |||
| patchFile = argv[optind]; | |||
| if (args["local"]) { | |||
| customLocalDir = args["local"].as<std::string>(); | |||
| } | |||
| if (args["port"]) { | |||
| customBridgePort = args["port"].as<int>(); | |||
| } | |||
| // Filename as first positional argument | |||
| if (args.pos.size() > 0) { | |||
| patchFile = args.as<std::string>(0); | |||
| } | |||
| // Initialize environment | |||
| randomInit(); | |||
| assetInit(devMode); | |||
| assetInit(devMode, customGlobalDir, customLocalDir); | |||
| loggerInit(devMode); | |||
| // Log environment | |||
| @@ -54,7 +89,12 @@ int main(int argc, char* argv[]) { | |||
| pluginInit(devMode); | |||
| engineInit(); | |||
| rtmidiInit(); | |||
| bridgeInit(); | |||
| if (customBridgePort > 0) { | |||
| bridgeInit(customBridgePort); | |||
| } | |||
| else { | |||
| bridgeInit(); | |||
| } | |||
| keyboardInit(); | |||
| gamepadInit(); | |||
| windowInit(); | |||