Hey i’m new to Juce / audio development
I’m currently working on my first project (vst) a Sampler / Synth and i want to implement threading for sample loading & pre-processing of the sample.
while loading the sample the UI thread should be locked while my LevelMeters will still update (own thread?) if possible if not i want to skip sections while the thread is running using the “isThreadRunning()” function with an “if” and notifying the UI thread that the loading sample thread has finished and the UI can repaint.
here is what i have so far (of course highly reduced)
i have tried the last two 2 days alot of diffrent things but nothing seems to work probably
so im looking forwad to any kind of advice
PluginEditor.cpp
SampleBasedSynthAudioProcessorEditor::SampleBasedSynthAudioProcessorEditor (SampleBasedSynthAudioProcessor& p)
: AudioProcessorEditor (&p), audioProcessor (p), Thread("UI")
{
addAndMakeVisible(levelMeterLeft);
addAndMakeVisible(levelMeterRight);
startTimerHz(24);
}
void SampleBasedSynthAudioProcessorEditor::paint (juce::Graphics& g)
{
if (!loadedSampleOne) { g.drawFittedText("drag&drop sample here!", sampleOneBackground.getSmallestIntegerContainer(), juce::Justification::centred, 1); }
if (loadedSampleOne) // && !sampleLoader.isThreadRunning()
{
drawWaveform();
}
}
bool SampleBasedSynthAudioProcessorEditor::isInterestedInFileDrag(const juce::StringArray& files)
{
for (auto file : files)
{
if (file.contains(".wav") || file.contains(".mp3") || file.contains(".aif"))
{
return true;
}
}
return false;
}
void SampleBasedSynthAudioProcessorEditor::filesDropped(const juce::StringArray& files, int x, int y)
{
for (auto file : files)
{
if (isInterestedInFileDrag(file))
{
if (zoneOne.contains(x, y))
{
sampleLoader.loadSample(file, audioProcessor.getMySampleBufferOne(), audioProcessor.getSynth());
loadedSampleOne = true;
}
}
}
while (sampleLoader.isThreadRunning())
{
DBG("loading...");
wait(250);
}
repaint();
}
void SampleBasedSynthAudioProcessorEditor::timerCallback()
{
levelMeterLeft.setLevel(audioProcessor.getRmsValueLeft());
levelMeterRight.setLevel(audioProcessor.getRmsValueRight());
levelMeterLeft.repaint();
levelMeterRight.repaint();
}
SampleLoader.h
class SampleLoader : public juce::Thread
{
public:
SampleLoader() : juce::Thread("Load Sample")
{
formatManger.registerBasicFormats();
}
~SampleLoader()
{
formatReader = nullptr;
formatWriter = nullptr;
}
void loadSample(juce::String& p, juce::AudioBuffer<float>& b, juce::Synthesiser& s)
{
setPath(p);
setBuffer(b);
setSampler(s);
startThread(Priority::normal);
}
void setPath(juce::String& p) { file = juce::File(p); }
void setBuffer(juce::AudioBuffer<float>& b) { buffer.reset(&b); }
void setSampler(juce::Synthesiser& s) { sampler.reset(&s); }
private:
void run() override
{
formatReader.reset(formatManger.createReaderFor(file));
auto sampleLength = static_cast<int>(formatReader->lengthInSamples);
buffer->setSize(2, sampleLength);
formatReader->read(buffer.get(), 0, sampleLength, 0, true, true);
//TO-DO pre-processing
file = ("D:/test.wav");
file.deleteFile();
writer.reset(wavFormat.createWriterFor(new juce::FileOutputStream(file),
44100,
buffer->getNumChannels(),
24,
{},
0));
if (writer != nullptr)
writer->writeFromAudioSampleBuffer(*buffer.get(), 0, buffer->getNumSamples());
juce::BigInteger range;
range.setRange(0, 128, true);
formatReader.reset(formatManger.createReaderFor(file)); // <- not working
formatReader->read(buffer.get(), 0, sampleLength, 0, true, true);
sampler->clearSounds();
sampler->addSound(new juce::SamplerSound("Sample", *formatReader, range, 60, 0.01, 0.1, 16.0));
}
juce::File file;
std::unique_ptr<juce::AudioBuffer<float>> buffer;
std::unique_ptr<juce::Synthesiser> sampler;
juce::AudioFormatManager formatManger;
std::unique_ptr<juce::AudioFormatReader> formatReader { nullptr };
juce::WavAudioFormat wavFormat;
std::unique_ptr<juce::AudioFormatWriter> writer;
};
I also have 2 other problems with my sampleLoader class
1: reading out the newly created file will not work the reader read function will always result in an empty buffer and when playing a note it crashes
2: The second Time when loading a sample the programm crashes when setBuffer(b); is been called
Error message:
HEAP[AudioPluginHost.exe]: Invalid address specified to RtlValidateHeap( 000001FE440C0000, 000001FE46176548 )
A breakpoint instruction (__debugbreak() statement or a similar call) was executed in AudioPluginHost.exe.
delete_scalar.cpp
_CRT_SECURITYCRITICAL_ATTRIBUTE
void __CRTDECL operator delete(void* const block) noexcept
{
#ifdef _DEBUG
_free_dbg(block, _UNKNOWN_BLOCK);
#else
free(block);
#endif
}