New User a bit lost


#1

My company recently outsourced to have someone create the sound software for our simulator. The person they hired for that job delivered a product and then disappeared. Their product makes extensive use of JUCE (which I had never seen before or heard of) and had a few odd-ball problems that I’ve now been tasked to debug.

I am currently trying to update to the latest version of JUCE for this software. It was built using JUCE 1.45 and I have just downloaded and built JUCE 1.51. I really do not know anything about JUCE and am unsure where to start to learn its systems and structures.

The first fire I would like to put out after this update of the JUCE libraries is that I can no longer build the sound software because I am struggling to fix the calls to setAudioDevice(). This function has been removed in 1.51 and I’m not sure what I should be doing instead.

Any guidance would be very appreciated. If you need more information or source code posted please let me know!


#2

Which class are you talking about when you say setAudioDevice? If it’s AudioDeviceManager, you probably just need to use setAudioDeviceSetup() or initialise() instead.


#3

You guessed the class correctly :slight_smile:

I will look into those two functions today, thank you!


#4

Thank you again for your help!

I was able to get the program to compile, but the replacement methodolgy I came up with for Initializing the sound drivers is currently failing to find the actual important hardware drivers.

The old methodology (for JUCE 1.45) was:

[code]{
motuIndex = -1;
const String error (audioDeviceManager.initialise (0, /* number of input channels /
12, /
number of output channels /
0, /
no XML settings… /
true /
select default device on failure */));

if (error.isNotEmpty())
{
    AlertWindow::showMessageBox (AlertWindow::WarningIcon,
                                 T("Audio Demo"),
                                 T("Couldn't open an output device!\n\n") + error);
}
else
{
    int blockSize = -1;
    double sampleRate = 44100.0;
    BitArray inputChannels;
    BitArray outputChannels;
    outputChannels.clear();
    outputChannels.setRange(0, 12, true);

    const StringArray audioDeviceNames = audioDeviceManager.getAvailableAudioDeviceNames();

    for (int i=0; i < audioDeviceNames.size();i++) {

// AlertWindow::showMessageBox (AlertWindow::WarningIcon, T(“ASIO Device List”), audioDeviceNames[i]);
if (audioDeviceNames[i].contains(T(“MOTU Audio ASIO”)) || audioDeviceNames[i].contains(T(“MOTU PCI ASIO”))) {
motuIndex = i;
break;
}
}

    if (motuIndex >= 0) {
        const String error (audioDeviceManager.setAudioDevice(audioDeviceNames[motuIndex], blockSize, sampleRate, &inputChannels, &outputChannels, false));
        if (error.isNotEmpty()) {
            AlertWindow::showMessageBox (AlertWindow::WarningIcon,
                                         T("Audio Demo"),
                                         T("MOTU Device not available. (Is it unplugged? Turned off?) Fallback: Stereo PC Speakers"));

            outputChannels.clear();
            outputChannels.setRange(0, 2, true);
            audioDeviceManager.setAudioDevice(audioDeviceNames[0], blockSize, sampleRate, &inputChannels, &outputChannels, false);
            motuIndex = -1;
            simSound.SetStereoOutputFlag(true);
        }
        else {
            simSound.SetStereoOutputFlag(false);
        }
    }
    else {
            AlertWindow::showMessageBox (AlertWindow::WarningIcon,
                                         T("Audio Demo"),
                                         T("No ASIO Drivers detected. Fallback: Using Stereo Field as output."));

            outputChannels.clear();
            outputChannels.setRange(0, 2, true);
            audioDeviceManager.setAudioDevice(audioDeviceNames[0], blockSize, sampleRate, &inputChannels, &outputChannels, false);
            motuIndex = -1;
            simSound.SetStereoOutputFlag(true);
    }

    // start the IO device pulling its data from our callback..
    audioDeviceManager.setAudioCallback (this);
    addAndMakeVisible (tabs = new TabComponent (simSound));
}

}[/code]

Of course lookign at this in full just now I notice the old methodology called audioDeviceManager.initialise() as well…

In my haste to get something compiling ASAP I came up with:

[code]motuIndex = -1;
const String error (audioDeviceManager.initialise (0, /* number of input channels /
12, /
number of output channels /
0, /
no XML settings… /
true /
select default device on failure */));

