@@ -1,5 +1,6 @@ | |||||
#pragma once | #pragma once | ||||
#include <common.hpp> | #include <common.hpp> | ||||
#include <context.hpp> | |||||
#include <jansson.h> | #include <jansson.h> | ||||
#include <vector> | #include <vector> | ||||
#include <set> | #include <set> | ||||
@@ -106,6 +107,7 @@ struct Port { | |||||
/** Not owned */ | /** Not owned */ | ||||
Driver* driver = NULL; | Driver* driver = NULL; | ||||
Device* device = NULL; | Device* device = NULL; | ||||
Context* context; | |||||
Port(); | Port(); | ||||
virtual ~Port(); | virtual ~Port(); | ||||
@@ -47,6 +47,10 @@ void contextInit(); | |||||
void contextDestroy(); | void contextDestroy(); | ||||
/** Returns the global Context pointer */ | /** Returns the global Context pointer */ | ||||
Context* contextGet(); | Context* contextGet(); | ||||
/** Sets the context for this thread. | |||||
You must call this every thread if you want to use the APP macro in that thread. | |||||
*/ | |||||
void contextSet(Context* context); | |||||
/** Accesses the global Context pointer */ | /** Accesses the global Context pointer */ | ||||
#define APP rack::contextGet() | #define APP rack::contextGet() | ||||
@@ -1,5 +1,6 @@ | |||||
#pragma once | #pragma once | ||||
#include <common.hpp> | #include <common.hpp> | ||||
#include <context.hpp> | |||||
#include <vector> | #include <vector> | ||||
#include <queue> | #include <queue> | ||||
#include <set> | #include <set> | ||||
@@ -154,6 +155,7 @@ struct Port { | |||||
/** Not owned */ | /** Not owned */ | ||||
Driver* driver = NULL; | Driver* driver = NULL; | ||||
Device* device = NULL; | Device* device = NULL; | ||||
Context* context; | |||||
Port(); | Port(); | ||||
virtual ~Port(); | virtual ~Port(); | ||||
@@ -54,24 +54,30 @@ std::string Device::getDetail(int offset, int maxChannels) { | |||||
void Device::processBuffer(const float* input, int inputStride, float* output, int outputStride, int frames) { | void Device::processBuffer(const float* input, int inputStride, float* output, int outputStride, int frames) { | ||||
for (Port* port : subscribed) { | for (Port* port : subscribed) { | ||||
// Setting the thread context should probably be the responsibility of Port, but because processInput() etc are overridden, this is the only good place for it. | |||||
contextSet(port->context); | |||||
port->processInput(input + port->offset, inputStride, frames); | port->processInput(input + port->offset, inputStride, frames); | ||||
} | } | ||||
for (Port* port : subscribed) { | for (Port* port : subscribed) { | ||||
contextSet(port->context); | |||||
port->processBuffer(input + port->offset, inputStride, output + port->offset, outputStride, frames); | port->processBuffer(input + port->offset, inputStride, output + port->offset, outputStride, frames); | ||||
} | } | ||||
for (Port* port : subscribed) { | for (Port* port : subscribed) { | ||||
contextSet(port->context); | |||||
port->processOutput(output + port->offset, outputStride, frames); | port->processOutput(output + port->offset, outputStride, frames); | ||||
} | } | ||||
} | } | ||||
void Device::onOpenStream() { | void Device::onOpenStream() { | ||||
for (Port* port : subscribed) { | for (Port* port : subscribed) { | ||||
contextSet(port->context); | |||||
port->onOpenStream(); | port->onOpenStream(); | ||||
} | } | ||||
} | } | ||||
void Device::onCloseStream() { | void Device::onCloseStream() { | ||||
for (Port* port : subscribed) { | for (Port* port : subscribed) { | ||||
contextSet(port->context); | |||||
port->onCloseStream(); | port->onCloseStream(); | ||||
} | } | ||||
} | } | ||||
@@ -82,6 +88,7 @@ void Device::onCloseStream() { | |||||
Port::Port() { | Port::Port() { | ||||
reset(); | reset(); | ||||
context = contextGet(); | |||||
} | } | ||||
Port::~Port() { | Port::~Port() { | ||||
@@ -45,7 +45,7 @@ Context::~Context() { | |||||
} | } | ||||
static Context* context = NULL; | |||||
static thread_local Context* context = NULL; | |||||
void contextInit() { | void contextInit() { | ||||
assert(!context); | assert(!context); | ||||
@@ -60,8 +60,13 @@ void contextDestroy() { | |||||
} | } | ||||
Context* contextGet() { | Context* contextGet() { | ||||
assert(context); | |||||
return context; | return context; | ||||
} | } | ||||
void contextSet(Context* context) { | |||||
rack::context = context; | |||||
} | |||||
} // namespace rack | } // namespace rack |
@@ -172,6 +172,7 @@ struct Engine::Internal { | |||||
HybridBarrier engineBarrier; | HybridBarrier engineBarrier; | ||||
HybridBarrier workerBarrier; | HybridBarrier workerBarrier; | ||||
std::atomic<int> workerModuleIndex; | std::atomic<int> workerModuleIndex; | ||||
Context* context; | |||||
}; | }; | ||||
@@ -386,6 +387,7 @@ static void Engine_relaunchWorkers(Engine* that, int threadCount) { | |||||
Engine::Engine() { | Engine::Engine() { | ||||
internal = new Internal; | internal = new Internal; | ||||
internal->context = contextGet(); | |||||
internal->sampleRate = 44100.f; | internal->sampleRate = 44100.f; | ||||
internal->sampleTime = 1 / internal->sampleRate; | internal->sampleTime = 1 / internal->sampleRate; | ||||
} | } | ||||
@@ -1036,6 +1038,7 @@ void Engine::fromJson(json_t* rootJ) { | |||||
void EngineWorker::run() { | void EngineWorker::run() { | ||||
// Configure thread | // Configure thread | ||||
contextSet(engine->internal->context); | |||||
system::setThreadName(string::f("Worker %d", id)); | system::setThreadName(string::f("Worker %d", id)); | ||||
initMXCSR(); | initMXCSR(); | ||||
random::init(); | random::init(); | ||||
@@ -170,8 +170,8 @@ int main(int argc, char* argv[]) { | |||||
windowInit(); | windowInit(); | ||||
} | } | ||||
// Initialize app | |||||
INFO("Initializing app"); | |||||
// Initialize context | |||||
INFO("Initializing context"); | |||||
contextInit(); | contextInit(); | ||||
// On Mac, use a hacked-in GLFW addition to get the launched path. | // On Mac, use a hacked-in GLFW addition to get the launched path. | ||||
@@ -201,11 +201,11 @@ int main(int argc, char* argv[]) { | |||||
INFO("Stopped window"); | INFO("Stopped window"); | ||||
} | } | ||||
// Destroy app | |||||
// Destroy context | |||||
if (!settings::headless) { | if (!settings::headless) { | ||||
APP->patch->save(asset::autosavePath); | APP->patch->save(asset::autosavePath); | ||||
} | } | ||||
INFO("Destroying app"); | |||||
INFO("Destroying context"); | |||||
contextDestroy(); | contextDestroy(); | ||||
if (!settings::headless) { | if (!settings::headless) { | ||||
settings::save(asset::settingsPath); | settings::save(asset::settingsPath); | ||||
@@ -33,6 +33,7 @@ void InputDevice::onMessage(const Message &message) { | |||||
msg.timestamp = system::getNanoseconds(); | msg.timestamp = system::getNanoseconds(); | ||||
for (Input* input : subscribed) { | for (Input* input : subscribed) { | ||||
contextSet(input->context); | |||||
// Filter channel | // Filter channel | ||||
if (input->channel < 0 || msg.getStatus() == 0xf || msg.getChannel() == input->channel) { | if (input->channel < 0 || msg.getStatus() == 0xf || msg.getChannel() == input->channel) { | ||||
input->onMessage(msg); | input->onMessage(msg); | ||||
@@ -55,6 +56,7 @@ void OutputDevice::unsubscribe(Output* output) { | |||||
//////////////////// | //////////////////// | ||||
Port::Port() { | Port::Port() { | ||||
context = contextGet(); | |||||
} | } | ||||
Port::~Port() { | Port::~Port() { | ||||