|
|
@@ -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 (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 (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 (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));
|
|
|
@@ -106,9 +106,11 @@ namespace |
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
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_activate (client);
|
|
|
|
isOpen_ = true;
|
|
|
@@ -264,6 +267,8 @@ public: |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateActivePorts();
|
|
|
|
|
|
|
|
return lastError;
|
|
|
|
}
|
|
|
|
|
|
|
@@ -275,6 +280,7 @@ public: |
|
|
|
{
|
|
|
|
juce::jack_deactivate (client);
|
|
|
|
juce::jack_set_process_callback (client, processCallback, nullptr);
|
|
|
|
juce::jack_set_port_connect_callback (client, portConnectCallback, nullptr);
|
|
|
|
juce::jack_on_shutdown (client, shutdownCallback, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
@@ -312,27 +318,8 @@ public: |
|
|
|
int getCurrentBitDepth() { return 32; }
|
|
|
|
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()
|
|
|
|
{
|
|
|
@@ -363,24 +350,27 @@ private: |
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
@@ -397,6 +387,30 @@ private: |
|
|
|
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 */)
|
|
|
|
{
|
|
|
|
jack_Log ("JackAudioIODevice::initialise");
|
|
|
@@ -428,6 +442,7 @@ private: |
|
|
|
int totalNumberOfInputChannels;
|
|
|
|
int totalNumberOfOutputChannels;
|
|
|
|
Array<void*> inputPorts, outputPorts;
|
|
|
|
BigInteger activeInputChannels, activeOutputChannels;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|