const String open (const BitArray& inputChannels, const BitArray& outputChannels,
                       double sampleRate, int bufferSizeSamples)
    {
        if (client == 0)
        {
            lastError = T("No JACK client running");
            return lastError;
        }

        lastError = String::empty;
        close();

        JUCE_NAMESPACE::jack_set_process_callback (client, processCallback, this);
        JUCE_NAMESPACE::jack_on_shutdown (client, shutdownCallback, this);
        JUCE_NAMESPACE::jack_activate (client);
        isOpen_ = true;

        if (! inputChannels.isEmpty())
        {
            const char** const ports = JUCE_NAMESPACE::jack_get_ports (client, 0, 0, /* JackPortIsPhysical | */ JackPortIsOutput);

            if (ports != 0)
            {
                const int numInputChannels = inputChannels.getHighestBit () + 1;

                for (int i = 0; i < numInputChannels; ++i)
                {
                    const String portName (ports[i]);

                    if (inputChannels[i] && portName.upToFirstOccurrenceOf (T(":"), false, false) == getName())
                    {
                        int error = JUCE_NAMESPACE::jack_connect (client, ports[i], JUCE_NAMESPACE::jack_port_name ((jack_port_t*) inputPorts[i]));
                        if (error != 0)
                            jack_Log ("Cannot connect input port " + String (i) + " (" + String (ports[i]) + "), error " + String (error));
                    }
                }

                free (ports);
            }
        }

        if (! outputChannels.isEmpty())
        {
            const char** const ports = JUCE_NAMESPACE::jack_get_ports (client, 0, 0, /* JackPortIsPhysical | */ JackPortIsInput);

            if (ports != 0)
            {
                const int numOutputChannels = outputChannels.getHighestBit () + 1;

                for (int i = 0; i < numOutputChannels; ++i)
                {
                    const String portName (ports[i]);

                    if (outputChannels[i] && portName.upToFirstOccurrenceOf (T(":"), false, false) == getName())
                    {
                        int error = JUCE_NAMESPACE::jack_connect (client, JUCE_NAMESPACE::jack_port_name ((jack_port_t*) outputPorts[i]), ports[i]);
                        if (error != 0)
                            jack_Log ("Cannot connect output port " + String (i) + " (" + String (ports[i]) + "), error " + String (error));
                    }
                }

                free (ports);
            }
        }

        return lastError;
    }