Use string to load BinaryData files?

Is it possible to convert a string to a type that might be able to directly load BinaryData files?

I’ve built a binaural panner but, due to some assertion errors while reading in WAV files, decided binary is a better option.

It’s working now when hard-coded with a particular file (BinaryData::thisFile), but I’m looking for a way of converting the existing string file names “H-10e000a.wav” into something that can produce the same result (“H-10e000a.wav” → BinaryData::H-10e000a_wav).

Hoping I don’t have to completely rework the switch statements I currently have. Thanks for your help!

Switch statements usually don’t work with strings, only integral types.

However there is a method in BinaryData that allows to retrieve the filenames, so you can iterate through the available files.

for (int i = 0; i < BinaryData::namedResourceListSize; ++i)
    if (juce::String::fromUTF8 (BinaryData::namedResourceList [i])) == name)
        // ...

I use something like this:

//Represents a binary data object:
struct RawData
{
    explicit RawData(const char* fileToFind)
    {
        using namespace BinaryData;

        for (int index = 0; index < namedResourceListSize; ++index)
        {
            auto binaryName = namedResourceList[index];
            auto fileName = getNamedResourceOriginalFilename(binaryName);

            if (fileName == fileToFind)
            {
                data = BinaryData::getNamedResource(binaryName, size);
                break;
            }
        }

        jassert(data != nullptr); //File not found
    }

    const char* data = nullptr;
    int size = 0;
};

Then when you need something:

RawData binary ("File.wav");
doSomethingWithData(binary.data, binary.size);
1 Like

Thanks @Daniel and @eyalamir - I’ll look into those now!

I’ve been passing the file path, determined by GUI parameters, as a string previously. This makes a lot more sense.

All sorted - works really well now. Thanks again!

I have an xml file that holds the original file name

auto xml { juce::parseXML (juce::File (“Attribute.xml”) };

auto filename { static_cast<const char*> (xml->getStringAttribute (“file”).toUTF8() };

DBG prints the filename correctly.

DBG (filename);

But passing filename as an argument always returns nullptr.

RawData binary (filename);

I also have tried

auto filename { static_cast<const char*> (xml->getStringAttribute (“file”).toUTF8().getAddress() };

But still to no avail.

Any idea how to make it work?

A few things to try:

  1. Make sure that where the RawData constructor is defined, is also where you include “BinaryData.h”

  2. Perhaps step into that function and see why it doesn’t find it? Maybe there’s an issue with the case not matching or something like that?

  1. I put RawData constructor definition in one of my JUCE modules cpp, which includes <JuceHeader.h>
  2. The case is perfectly matched. I can confirmed it by printing via DBG the String object from XmlElement::getStringAttribute, and the const char* fileToFind inside RawData constructor.
            DBGV (fileName);
            DBGV (fileToFind);
            
            if (fileName == fileToFind)
            {
                data = BinaryData::getNamedResource(binaryName, size);
                break;
            }

fileName and fileToFind printed identically in DBG console output. But fileName == fileToFind comparison always return false, hence it always return nullptr.

EDIT: I managed to solve the issue, by changing the condition using strcmp.

struct RawData
{
    explicit RawData (const char* fileToFind)
    {
        using namespace BinaryData;

        for (int index = 0; index < namedResourceListSize; ++index)
        {
            auto binaryName = namedResourceList[index];
            auto fileName = getNamedResourceOriginalFilename (binaryName);

            if (strcmp (fileName, fileToFind) == 0)
            {
                data = getNamedResource (binaryName, size);
                break;
            }
        }

        jassert (data != nullptr); //File not found
    }

    const char* data = nullptr;
    int size = 0;
};

Ah, thank you for debugging that @bayu!

I think we probably need to change that code so it accepts a String or a std::string in the constructor instead of a const char *.

Sure.

struct RawData
{
    explicit RawData (const char* fileToFind)
    {
        using namespace BinaryData;

        for (int index = 0; index < namedResourceListSize; ++index)
        {
            auto binaryName = namedResourceList[index];
            auto fileName = getNamedResourceOriginalFilename (binaryName);

            if (strcmp (fileName, fileToFind) == 0)
            {
                data = getNamedResource (binaryName, size);
                break;
            }
        }

        jassert (data != nullptr); // File not found
    }

    explicit RawData (const juce::String& fileToFind) : RawData (static_cast<const char*> (fileToFind.toUTF8())) {}
    explicit RawData (const std::string& fileToFind) : RawData (fileToFind.c_str()) {}
    const char* data = nullptr;
    int size = 0;
};