| @@ -66,7 +66,7 @@ JUCE_DECL_JACK_FUNCTION (int, jack_set_process_callback, (jack_client_t* client, | |||||
| JUCE_DECL_JACK_FUNCTION (const char**, jack_get_ports, (jack_client_t* client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags), (client, port_name_pattern, type_name_pattern, flags)); | JUCE_DECL_JACK_FUNCTION (const char**, jack_get_ports, (jack_client_t* client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags), (client, port_name_pattern, type_name_pattern, flags)); | ||||
| JUCE_DECL_JACK_FUNCTION (int, jack_connect, (jack_client_t* client, const char* source_port, const char* destination_port), (client, source_port, destination_port)); | JUCE_DECL_JACK_FUNCTION (int, jack_connect, (jack_client_t* client, const char* source_port, const char* destination_port), (client, source_port, destination_port)); | ||||
| JUCE_DECL_JACK_FUNCTION (const char*, jack_port_name, (const jack_port_t* port), (port)); | JUCE_DECL_JACK_FUNCTION (const char*, jack_port_name, (const jack_port_t* port), (port)); | ||||
| JUCE_DECL_JACK_FUNCTION (int, jack_set_port_connect_callback, (jack_client_t* client, JackPortConnectCallback connect_callback, void* arg), (client, connect_callback, arg)); | |||||
| JUCE_DECL_JACK_FUNCTION (void*, jack_set_port_connect_callback, (jack_client_t* client, JackPortConnectCallback connect_callback, void* arg), (client, connect_callback, arg)); | |||||
| JUCE_DECL_JACK_FUNCTION (jack_port_t* , jack_port_by_id, (jack_client_t* client, jack_port_id_t port_id), (client, port_id)); | JUCE_DECL_JACK_FUNCTION (jack_port_t* , jack_port_by_id, (jack_client_t* client, jack_port_id_t port_id), (client, port_id)); | ||||
| JUCE_DECL_JACK_FUNCTION (int, jack_port_connected, (const jack_port_t* port), (port)); | JUCE_DECL_JACK_FUNCTION (int, jack_port_connected, (const jack_port_t* port), (port)); | ||||
| JUCE_DECL_JACK_FUNCTION (int, jack_port_connected_to, (const jack_port_t* port, const char* port_name), (port, port_name)); | JUCE_DECL_JACK_FUNCTION (int, jack_port_connected_to, (const jack_port_t* port, const char* port_name), (port, port_name)); | ||||
| @@ -106,9 +106,11 @@ namespace | |||||
| static const char** getJackPorts (jack_client_t* const client, const bool forInput) | static const char** getJackPorts (jack_client_t* const client, const bool forInput) | ||||
| { | { | ||||
| return juce::jack_get_ports (client, nullptr, nullptr, | |||||
| forInput ? JackPortIsOutput : JackPortIsInput); | |||||
| // (NB: This looks like it's the wrong way round, but it is correct!) | |||||
| if (client != nullptr) | |||||
| return juce::jack_get_ports (client, nullptr, nullptr, | |||||
| forInput ? JackPortIsOutput : JackPortIsInput); | |||||
| // (NB: This looks like it's the wrong way round, but it is correct!) | |||||
| return nullptr; | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -216,6 +218,7 @@ public: | |||||
| close(); | close(); | ||||
| juce::jack_set_process_callback (client, processCallback, this); | juce::jack_set_process_callback (client, processCallback, this); | ||||
| juce::jack_set_port_connect_callback (client, portConnectCallback, this); | |||||
| juce::jack_on_shutdown (client, shutdownCallback, this); | juce::jack_on_shutdown (client, shutdownCallback, this); | ||||
| juce::jack_activate (client); | juce::jack_activate (client); | ||||
| isOpen_ = true; | isOpen_ = true; | ||||
| @@ -264,6 +267,8 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| updateActivePorts(); | |||||
| return lastError; | return lastError; | ||||
| } | } | ||||
| @@ -275,6 +280,7 @@ public: | |||||
| { | { | ||||
| juce::jack_deactivate (client); | juce::jack_deactivate (client); | ||||
| juce::jack_set_process_callback (client, processCallback, nullptr); | juce::jack_set_process_callback (client, processCallback, nullptr); | ||||
| juce::jack_set_port_connect_callback (client, portConnectCallback, nullptr); | |||||
| juce::jack_on_shutdown (client, shutdownCallback, nullptr); | juce::jack_on_shutdown (client, shutdownCallback, nullptr); | ||||
| } | } | ||||
| @@ -312,27 +318,8 @@ public: | |||||
| int getCurrentBitDepth() { return 32; } | int getCurrentBitDepth() { return 32; } | ||||
| String getLastError() { return lastError; } | String getLastError() { return lastError; } | ||||
| BigInteger getActiveOutputChannels() const | |||||
| { | |||||
| BigInteger outputBits; | |||||
| for (int i = 0; i < outputPorts.size(); i++) | |||||
| if (juce::jack_port_connected ((jack_port_t*) outputPorts [i])) | |||||
| outputBits.setBit (i); | |||||
| return outputBits; | |||||
| } | |||||
| BigInteger getActiveInputChannels() const | |||||
| { | |||||
| BigInteger inputBits; | |||||
| for (int i = 0; i < inputPorts.size(); i++) | |||||
| if (juce::jack_port_connected ((jack_port_t*) inputPorts [i])) | |||||
| inputBits.setBit (i); | |||||
| return inputBits; | |||||
| } | |||||
| BigInteger getActiveOutputChannels() const { return activeOutputChannels; } | |||||
| BigInteger getActiveInputChannels() const { return activeInputChannels; } | |||||
| int getOutputLatencyInSamples() | int getOutputLatencyInSamples() | ||||
| { | { | ||||
| @@ -363,24 +350,27 @@ private: | |||||
| for (int i = 0; i < totalNumberOfInputChannels; ++i) | for (int i = 0; i < totalNumberOfInputChannels; ++i) | ||||
| { | { | ||||
| if (jack_default_audio_sample_t* in | |||||
| = (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) inputPorts.getUnchecked(i), numSamples)) | |||||
| inChans [numActiveInChans++] = (float*) in; | |||||
| if (activeInputChannels[i]) | |||||
| if (jack_default_audio_sample_t* in | |||||
| = (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) inputPorts.getUnchecked(i), numSamples)) | |||||
| inChans [numActiveInChans++] = (float*) in; | |||||
| } | } | ||||
| for (int i = 0; i < totalNumberOfOutputChannels; ++i) | for (int i = 0; i < totalNumberOfOutputChannels; ++i) | ||||
| { | { | ||||
| if (jack_default_audio_sample_t* out | |||||
| = (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) outputPorts.getUnchecked(i), numSamples)) | |||||
| outChans [numActiveOutChans++] = (float*) out; | |||||
| if (activeOutputChannels[i]) | |||||
| if (jack_default_audio_sample_t* out | |||||
| = (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) outputPorts.getUnchecked(i), numSamples)) | |||||
| outChans [numActiveOutChans++] = (float*) out; | |||||
| } | } | ||||
| const ScopedLock sl (callbackLock); | const ScopedLock sl (callbackLock); | ||||
| if (callback != nullptr) | if (callback != nullptr) | ||||
| { | { | ||||
| callback->audioDeviceIOCallback (const_cast <const float**> (inChans.getData()), numActiveInChans, | |||||
| outChans, numActiveOutChans, numSamples); | |||||
| if ((numActiveInputChannels + numActiveOutputChannels) > 0) | |||||
| callback->audioDeviceIOCallback (const_cast <const float**> (inChans.getData()), numActiveInChans, | |||||
| outChans, numActiveOutChans, numSamples); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -397,6 +387,30 @@ private: | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| void updateActivePorts() | |||||
| { | |||||
| // This function is called on open(), and from jack as callback on external | |||||
| // jack port changes. Jules, is there any risk that this can happen in a | |||||
| // separate thread from the audio thread, meaning we need a critical section? | |||||
| // the below two activeOut/InputChannels are used in process() | |||||
| activeOutputChannels.clear(); | |||||
| activeInputChannels.clear(); | |||||
| for (int i = 0; i < outputPorts.size(); ++i) | |||||
| if (juce::jack_port_connected ((jack_port_t*) outputPorts.getUnchecked(i))) | |||||
| activeOutputChannels.setBit (i); | |||||
| for (int i = 0; i < inputPorts.size(); ++i) | |||||
| if (juce::jack_port_connected ((jack_port_t*) inputPorts.getUnchecked(i))) | |||||
| activeInputChannels.setBit (i); | |||||
| } | |||||
| static void portConnectCallback (jack_port_id_t, jack_port_id_t, int, void* callbackArgument) | |||||
| { | |||||
| if (callbackArgument != nullptr) | |||||
| static_cast<JackAudioIODevice*> (callbackArgument)->updateActivePorts(); | |||||
| } | |||||
| static void threadInitCallback (void* /* callbackArgument */) | static void threadInitCallback (void* /* callbackArgument */) | ||||
| { | { | ||||
| jack_Log ("JackAudioIODevice::initialise"); | jack_Log ("JackAudioIODevice::initialise"); | ||||
| @@ -428,6 +442,7 @@ private: | |||||
| int totalNumberOfInputChannels; | int totalNumberOfInputChannels; | ||||
| int totalNumberOfOutputChannels; | int totalNumberOfOutputChannels; | ||||
| Array<void*> inputPorts, outputPorts; | Array<void*> inputPorts, outputPorts; | ||||
| BigInteger activeInputChannels, activeOutputChannels; | |||||
| }; | }; | ||||