Possible Bug in "juce_linux_ALSA.cpp"


#1

Hi, I’m new to JUCE and have been digging around in the code to learn how things work (it’s very well commented, which is great!)

I noticed some odd behaviour when setting up output channels using the ALSAAudioIODevice. The following test code sets AudioDeviceSetup.outputChannels to 1100 (bin) :

[code]AudioDeviceManager::AudioDeviceSetup config;
mDeviceManager.getAudioDeviceSetup( config );

config.useDefaultOutputChannels = false;
config.outputChannels.clear();
config.outputChannels.setRange( 2, 2, true );

mDeviceManager.setAudioDeviceSetup( config, true );[/code]

However, calling mDeviceManager.getAudioDeviceSetup( config ) again immediately after the above reveals that outputChannels has actually been set to 1101 (bin).

With the help of a debugger I managed to track the cause down to this line of code in ALSAThread::open() in juce_linux_ALSA.cpp :

What seems to be happening is that after currentOutputChans has been set to 1100, the above then adds an extra 1 (the minimum no. of output channels for my MAudio Audiophile 24/96 is apparently 1).

I tried running the test code again but this time using the on-board sound chip instead the MAudio card. The debugger showed that currentOutputChans was initially correctly set to 1100 but then after the call to currentOutputChans.setRange() it was changed to 1111 (indicating the min no. of output channels for my on-board audio is 2).

I edited the code in ALSAThread::open() so that it looks as follows and this seems to work nicely (my edits appear between each set of “//=======” comments) :

[code]
//===================================================================================================
if (outputChannels.countNumberOfSetBits () < minChansOut)
{
outputChannels.clear();
outputChannels.setRange (0, minChansOut, true);
}
//===================================================================================================

    outputChannelBuffer.setSize (jmax ((int) minChansOut, outputChannels.getHighestBit()) + 1, bufferSize);
    outputChannelBuffer.clear();
    outputChannelDataForCallback.clear();
    currentOutputChans.clear();

    if (outputChannels.getHighestBit() >= 0)
    {
        for (int i = 0; i <= jmax (outputChannels.getHighestBit(), (int) minChansOut); ++i)
        {
            if (outputChannels[i])
            {
                outputChannelDataForCallback.add (outputChannelBuffer.getSampleData (i));
                currentOutputChans.setBit (i);
            }
        }
    }

    if (outputChannelDataForCallback.size() > 0 && outputId.isNotEmpty())
    {
        outputDevice = new ALSADevice (outputId, false);

        if (outputDevice->error.isNotEmpty())
        {
            error = outputDevice->error;
            outputDevice = nullptr;
            return;
        }

        //=================================================================================================
        //currentOutputChans.setRange (0, minChansOut, true);
        //=================================================================================================

        if (! outputDevice->setParameters ((unsigned int) sampleRate,
                                           jlimit ((int) minChansOut, (int) maxChansOut, currentOutputChans.getHighestBit() + 1),
                                           bufferSize))
        {
            error = outputDevice->error;
            outputDevice = nullptr;
            return;
        }

        outputLatency = outputDevice->latency;
    }[/code]

#2

Excellent detective-work, very much appreciated! I’ll take a look at that right away…