MIDI into audio plugin

Is there anyway to create a plug-in that affects an audio track, but can also take in MIDI as input? MIDI would be used for neat things that aren’t relevant to the question. Just need the input into the plugin.

Plan would be to use the plugin in Logic Pro.

Thank you for any help!

1 Like

in the projucer you can tell your plugin that it is able to receive midi input. then it’s given to you as the 2nd argument of processBlock

I’m a bit new to JUCE, but my understanding is that JUCE itself is capable of being set up this way, but where you may run into problems is how the host handles I/O. For example, I know that in Ableton this will work just fine, you just set up your VST as an audio effect on an audio track, then set up a MIDI track and route its MIDI output to your plugin on the audio track. But I believe that Logic makes this more difficult, if not impossible…

In Logic, you have to add the plugin to an Instrument track as an Input, and then set your Audio track as its sidechain input.

1 Like

@HowardAntares I’m making a plugin that needs to accept both audio & MIDI… If I want to make sure that Logic users will be able to use it the way you describe, do I need to do anything special to my JUCE code to allow it to accept sidechain? Currently I’m not using or dealing with sidechaining at all, because for the “normal” use of the plugin in a DAW like Ableton it’s not needed…

I think this addition of the second withInput here was needed, in the initialization of my Processor class:

: AudioProcessor( BusesProperties()	.withInput("Input", AudioChannelSet::stereo()).withOutput("Output", AudioChannelSet::stereo()).withInput ("Sidechain", AudioChannelSet::stereo(), true)
1 Like

okay, thanks!.. so my plugin’s audio input (to the actual processBlock() ) is only ever supposed to be a mono channel of audio (it’s a pitch shifter), so if I add this .withInput(“Sidechain”), would I also need to add some sort of input selector somewhere in my code, to determine if it’s reading from the “normal” inputs or the “sidechain” input?

if so, could/should I have the plugin do this automatically by detecting the DAW being used…?

Ideally, if the user is in Ableton, I wouldn’t want my plugin to show a sidechain selector in the host because it doesn’t actually need a sidechain input… I hope this makes sense.

Thanks for your help!

No, it’s not necessary. I have a couple of audio effect plugins that accept MIDI notes and my processBlock is only ever just getting a pointer to the audio buffer with SampleType* channelData = buffer.getWritePointer(channel);, no conditionals to check for DAW and/or sidechain usage.

This is a good point, I just confirmed that my plugins do indeed show a needless sidechain input selector in Ableton, I assume that it should be possible to set the BusProperties up according to DAW being used.

1 Like

Yep. Here’s how to get that information:

if (pluginHostType.isAbletonLive())
1 Like

Awesome, thank you both!

So in my audio processor’s constructor I have

AudioProcessor::AudioProcessor(): (BusesProperties()
                       .withInput  ("Input",  juce::AudioChannelSet::mono(), true)
                       .withOutput ("Output", juce::AudioChannelSet::stereo(), true)
                       )
{
if(! host.isAbletonLive())  // where host is a pluginHostType object that's a member of my AudioProcessor class
		BusesProperties().withInput("Sidechain", juce::AudioChannelSet::mono(), true);
}

It seems like this works! My only question left is if I need to put the .withInput ("Input"...) in a conditional in the body of the constructor as well, like

if(! host.isAbletonLive())  // where host is a pluginHostType object that's a member of my AudioProcessor class
		BusesProperties().withInput("Sidechain", juce::AudioChannelSet::mono(), true);
else
        BusesProperties().withInput  ("Input",  juce::AudioChannelSet::mono(), true)
}

or should I leave it as it is now?

Thanks again!

I’m somewhat surprised that works, I would have thought you would need a little helper function to create the BusProperties in the constructor parameters, something like:

BusProperties AudioProcessor::makeBusProperties()
{
    auto pluginHost = PluginHostType();
    if(pluginHost.isLogic() || pluginHost.isGarageBand())
    {
        // only add the side-chain to hosts that need it
        return BusesProperties().withInput("Input", AudioChannelSet::stereo())
                                .withInput ("Sidechain", AudioChannelSet::stereo()
                                .withOutput("Output", AudioChannelSet::stereo());
    }
    else
    {
        // every other host needs no sidechain
        return BusesProperties().withInput("Input", AudioChannelSet::stereo())
                                .withOutput("Output", AudioChannelSet::stereo());
    }   
}

AudioProcessor::AudioProcessor(makeBusProperties(), true)
{
    // ...
}

This is completely untested, but something like that is what I imagine is needed.

1 Like

This is much cleaner, thanks! It works, with some minor syntax alterations. For anyone else finding this, here’s how I got it to work:

YourPluginAudioProcessor::YourPluginAudioProcessor(): AudioProcessor(makeBusProperties())
AudioProcessor::BusesProperties YourPluginAudioProcessor::makeBusProperties()
{
	PluginHostType host;
	if(host.isLogic() || host.isGarageBand())
		return BusesProperties().withInput("Input", AudioChannelSet::mono(), false)
								.withInput("Sidechain", AudioChannelSet::mono(), true)
								.withOutput("Output", AudioChannelSet::stereo(), true);
	else
		return BusesProperties().withInput("Input", AudioChannelSet::mono(), true)
								.withOutput("Output", AudioChannelSet::stereo(), true);
}