setDefaultMidiOutput() and emptyBuffer in AudioFilterStreame


#1

Hi!
When i load my juce aplication i sometimes get assertion faults in AudioSampleBuffer becouse “emptyBuffer” gets resized in AudioFilterStreamer::audioDeviceStopped() even while processing an audio callback in audioDeviceIOCallback

This happens quite randomly (its very ellusive only1 out of 8 or so tries) but it happens only when setDefaultMidiOutput() is called. (it is also called at the audio device’s initialize() function which is why it happens when i load my program)

trying to debug with malloc gaurd crashes the software there and then.

any idea on why this may be happening? did i forget to do something?


#2

No idea - that should never be able to happen while the audio callback is active… Any other clues?


#3

i dont see anything restricting callbacks when setDefaultMidiOutput() is called… setDefaultMidiOutput() is where it calls audioDeviceStopped() (and shrinks the empty buffer) . it is called in two main places:
AudioFilterStreamingDeviceManager::initialise()
AudioDeviceSelectorComponent::comboBoxChanged()

both can crash the software but sometimes it runs through the assertion faults and continues running. thats why i suspect that audioDeviceIOCallback is still passing through its last iteration before stopping.

it gives me the errors after these: (AudioFilterStreamer::audioDeviceIOCallback in file juce_AudioFilterSteamer.cpp line 78 )

    while (numActiveOutChans < numOutsWanted)
        outChans [numActiveOutChans++] = emptyBuffer.getSampleData (++i, 0);

#4

Ah yes, I see what you mean. Ok, how about this (I’ve not tried it myself yet)…

[code]void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName)
{
if (defaultMidiOutputName != deviceName)
{
SortedSet <AudioIODeviceCallback*> oldCallbacks;

    {
        const ScopedLock sl (audioCallbackLock);
        oldCallbacks = callbacks;
        callbacks.clear();
    }

    if (currentAudioDevice != 0)
        for (int i = oldCallbacks.size(); --i >= 0;)
            oldCallbacks.getUnchecked(i)->audioDeviceStopped();

    deleteAndZero (defaultMidiOutput);
    defaultMidiOutputName = deviceName;

    if (deviceName.isNotEmpty())
        defaultMidiOutput = MidiOutput::openDevice (MidiOutput::getDevices().indexOf (deviceName));

    if (currentAudioDevice != 0)
        for (int i = callbacks.size(); --i >= 0;)
            oldCallbacks.getUnchecked(i)->audioDeviceAboutToStart (currentAudioDevice);

    {
        const ScopedLock sl (audioCallbackLock);
        callbacks = oldCallbacks;
    }

    updateXml();
    sendChangeMessage (this);
}

}
[/code]


#5

Excelent! it worx like a charm. thank you!

one small fix:

[code]void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName)
{
if (defaultMidiOutputName != deviceName)
{
SortedSet <AudioIODeviceCallback*> oldCallbacks;

    {
        const ScopedLock sl (audioCallbackLock);
        oldCallbacks = callbacks;
        callbacks.clear();
    }

    if (currentAudioDevice != 0)
        for (int i = oldCallbacks.size(); --i >= 0;)
            oldCallbacks.getUnchecked(i)->audioDeviceStopped();

    deleteAndZero (defaultMidiOutput);
    defaultMidiOutputName = deviceName;

    if (deviceName.isNotEmpty())
        defaultMidiOutput = MidiOutput::openDevice (MidiOutput::getDevices().indexOf (deviceName));

    if (currentAudioDevice != 0)
        for (int i = oldCallbacks.size(); --i >= 0;)                 // FIX: oldCallbacks instead of callbacks.
            oldCallbacks.getUnchecked(i)->audioDeviceAboutToStart (currentAudioDevice);

    {
        const ScopedLock sl (audioCallbackLock);
        callbacks = oldCallbacks;
    }

    updateXml();
    sendChangeMessage (this);
}

}[/code]


#6

Ah yes, thanks for spotting my typo!