Where to store files (Assets/Resources) to include with install package

I understand that I can use Projucer to make binary data of files to embed in code, however say that for whatever reason I do not want to do that and instead want to include said files in a finished App, in the install package, where do I store files (audio, images, videos, documents, and so on) in my project so I do not have to enter a path?

I tried to files via “Add Existing Files…” in Projucer, and then restarted VS and the files show there, however file is not found (nullptr).

Here is my simple test code;

	formatManager.registerBasicFormats();
	transportSource.addChangeListener(this);

	File* file = new File("BrickHit.wav");
	auto reader = formatManager.createReaderFor(*file);
	if (reader != nullptr)
	{
		std::unique_ptr<AudioFormatReaderSource> newSource(new AudioFormatReaderSource(reader, true));
		transportSource.setSource(newSource.get(), 0, nullptr, reader->sampleRate);
		transportSource.start();
	}

Windows doesn’t have the concept of bundles, so you are on your own to put files in a known location. You will have to create an installer for that purpose, and you can use File::getSpecialLocation() to choose a suitable location, without hardcoding paths.

See this tutorial

Hope that helps…

Thank you very much for that reply.

To be clear, unless I put my files say in a special location, say “Desktop” and use getSpecialLocation(), even though my resource files are in my Projucer’s project root folder, I have to use absolute path to access these files in my code?

Ok I got it to work by adding file in Projuce is binary resource, then reopen VS and with the belo code I can now play my wav file anytime I want.

	formatManager.registerBasicFormats();
	transportSource.addChangeListener(this);

	MemoryInputStream* file = new MemoryInputStream(BinaryData::BrickHit_wav, BinaryData::BrickHit_wavSize, false);
	auto reader = formatManager.createReaderFor(file);

	if (reader != nullptr)
	{
		std::unique_ptr<AudioFormatReaderSource> newSource(new AudioFormatReaderSource(reader, true));
		transportSource.setSource(newSource.get(), 0, nullptr, reader->sampleRate);
		readerSource.reset(newSource.release());
		transportSource.start();
	}
1 Like

You have to distinguish between two perspectives: Compile time and run time.

Files you add to the project in the Projucer are meant to be resources for compile time, e.g. files that are needed to compile the application but not to run the application. To make it clear, if you distribute your plugin or application, you won’t ship the cpp source files, you will ship a compiled binary, built from these source files. The same goes for other resources that come with the project. Therefore it is a nice technique to embed files you need into your compiled binary as binary resource, this way they become part of your compiled executable.

The runtime perspective on the other hand does not even know that there was something like a Projucer project it was generated from. So if you want to load files at runtime you need to put them to a known location on the computer and load it from there at runtime. Therefore you need to create an installer tool, that makes sure that theses files will be copied to that exact location to be loadable at runtime. So you’re better off designing it in such a way that this file is not part of the project folder structure, except for the sake of building the installer from there.

MemoryInputStream* file = new MemoryInputStream(BinaryData::BrickHit_wav, BinaryData::BrickHit_wavSize, false);
auto reader = formatManager.createReaderFor(file);
MemoryInputStream(BinaryData::BrickHit_wav, BinaryData::BrickHit_wavSize, false));

The third line doesn’t do anything. As well, the whole thing can become:

auto reader = formatManager.createReaderFor(new MemoryInputStream(BinaryData::BrickHit_wav, BinaryData::BrickHit_wavSize, false));

Thanks for that explanation.

So in my above example code, which was after I had added the wav file as a binary resource in Projucer, and then opened Visual Studio, and then compiled, I should be good right and only need to distribute the generated exe file right? Because when I go to the build folder after compilation, and copy the exe file to my desktop and run it, my sound still plays, leading me to believe the wav file is embedded in the exe file or am I wrong?

And now that you fixed the unique_ptr scope issue, you have created a memory leak, as the memory for newSource will never be deleted.

Even though I have this;

void MainComponent::releaseResources()
{
    // This will be called when the audio device stops, or when it is being
    // restarted due to a setting change.

    // For more details, see the help for AudioProcessor::releaseResources()

	transportSource.releaseResources();
}

Oh I forgot I had already deleted that third line, but thanks.

Again, refer the the AudioTransportSource docs. It says that it does not own the object you pass in, and you need to manage it yourself. It’s good practice to read the docs when passing pointers around.

I looked at the following tutorial - https://docs.juce.com/master/tutorial_playing_sound_files.html

For this line readerSource.reset(newSource.release()); which I also have in my above code, it says;

" Since the AudioTransportSource should now be using our newly allocated AudioFormatReaderSource object we can safely store the AudioFormatReaderSource object in our readerSource member. (As mentioned in Processing the audio above.) To do this we must transfer ownership from the local newSource variable by using std::unique_ptr::release()."

I do not see anything else in that tutorial about memory leaks.

Doh! my bad. I missed the readerSource.reset(newSource.release());

No problem and thank you very much for your help!

Now although above worked fine for playing a single wav file, I now have a problem playing several different, that may or may not be running at the same time, or at least overlapping.

https://docs.juce.com/master/classMixerAudioSource.html might be a good place to start.