| @@ -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() { | ||||