Console cd reader with assertion?


#1

Hi,
I have built example cd reader and in debug build I get assertion which I don’t understand:

JUCE Assertion failure in
d:\devel\src\juce\build\git\src\events\juce_messagelistener.cpp, line 37
JUCE Assertion failure in
d:\devel\src\juce\build\git\src\events\juce_messagelistener.cpp, line 37

juce_messagelistener.cpp:37

MessageListener::MessageListener() throw()
{
    // are you trying to create a messagelistener before or after juce has been intialised??
    jassert (MessageManager::instance != 0);

    if (MessageManager::instance != 0)
        MessageManager::instance->messageListeners.add (this);
}

cdreader.cpp

/* CDReader.cpp */

#include <juce.h>

int readcd (const char* directory)
{
    String outputDirectory (directory);
    File output (outputDirectory);
    if (output.exists() == false || output.isDirectory() == false)
    {
        printf ("Not a directory: %s\n", directory);
        return 1;
    }
    if (outputDirectory.endsWithChar (File::separator) == false)
        outputDirectory += File::separator;

    StringArray cdNames (AudioCDReader::getAvailableCDNames());
    if (cdNames.size() == 0)
    {
        printf ("No CD available\n");
        return 1;
    }

    AudioCDReader* cdReader (AudioCDReader::createReaderForCD(0));
    if (cdReader == 0)
    {
        printf ("Unable to create CD reader\n");
        return 1;
    }

    int numTracks (cdReader->getNumTracks());
    int cddbid (cdReader->getCDDBId());
    if (cddbid == 0)
    {
        printf ("Please insert disc\n");
        delete cdReader;
        return 1;
    }

    printf ("CD available (%d) with number of tracks and CDDB id:\n", cdNames.size());
    for (int n = 0; n < cdNames.size(); ++n)
        printf ("%d: \"%s\" %d: %x\n", n, (const char*) cdNames[n], numTracks, cddbid);

    for (int n = 0, s = cdReader->getPositionOfTrackStart(n);
            cdReader->isCDStillPresent() && n < numTracks;
            ++n, s = cdReader->getPositionOfTrackStart(n))
    {
        if (cdReader->isTrackAudio(n) == false)
        {
            printf ("Not an audio track: %d\n", n);
            continue;
        }

        int trackEnd(0);
        if (n + 1 < numTracks)
            trackEnd = cdReader->getPositionOfTrackStart(n+1);
        else
            trackEnd = cdReader->lengthInSamples;

        printf ("Track number with start/end position: %d %d %d\n", n, s, trackEnd);
        if (n < 10)
            output = File (outputDirectory + T("Track0") + String (n+1) + T(".wav"));
        else
            output = File (outputDirectory + T("Track") + String (n+1) + T(".wav"));

        printf ("Output file name: %s\n", (const char*) output.getFullPathName());
        OutputStream* outputStream = output.createOutputStream();

        int blockSize (2366);
        AudioSampleBuffer buffer (2, blockSize);

        WavAudioFormat wavFormat;
        AudioFormatWriter* wavWriter = wavFormat.createWriterFor (
                    outputStream, 44100, 2, 16,
                    StringPairArray(), 0);

        if (outputStream == 0 || wavWriter == 0)
        {
            printf ("Unable to create output\n");
            if (outputStream)
                delete outputStream;
            return 1;
        }

        while (cdReader->isCDStillPresent())
        {
            printf ("Sample: %d\r", s);
            if (s >= trackEnd)
                break;

            if (s + blockSize > trackEnd)
                blockSize = trackEnd - s;

            buffer.readFromAudioReader (cdReader, 0, blockSize, s, true, true);
            buffer.writeToAudioWriter (wavWriter, 0, blockSize);

            s += blockSize;
        }

        delete wavWriter;
    }

    delete cdReader;
    return 0;
}

int main (int argc, char* argv[])
{
    if (argc != 2)
    {
        printf ("Usage: cdreader DIRECTORY\n");
        return 1;
    }
    initialiseJuce_NonGUI();

    int ret = readcd (argv[1]);

    shutdownJuce_NonGUI();
    return ret;
}

Thanks, bye


#2

well, yes - like it says, you’re using a juce function without initialising juce. In a command line app, you need to manually call juce_initialiseNonGUI.

But if you’re using messages, you can’t do that in a command line app anyway - it’d need to be a gui app so that it can run the message dispatch loop.


#3

Hi,
On Windows class AudioCDReader uses Timer which uses MessageListener which uses MessageManager…

snipet from juce_Application.cpp:

initialiseJuce_GUI()
{
        ...
        initialiseJuce_NonGUI();
        MessageManager::getInstance()
        ...
}
shutdownJuce_GUI()
{
        ...
        delete MessageManager::getInstance();
        shutdownJuce_NonGUI();
        ...
}

When I add MassageManager::getInstance() like above (after/before initialise/shutdown) everything works ok…

See cdreader.cpp from my previous post…

Thanks, bye


#4

initialiseJuce_GUI() should NOT be called in a command-line app - hence the word “GUI” in it.

A command-line app has no message loop, so none of the messaging classes will work, and none of the initialisation will happen correctly. If the cd reader code needs messages, then you have to write it as a normal GUI app.


#5

Hi Jules,
Does that means I can’t use of any of ActionBroadcaster, ChangeBroadcaster and MessageListener in an console application.
Secondly If My application uses juce for back-end coding can I call “initialiseJuce_GUI()”.
Finally are there any specific reason for not supporting MessageManagers on non-UI based applications.


#6

You all seem confused by all this. Let me try to explain.

All apps are basically the same, but…

  • In a GUI app, the main() function just kicks off the message thread, which loops, sending messages, and everything you do is a result of those messages.

  • In a console app, main() just does the work it needs to without stopping. It doesn’t run a message loop.

Obviously if there’s no message loop, you can’t use messages. And you mustn’t call initialiseJuce_GUI.

If you do want a message loop, do NOT write your own main() method - just use the normal JuceApplication stuff to start the app.

But there’s nothing wrong with writing a GUI app which doesn’t open any windows, and which gets called from the command-line. If you need to use message-based classes, that’d be the way to do it.


#7

Well, TBH I had almost forgotten the existence of main method thanks to juce. :frowning:

I get it now.


#8

Hello,

I have a similar issue where I am trying to mix CSL and Juce. I called initialiseJuce_NonGUI() but I still hit the assertion

ChangeBroadcaster::ChangeBroadcaster() throw()
{
    // are you trying to create this object before or after juce has been intialised??
    jassert (MessageManager::instance != 0);

I’ve posted in detail http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=3199&p=38701#p38701 <- there.
If any of you have a second to take a look I would appreciate it.

Lucas


#9