Reading and writing .wav files to XML

Hi all.
I’ve seen quite a few posts on this subject but I keep running into issues. In my sampler plug-in, I am saving and recalling the base64 data of its .wav sample files via a ValueTree/XML.
I believe my AudioFormatWriter code is working correctly. I can see the output saved in my plug-in’s XML file. However, whenever I try to recall the base64 data via an input stream and an AudioFormatManager the reader does not work correctly. I noticed that reader->lengthInSamples always stays at 0 samples. I am assuming that an object is not getting properly initialized before reading or writing the data, but I do not know how to better debug this.

Here are some code snippets with any unrelated information left out. Thanks!

/// saving base64 data
void SamplerProcessor::loadSample(File& file, int index)
{
    auto sampleState = samplerState.getChild(index);

    if (file != File{}) 
    {
        std::unique_ptr<AudioFormatReader> reader (formatManager.createReaderFor(file));
        if (reader != nullptr)
        {
            // --- save sample's base64 data to ValueTree
            MemoryBlock audioData;
            WavAudioFormat format;
            std::unique_ptr<AudioFormatWriter> writer (format.createWriterFor (new MemoryOutputStream (audioData, false), reader->sampleRate, reader->numChannels, reader->bitsPerSample, StringPairArray(), 0));
            writer->writeFromAudioReader(*reader, 0, reader->lengthInSamples);
            auto data = audioData.toBase64Encoding();
            sampleState.setProperty(IDs::sampleData, data, nullptr);
        };
    }
}

/// recalling base64 data
void SamplerProcessor::reloadSample(int index)
{
    auto sampleState = samplerState.getChild(index);
    
    String audioData = sampleState[IDs::sampleData];
    
    MemoryBlock data;
    data.fromBase64Encoding(audioData);
    std::unique_ptr<InputStream> input;
    input.reset(new MemoryInputStream(data.getData(), data.getSize(), false));

    std::unique_ptr<AudioFormatReader> reader (formatManager.createReaderFor(std::move(input)));
    
    if (reader != nullptr)
    {
        auto sound = dynamic_cast<SySamplerSound*>(sampler.getSound(index).get());
      
        sound->loadReader(*reader, reader->sampleRate);
    }
}

The problem is that you are writing into base64 without destroying the writer before. The lengthInSamples is written when the writer is closed.

Calling writer.reset() before writing the base64 should solve the issue.

That worked perfectly, I can’t thank you enough :slight_smile:
In case anyone else is interested here is the updated loadSample() code.

/// saving base64 data
void SamplerProcessor::loadSample(File& file, int index)
{
    auto sampleState = samplerState.getChild(index);

    if (file != File{}) 
    {
        std::unique_ptr<AudioFormatReader> reader (formatManager.createReaderFor(file));
        if (reader != nullptr)
        {
            // --- save sample's base64 data to ValueTree
            MemoryBlock audioData;
            WavAudioFormat format;
            std::unique_ptr<AudioFormatWriter> writer (format.createWriterFor (new MemoryOutputStream (audioData, false), reader->sampleRate, reader->numChannels, reader->bitsPerSample, StringPairArray(), 0));
            writer->writeFromAudioReader(*reader, 0, reader->lengthInSamples);
            writer.reset();
            auto data = audioData.toBase64Encoding();
            sampleState.setProperty(IDs::sampleData, data, nullptr);
        };
    }
}