Are you using the JUCE plug-in host? I’ve tried reproducing this with the following code but I’m not seeing any issues:
/*******************************************************************************
The block below describes the properties of this PIP. A PIP is a short snippet
of code that can be read by the Projucer and used to generate a JUCE project.
BEGIN_JUCE_PIP_METADATA
name: VST3Programs
dependencies: juce_audio_basics, juce_audio_devices, juce_audio_formats, juce_audio_plugin_client,
juce_audio_processors, juce_audio_utils, juce_core, juce_data_structures, juce_events,
juce_graphics, juce_gui_basics, juce_gui_extra
exporters: xcode_mac
moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1
type: AudioProcessor
mainClass: MyPlugin
END_JUCE_PIP_METADATA
*******************************************************************************/
#pragma once
//==============================================================================
class MyPlugin : public AudioProcessor
{
public:
//==============================================================================
MyPlugin()
: AudioProcessor (BusesProperties().withInput ("Input", AudioChannelSet::stereo())
.withOutput ("Output", AudioChannelSet::stereo()))
{
}
~MyPlugin()
{
}
//==============================================================================
void prepareToPlay (double, int) override
{
// Use this method as the place to do any pre-playback
// initialisation that you need..
}
void releaseResources() override
{
// When playback stops, you can use this as an opportunity to free up any
// spare memory, etc.
}
void processBlock (AudioBuffer<float>& buffer, MidiBuffer&) override
{
ScopedNoDenormals noDenormals;
auto totalNumInputChannels = getTotalNumInputChannels();
auto totalNumOutputChannels = getTotalNumOutputChannels();
// In case we have more outputs than inputs, this code clears any output
// channels that didn't contain input data, (because these aren't
// guaranteed to be empty - they may contain garbage).
// This is here to avoid people getting screaming feedback
// when they first compile a plugin, but obviously you don't need to keep
// this code if your algorithm always overwrites all the output channels.
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear (i, 0, buffer.getNumSamples());
// This is the place where you'd normally do the guts of your plugin's
// audio processing...
// Make sure to reset the state if your inner loop is processing
// the samples and the outer loop is handling the channels.
// Alternatively, you can process the samples with the channels
// interleaved by keeping the same state.
for (int channel = 0; channel < totalNumInputChannels; ++channel)
{
auto* channelData = buffer.getWritePointer (channel);
// ..do something to the data...
}
}
//==============================================================================
AudioProcessorEditor* createEditor() override { return nullptr; }
bool hasEditor() const override { return false; }
//==============================================================================
const String getName() const override { return "VST3Programs"; }
bool acceptsMidi() const override { return false; }
bool producesMidi() const override { return false; }
double getTailLengthSeconds() const override { return 0; }
//==============================================================================
int getNumPrograms() override { return programs.size(); }
int getCurrentProgram() override { return selected; }
void setCurrentProgram (int index) override { selected = index; DBG ("PROGRAM SELECTED: " + programs[selected]); }
const String getProgramName (int index) override { return programs[index]; }
void changeProgramName (int, const String&) override {}
//==============================================================================
void getStateInformation (MemoryBlock& destData) override
{
// You should use this method to store your parameters in the memory block.
// You could do that either as raw data, or use the XML or ValueTree classes
// as intermediaries to make it easy to save and load complex data.
}
void setStateInformation (const void* data, int sizeInBytes) override
{
// You should use this method to restore your parameters from this memory block,
// whose contents will have been created by the getStateInformation() call.
}
//==============================================================================
bool isBusesLayoutSupported (const BusesLayout& layouts) const override
{
// This is the place where you check if the layout is supported.
// In this template code we only support mono or stereo.
if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
return false;
// This checks if the input layout matches the output layout
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
return true;
}
private:
int selected = 0;
StringArray programs { "Program 1", "Program 2", "Program 3", "Program 4", "Program 5",
"Program 6", "Program 7", "Program 8", "Program 9", "Program 10",
"Program 11", "Program 12", "Program 13", "Program 14", "Program 15",
"Program 16", "Program 17", "Program 18", "Program 19", "Program 20" };
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MyPlugin)
};
What do your plug-in’s get/setCurrentProgram()
methods look like?