Hey all,
I’m working on a standalone app which allows the user to load in audio files, play/pause/resume/stop the file, view a thumbnail of the waveform etc. I got started using the “Build an audio player” and “Draw audio waveform” tutorials which both worked great.
I have moved all of the code handling the loading, transport functionality, waveform drawing etc into it’s own class so that I can instantiate multiple instances.
Here is the class:
#pragma once
#include <JuceHeader.h>
class fileComponent : public juce::AudioAppComponent, public juce::ChangeListener, private juce::Timer
{
public:
fileComponent();
~fileComponent() override;
enum TransportState
{
Stopped,
Starting,
Playing,
Pausing,
Paused,
Stopping
};
void paint (juce::Graphics&) override;
void resized() override;
//==============================================================================
void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override;
void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) override;
void releaseResources() override;
void changeListenerCallback (juce::ChangeBroadcaster* source) override;
void changeState (TransportState newState);
void openButtonClicked();
void playButtonClicked();
void stopButtonClicked();
void transportSourceChanged();
void thumbnailChanged();
void paintIfNoFileLoaded (juce::Graphics& g, const juce::Rectangle<int>& thumbnailBounds);
void paintIfFileLoaded (juce::Graphics& g, const juce::Rectangle<int>& thumbnailBounds);
void timerCallback() override;
private:
std::unique_ptr<juce::FileChooser> chooser;
juce::AudioFormatManager formatManager;
std::unique_ptr<juce::AudioFormatReaderSource> readerSource;
juce::AudioTransportSource transportSource;
TransportState state;
juce::AudioThumbnailCache thumbnailCache;
juce::AudioThumbnail thumbnail;
juce::TextButton openButton;
juce::TextButton playButton;
juce::TextButton stopButton;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (fileComponent)
};
Here is the code relating to actually loading in files:
void fileComponent::openButtonClicked()
{
chooser = std::make_unique<juce::FileChooser> ("Select a Wave file to play...",
juce::File{},
"*.wav");
auto chooserFlags = juce::FileBrowserComponent::openMode
| juce::FileBrowserComponent::canSelectFiles;
chooser->launchAsync (chooserFlags, [this] (const juce::FileChooser& fc)
{
//Get the file
auto file = fc.getResult();
//Check the file
if (file != juce::File{})
{
//Make a reader for this file
auto* reader = formatManager.createReaderFor (file);
if (reader != nullptr)
{
//Make the Format Reader Source from the reader
auto newSource = std::make_unique<juce::AudioFormatReaderSource> (reader, true);
//Set the transport source
transportSource.setSource (newSource.get(), 0, nullptr, reader->sampleRate);
playButton.setEnabled (true);
//Set source for the thumbnail
thumbnail.setSource(new juce::FileInputSource (file));
//Get rid of the Reader Source
readerSource.reset (newSource.release());
}
}
});
}
In the private section of my MainComponent.h file I have this:
fileComponent fileComp1;
fileComponent fileComp2;
fileComponent fileComp3;
In the MainComponent.cpp file I addAndMakeVisible and call prepareToPlay, getNextAudioBlock, releaseResources and set their bounds in the appropriate places. When I run the app and load files into each of the objects, I can click play/pause/etc. but only fileComp3 actually generates audio. The waveforms and buttons are loaded for all of them.
I’m thinking the problem is coming from the fact that in “openButtonClicked()” function, when each new file is being loaded,
readerSource.reset (newSource.release());
is being called. Since it is using a std::unique_ptr the object it’s pointing to is getting released and the next file gets loaded, the final file is the only one that is actually still loaded. It doesn’t seem to matter what order I click open and load files in, only the final one works as intended. I’m struggling with fixing this issue and would love some help.
Thanks in advance