if (error.isNotEmpty())
{
    AlertWindow::showMessageBox (AlertWindow::WarningIcon,
                                 T("Audio Demo"),
                                 T("Couldn't open an output device!\n\n") + error);
}
else
{
    int blockSize = -1;
    double sampleRate = 44100.0;
    BitArray inputChannels;
    BitArray outputChannels;
    outputChannels.clear();
    outputChannels.setRange(0, 12, true);

    /* New methods needed in order to compile with JUCE 1.51 instead of 1.45 */
    OwnedArray <AudioIODeviceType> types;
    StringArray fullArray;

    audioDeviceManager.createAudioDeviceTypes (types);

    for (int i = 0; i < types.size(); ++i)
    {
        String typeName (types[i]->getTypeName());  // This will be things like "DirectSound", "CoreAudio", etc.

        types[i]->scanForDevices();                 // This must be called before getting the list of devices

        StringArray deviceNames (types[i]->getDeviceNames());  // This will now return a list of available devices of this type
        fullArray.addArray(deviceNames, 0, deviceNames.size());
    }
    
    const StringArray audioDeviceNames = fullArray;

    for (int i=0; i < audioDeviceNames.size();i++) {

// AlertWindow::showMessageBox (AlertWindow::WarningIcon, T(“ASIO Device List”), audioDeviceNames[i]);
if (audioDeviceNames[i].contains(T(“MOTU Audio ASIO”)) || audioDeviceNames[i].contains(T(“MOTU PCI ASIO”))) {
motuIndex = i;
break;
}
}

    if (motuIndex >= 0) {
        //const String error (audioDeviceManager.setAudioDevice(audioDeviceNames[motuIndex], blockSize, sampleRate, &inputChannels, &outputChannels, false));
        const String error (audioDeviceManager.initialise(1, 1, 0, true, audioDeviceNames[motuIndex], 0));
        if (error.isNotEmpty()) {
            AlertWindow::showMessageBox (AlertWindow::WarningIcon,
                                         T("Audio Demo"),
                                         T("MOTU Device not available. (Is it unplugged? Turned off?) Fallback: Stereo PC Speakers"));

            outputChannels.clear();
            outputChannels.setRange(0, 2, true);
            //audioDeviceManager.setAudioDevice(audioDeviceNames[0], blockSize, sampleRate, &inputChannels, &outputChannels, false);
            audioDeviceManager.initialise(1, 1, 0, true, audioDeviceNames[0], 0);
            motuIndex = -1;
            simSound.SetStereoOutputFlag(true);
        }
        else {
            simSound.SetStereoOutputFlag(false);
        }
    }
    else {
            AlertWindow::showMessageBox (AlertWindow::WarningIcon,
                                         T("Audio Demo"),
                                         T("No ASIO Drivers detected. Fallback: Using Stereo Field as output."));

            outputChannels.clear();
            outputChannels.setRange(0, 2, true);
            //audioDeviceManager.setAudioDevice(audioDeviceNames[0], blockSize, sampleRate, &inputChannels, &outputChannels, false);
            audioDeviceManager.initialise(1, 1, 0, true, audioDeviceNames[0], 0);
            motuIndex = -1;
            simSound.SetStereoOutputFlag(true);
    }

    // start the IO device pulling its data from our callback..
    //audioDeviceManager.setAudioCallback(this);
    audioDeviceManager.addAudioCallback(this);
    addAndMakeVisible (tabs = new TabComponent (simSound));
}

}[/code]

I’m sure that I’m doing much of this inefficiently and down-right erroneously. So I apologize in advance for my complete ignorance of your API.


#5

After quite a bit more work I might have found a problem with JUCE or at least I am at a point where I’m unsure how I am correctly supposed to get the code to do what it is supposed to do. The old version of the code was able to successfully load the “MOTU PCI ASIO” Audio Device. However, in the new version when I attempt to use Initialize() or audioDeviceManager.setAudioDeviceSetup() in order to set the Audio device to the “MOTU PCI ASIO” I encounter a problem in juce_AudioDeviceManager.cpp.

What is happening is that once we get into the setAudioDeviceSetup() function we eventually make the following assignment:

However, as far as I can tell this is giving only the audio devices of type ‘Direct Sound’ and none of the audio devices of type ‘ASIO’. Because of this the setAudioDeviceSetup() function can never find any ASIO type audio devices.

Is there some other way to set Audio Devices that I am missing or is this an actual bug?


#6

No, not a bug. Did you actually set the JUCE_ASIO flag when you built your project? And if you’re setting up the device programatically rather than letting the user select it, you might need to use setCurrentAudioDeviceType() to switch it to ASIO mode before selecting the device.


#7

Beautiful. Thank you for putting up with me!

I had no idea that I needed to set up the config page to work because as I stated I’m just looking at a lot of work that someone else did and trying to fix it…
And after setting that up, I did need to set the device manually to let it know that I wanted to look for ASIO devices.

It is compiling and running now! Thank you very much for amazingly prompt, accurate, and patient help.
I had some display bugs to work out, but I think they’re mostly gone.

