Replacement function for createInputStream()

I am assuming this function is the source of the problem I am having. As you know it is deprecated and I am looking for an alternative. Our C++ prof gave us an assignment with this line of code:

auto* reader = formatManager.createReaderFor(audioURL.createInputStream(false));

reader is a null pointer in all cases. audioURL is a valid JUCE URL object, instantiated with a local audiofile, as determined by typeid(audioURL).name():

audioURL is type N4juce3URL

I cannot get a hold of the prof. He wrote this DJ application over two years ago.

Looking over juce_Filechooser.cpp, I am unsure of what to replace this with. The input to a new function does not have to be a URL object, it could be a File object.

I am using Linux. I looked over juce_linux_FileChooser.cpp but nothing there seemed to fit the bill.

FWIW the function that this line of code is a part of is:

void DJAudioPlayer::loadURL(URL audioURL)
{
auto* reader = formatManager.createReaderFor(audioURL.createInputStream(false));
if (reader != nullptr) // good file!
{
std::unique_ptr newSource (new AudioFormatReaderSource(reader, true));
transportSource.setSource (newSource.get(), 0, nullptr, reader->sampleRate);
readerSource.reset (newSource.release());
}
}

I think the problem is rather the use of juce::URL. If you can change it to use juce::File, since the AudioFormatReader won’t cope with WebInputStreams anyway (needs to be seekable).

If that is not an option check url.isLocalFile() and work with url.getLocalFile() instead of the URL.

If you still want to use the URL::createInputStream(), you just need to give it some InputStreamOptions. There is an example on the linked page.

Here is my attempt at passing a file instead of a stream:

void DJAudioPlayer::loadFile(const File& file)
{
std::cout << “file type” << typeid(file).name() << std::endl;
auto* reader = formatManager.createReaderFor(file);
if (reader == nullptr) std::cout << "reader == nullptr "<< std::endl;
if (reader != nullptr) // good file!
{
std::unique_ptr newSource (
new AudioFormatReaderSource(reader, true));
transportSource.setSource (newSource.get(), 0, nullptr, reader->sampleRate);
readerSource.reset (newSource.release());
}
}
the file type seems OK: file typeN4juce4FileE

formatManager.registerBasicFormats() checks out fine, it is seeing four audio file types including MP3, which I am using for testing.

This new function should be using this JUCE function:

AudioFormatReader* AudioFormatManager::createReaderFor (const File& file)

instead of:

AudioFormatReader* AudioFormatManager::createReaderFor (std::unique_ptr audioFileStream)

I still get the same result: reader== nullptr.

Looking into AudioFormatManager::createReaderFor ():

AudioFormatReader* AudioFormatManager::createReaderFor (const File& file)
{
// you need to actually register some formats before the manager can
// use them to open a file!
jassert (getNumKnownFormats() > 0);

for (auto* af : knownFormats)
    if (af->canHandleFile (file))
        if (auto in = file.createInputStream())
            if (auto* r = af->createReaderFor (in.release(), true))
                return r;

return nullptr;

}

it’s possible this is the source of the nullptr, but how?

My code registers the audio file formats (WAV, MP3, a couple of others), I have tested this. jassert (getNumKnownFormats() > 0) does not throw an exception.

I cannot find the canHandleFile() function anywhere in order to check it out. juce_file has it’s own version of createInputStream(), which I substituted for audioURL.createInputStream() and got an error:

invalid use of non-static member function

I considered interference from my Linux file system, which is ext4, however it’s been around for a while, a problem should have turned up by now.

I’m stuck.

I know the current recommendation is to use the method that takes InputStreamOptions as an argument. I looked over that code and do not understand it.

AudioFormatReader* AudioFormatManager::createReaderFor (const File& file)
{
// you need to actually register some formats before the manager can
// use them to open a file!
jassert (getNumKnownFormats() > 0);
for (auto* af : knownFormats)
{
if (af->canHandleFile (file))

is returning 0 (false) for all file formats

There are a few things you could check:

  • first of all check if the file exists:
    jassert (file.existsAsFile());
  • then you can check if it is readable
    jassert (file.createInputStream());
    // if not readable it will return an empty unique_ptr which yields false
  • then check the module juce_audio_formats that MP3 format is enabled.
    If not enable it, re-save the project from projucer and rebuild
  • and try a different file, maybe also a different file type

Hope that helps

Hi, Daniel.

Solved it!

I discovered the application could play WAV files after all.

Then I saw this piece of code in juce_AudioFormatManager:

#if JUCE_USE_MP3AUDIOFORMAT
registerFormat (new MP3AudioFormat(), false);
#endif

I put JUCE_USE_MP3AUDIOFORMAT into all the preprocessor definitions, then it could load and play MP3s.

Interestingly, after deleting these preprocessor definitions, it still worked!

Thank you for your help!

Ideally use Projucer to configure the preprocessor defines:

Glad it works now

I didn’t know about this settings feature for individual audio modules. Merci.