Loading samples to vector/buffer painfully slow

Hello! I’m working on a guitar synthesiser and I need to load samples for it to work properly. I have sampled each fret on my guitar (6 strings, 24 frets) and I’m currently trying to load these samples at constructor on “PluginProcessor.cpp”.

Anyway I have tried both .csv loading to a std::vector matrix and/or loading the samples directly from .wav files using AudioFile.h (https://github.com/adamstark/AudioFile). When I run the program on debug mode, it takes about 2-3 minutes to load the whole thing in either way. It’s not that much samples I would think? 6 seconds at 48kHz each so that would make 144x288000 matrix.
Using the std::vector, I tried both push.back and pre-allocating 288000 for each std::vector<std::vector<std::vector>> unit, doesn’t make much of a difference.
How do the pro’s handle sample loading, it seems very fast in some programs I’ve used.

Always, profile and benchmark with optimizations because trying to improve performance without knowing what the problem is (and without compiler optimizations) is pointless.

That said using a vector of vectors is really bad for memory and cache performance. Use one big vector and index into it with channel_index * num_samples + sample_index. That way you allocate once and you get sequential access to the data.

There are some other things you can try w.r.t. memory layout, but that should help a lot.

Why are you using an unknown 3rd party library to read .wav-files when Juce already has facilities for that?

1 Like

And if you only want WAV and AIFF support, then https://docs.juce.com/master/classMemoryMappedAudioFormatReader.html is worth investigating, you could do something like having all the samples concatenated into a single file and map the sections prioritising based on the notes you need to play.

Even if you weren’t going down that route I would steer clear of loading all the samples in the PluginProcessor constructor; better hand that off to a background thread and just refuse to play back until that has finished up, otherwise (I may be wrong here, but it seems a reasonable assumption) you’ll slow down DAW startup.

Yeah the background loading seems like a good option. Is there a way to “prepackage” (idk the term) the data somehow? For example I have a MATLAB code that I use to test this synth and if I pre-write the data to a .mat file, the performance is significantly better this way.

Just used to syntax.

Something has to be wrong in your code or system. I did a test that loads in 403 .wav files (totaling about 400 megabytes on disk) into memory using Juce’s audio file reading facilities. With a release build the code runs in under 0.5 seconds. Windows 7 64 bit, Visual Studio 2017, latest Juce from develop branch. The hard drive is a basic Samsung SSD.

void test_file_load_speed()
{
	double t0 = Time::getMillisecondCounterHiRes();
	AudioFormatManager man;
	man.registerBasicFormats();
	std::vector<AudioBuffer<float>> buffers;
	DirectoryIterator dirit{ File("C:\\MusicAudio\\TestFiles"),true,"*.wav" };
	while (dirit.next())
	{
		std::unique_ptr<AudioFormatReader> reader{ man.createReaderFor(dirit.getFile()) };
		if (reader)
		{
			//std::cout << dirit.getFile().getFullPathName() << "\n";
			AudioBuffer<float> buf(reader->numChannels, reader->lengthInSamples);
			reader->read(&buf,  0, reader->lengthInSamples, 0, true, true);
			buffers.push_back(std::move(buf));
		}
	}
	double t1 = Time::getMillisecondCounterHiRes();
	std::cout << (t1 - t0) / 1000.0 << " seconds elapsed\n";
}

It should be noted though, that benchmarking these kinds of things isn’t entirely reliable since the files may be in the OS file cache after the first run. Still, even the first run I did with a debug build took only about 4 seconds to run.

1 Like

Thank you. I reinstalled Windows (had the same install since 2013 or something like that) and installed JUCE related stuff to main SSD. Takes about 0.66seconds now (Load .wav files to std::vector<std::vector<AudioBuffer>>