The display issues arose b/c the original author made extensive use of string.printf(). I tried replacing them all with calls to formatted but that did not seem to make the program happy so I took the advice of the comments in the string header and replaced them all with operator=, operator+, and String(float, 2). The one that is giving me trouble is there is a hex address being printed out. I came up with a bad workaround for it for the time being (Is there a clean way to accomplish printf("%08x") with your string type?)

Well Monday I guess I get to see if any of the old errors that started me down this rabbit hole persist. Thank you again fearless leader.


#8

No problem. For the hex stuff, I’d personally go for String::toHexString (xyz).paddedLeft ('0', 8), but a lot of people would probably choose to just use String::formatted instead.


#9

Thanks again, I will put that in. Of course I have more pressing issues now. :frowning:

I succesfully updated to the JUCE release version 1.51 and cleaned up the resulting compile errors, text display problems, and sound driver loading issues. However, when I ran the program in the debugger after accomplishing this I still saw visual studio generate a complaint about a corrupted stack about once every 15 minutes until about 75 minutes into running it through the same assertion that I was seeing before I went through the process of updating.

This prompted me to upgrade to the latest JUCE version from the sourceforge repository. All I had to do was clean up one function call and turn on the ASIO support in the config.h file to get this running smoothly again!

However, I am concerned that I will be seeing the same assertion error shortly (I should know if this is still a problem by tomorrow at the latest…). If I had to guess, I would say that it is not a problem with JUCE, but rather a problem with how the original code author is using JUCE. But the debugger is pointing me to JUCE code when the exception happens.

The exception being thrown is a bad allocation in juce_Timer.cpp on line 145 (inside the callTimers() function).
Is there any advice you could give me on figuring out what the root problem is?


#10

Sure enough the bug still exists :frowning:

It is an intermittant sort of thing. After running for ~1 - 2 hours the program simply explodes in one way or another (~80% of it is the assertion I described in the previous post).

When I set the debugger to look at the sendUnhandledException(e, sourceFile, lineNumber) function in juce_Application.cpp, I can see that the source of the exception e, is juce_Timer.cpp and the lineNumber is 147. But all that does is point me to:

[code]void callTimers()
{
const ScopedLock sl (lock);

    while (firstTimer != 0 && firstTimer->countdownMs <= 0)
    {
        Timer* const t = firstTimer;
        t->countdownMs = t->periodMs;

        removeTimer (t);
        addTimer (t);

        const ScopedUnlock ul (lock);

        JUCE_TRY
        {
            t->timerCallback();
        }
        JUCE_CATCH_EXCEPTION  //Line 147
    }[/code]

I’m not really sure where to proceed from here in order to determine why the program is having trouble.


#11

Looks like it’s throwing an exception in some user code - haven’t you got your debugger set to catch exceptions so that you can see what’s actually thowing it?


#12

I wasn’t able to work on this for some time and then I spent a lot more time figuring things out than it probably should have taken…

Anyways. I learned a little bit about exceptions and tried to track down where it was actually throwing them. I did so in a roundabout way, but eventually found the root of the problem:

The sound software that I am debugging is constantly making numerous different sound files play. As it swaps different files in and out the computer experiences severe memory leaks. When the system runs out of memory it throws an exception ‘bad allocation’. The more often the files that need to be played are changed the faster the system runs out of memory.

The original author is using custom-made member class functions create() and destroy() for allocating and deallocating the sound emitters. The hit counts on these functions look reasonable (create() always has just barely a few more calls to it than destroy() ). I’m not sure why so much memory is leaking, but at this point I am confident that this is not a JUCE problem (although I suppose it still could be a mis-use of JUCE problem).

Of course, if there anyone has suggestions for how to best hunt down memory leaks then I am all ears. But at this point that would likely be above and beyond the domain and intent of this forum.

Thanks again for all of the help!


#13

If you’re on a mac, XCode’s instruments have some excellent leak tracing stuff.

But really, there’s no substitute for writing code in a style that doesn’t leak, which isn’t difficult in c++ - try these anti-leaking steps:

  1. Remove ALL use of malloc from your code - use HeapBlock instead.
  2. Search for all uses of the “new” operator and try to replace them with either a stack-based object, or a member object that doesn’t need to be deleted.
  3. In those situations where you really, really have to use “new”, always use a ScopedPointer to manage the object’s lifetime rather than deleting it manually. Ideally, your app you shouldn’t contain the “delete” operator at all, except in special cases. (Though by the sound of it you probably aren’t using it much already!)

Utter crap. You should get rid of those and instead have a method that returns a ReferenceCountedObjectPtr (or some other copy-by-value object) that wraps the resource and manages its lifetime.