Hey there. I am building a Sidechain compression plugin which allows you to get a Sidechain input from another track where the DAW doesn’t support sidechaining. For this, I made use of the Singleton structure in JUCE to be able to share data between the two instances (one on the source, one on the target track), where the sending instance puts the data it receives in processBlock in a AudioBuffer object in my Singleton struct and the receiving instance is reading that and copies it into the actual buffer by doing
AudioBuffer<float>& remoteBuffer = singleton->remoteBuffer;
if (remoteBuffer.getNumSamples() > 0)
buffer.makeCopyOf(remoteBuffer);
This works, but when I’m listening I can hear that the track with the receiving end has some stuttering in the audio signal. Is my attempt too slow? Thanks!
makeCopyOf doesn’t only copy the samples, it can/will also reallocate the buffer. It has the argument that makes it attempt to not reallocate, though. You should not ever allocate memory in the audio processing thread.
However, I suspect there are other, much worse flaws, in your design at the moment. Passing audio data between plugin instances is a very complicated thing to attempt and there are no guarantees it can even be made to work.
Yea I recognized that it’s complicated but generally speaking when I’m sharing a buffer via a shared memory and only pass references instead of copying, I should be able to have no stuttering in the buffers as there’s nothing copied. I just hope it doesn’t involve any thread difficulties and/or memory lock stuff. Is there maybe any other attempt?
As already pointed out, makeCopyOf should not be used in the audio thread, although it has a flag to avoid reallocation it will not guarantee you to not allocate if I get it right. copyFrom is the function to use if you are copying on the audio thread.
However, I doubt your design works stable. Just consider those totally possible scenarios:
The host processes all plugins in one thread. However it choses to sometimes process the source plugin before the receiver plugin and sometimes does it the other way round
The host renders plugins on multiple threads. The source plugin accesses the shared buffer at the very same time as the destination plugin does
The host renders plugins in separate processes. Both plugin instances create an own instance of your singleton in their own process
The host decides to call the source plugin with a different block size than the destination plugin
Judging from the code snippet I see, I would expect all those cases to lead to a fail or massive drop of buffers / discontinuity in the audio signal.
Haha, FCPX doesn’t even do aux tracks, so where would it send the side chain to? FCPX is unsuitable for anything audio beyond copying a clip in. Granted, you can add effects on a clip and automate, but that’s as good as it gets.
Cubase Elements (the cheapest version) has no sidechain support and upgrading is pretty expensive so I thought my idea might be nice! But if it won’t work, it won’t There are some plugins though which have exactly this sidechain support I wanted to do so I wonder how they got it working
Maybe those plugins are using a shared thread-safe queue (ring buffer) and add some latency…? That way there could be at least some chance the receiving plugins will have enough audio to work with. Or maybe the developers of those plugins have asked Steinberg how it could be done inside Cubase Elements…
Ableton offers sidechain support in their Intro version for 79€. They probably have other limits but for a small indie musician like me it’s hard to cover
Are those plugins you mentioned that do sidechain made by Steinberg? If so, it makes sense they would expose ‘secret’ parts of their API to their own plugins.
If those are 3rd party, could you please name those so I could test it myself and maybe figure out what black magic they pulled off there?
Haven’t installed it, but could it be, that they just share the envelope, which is not as sensible, since it is low-passed anyway, and in most cases not as critical?
You could do nasty tests, like setting the send plugin on a normal track and the other on a track that does a lot of latency compensation?
iirc Sidechain Compressor | Dance production & voiceover audio plug-in does what OP is trying to achieve: comes with 2 plugins, a “sender” which you put as insert on your kick for instance, and the actual compressor which can receive from the sender that you would put on your bass.
Yea exactly. Even though there are solutions I’m very interested in seeing how they achieved it. I’m eager to learn as JUCE is an extremely interesting framework for me (I’m coming from game development)
It basically allows you to do quite simple “black box” plugins, similar to simple guitar pedals or MIDI controlled hardware synths. Anything more complicated will be a world of pain. Might be possible to do or not. (And that isn’t even really Juce’s fault, the plugin formats and APIs are just quite limited in what they expect you to do.)
There’s no guarantee that your plugins will be called in the correct order for sidechaining to work. Some hosts might be using multithreaded audio pipelines (this is especially common when rendering).
You probably want to use a FIFO (see juce::AbstractFifo) for passing audio between the plugins.
You might be able to achieve some hacks; your plugins might always
be called in the incorrect order, for example. You could skip a frame and have both plugins running a frame behind.