effSetSpeakerArrangement return code does not seem to make sense
Which means that it might well say "no" everytime as of today. Whereas in Iplug it says always "yes". However this has the potential to break lots of compatibility, so let's be extra-careful here
(EDIT: actually in Audio Unit, we also say "no" everytime for speaker arrangement, so maybe there is this logic of not pretending to support it)
Could it be the real fix for #113 ? Looks like we made a badfix for it, and we don't need the channel reassignment layer.
- [ ] respond correctly in effSetSpeakerArrangement and see if any VST host react badly (Win & Mac)
- [x] remove the channel reassignment layer in VST, see if #113 reappear (EDIT: probably not doable to remove it)
Generally the idea to accept more input/output combination that the algorithm strictly need is harmful, because input and output becomes untyped and might result in the wrong conversion. It's important not to break this semantic.
Up !
This cause Panagement 2 to be mono-mono in Cubase
It seems to me that we should always return 1 in the case of effSetSpeakerArrangement opcode since we always accept the arrangement.
From the VST2 documentation
Set the plug-in's speaker arrangements. If a (VST >= 2.3) plug-in returns \e true, it means that it accepts this IO
arrangement. The Host doesn't need to ask for getSpeakerArrangement(). If the plug-in returns \e false it means that it
doesn't accept this arrangement, the Host should then ask for getSpeakerArrangement() and then can (optional)
recall setSpeakerArrangement().
I believe that if we return 0 then we need to look for effGetSpeakerArrangement opcode and respond to it accordingly.
Ah it makes kind of sense with this bit of documentation! Indeed in that case we should, at the next effGetSpeakerArrangement, return the preferred computed I/O combination I guess (probably won't work with all hosts)
It seems to me that we should always return 1 in the case of effSetSpeakerArrangement opcode since we always accept the arrangement.
Essentially saying always "yes" is like dynamic typing, you loose semantic information of "this is a mono signal that will be expanded to stereo" and instead say "sure, I'll make a mono signal out of your mono input"
Currently how it works is:
- we accept whatever is given by host
- and then deal with the consequence by rearranging input and output pointers before processing the VST2 clients (this was done by infamous commit d2dfcf7cb8d2bc64c1e9b752cd2d75ed738689d9 3 years ago, probably not reasonable to just revert blindly)
=> this cause Panagement, a
[LegalIO(1, 2), LegalIO(2, 2)]to be instantiated as mono to mono in some hosts.
The way other frameworks do it:
- Iplug v1 always return 1 and probably does some workaround similar to Dplug for dealing with consequences. Iplugv2 looks the same.
- DISTROH just doesn't support
effGetSpeakerArrangementoreffSetSpeakerArrangement, always return 0 - Who knows what JUCE does? It is probably more complicated.
Unfortunately that fix can also breaks compatibility with hosts that can't do "mono to stereo", so perhaps there would be a need for an option?
About the channel reassignment layer: I think it can stay, as a last resort strategy, the important thing being refusing unsupported I/O combinations (in hosts that can accept this refusal...).
I'm thinking we can set some sort of flags like _getSpeakerArrangementCalled and _setSpeakerArrangmentCalled and if we get effGetSpeakerArrangement at any point we can do something like
case effGetSpeakerArrangement: // opcode 76
{
VstSpeakerArrangement* pInputArr = cast(VstSpeakerArrangement*) value;
VstSpeakerArrangement* pOutputArr = cast(VstSpeakerArrangement*) ptr;
if (pInputArr !is null && pOutputArr !is null )
{
choosePreferedIOArrangment();
pInputArr.numChannels = preferredNumInputs;
pOutputArr.numChannels = preferredNumOutputs;
}
_getSpeakerArrangementCalled;
return 1;
}
And then handle it accordingly when we get _effSetSpeakerArrangement. If either _setSpeakerArrangementCalled or _getSpeakerArrangementCalled then we can go ahead and call chooseIOArrangement as normal. Otherwise we can check if the IO combination matches our preferred IO, if not we will return 0 and hope that we get effGetSpeakerArrangement from the host. If not on the next effSetSpeakerArrangment we will just default back to how we normally handle it.
I've started working on it in this commit. I still have to actually test it since Reaper doesnt seems to use these opcodes. I'll have to find an easily debuggable host to test on!
Sorry I need a while to understand what needs to change... this is very delicate and might break lots of things so let's go extra-slowly. I'm busy until next week.
Okay I completely understand!
From my tests in Audition, it appears that my assumption was wrong. Returning 0 for effSetSpeakerArrangement doesn't cause effGetSpeakerArrangement to be called. Infact effGetSpeakerArrangement is never being called.
Something that can also help is if you can log the actual number of buffers the host actually calls you with (this will be a surprise in one of the process calls)
Helpful advice from Plogue: https://www.plogue.com/
From Seb: strategies more than a clean/direct answer :
- have VstSpeakerArrangement* members in your class for input and output
- in your ctor (or whenever else as long as it's before the host starts querying) set
them up for you max channels count
- in setSpeakerArrangement:
- be prepared to be able to simply return false depending on any combo of
audioMasterGetProductString/audioMasterGetVendorString/audioMasterGetVendorVersion
- be prepared to be asked for more channels than your max and simply return false
- call matchArrangement between pluginInput/your class member version,
pluginOutput/your class member version, if that works that would be
the expected number of i/os to the processReplacing calls, return true if that works
(it's possible that you might want to disable some matches or return true
even if the match returned false)
- if you need to deal/handle different VstSpeakerArrangementType/VstSpeakerProperties scenarios, good luck
- setSpeakerArrangement could be called again by the host with different values between a pair of suspend/resume calls
Customer hit by the current behaviour:
I'm testing Panagement 2 Free in Cubase 10 Le, but I can't hear the binaural spectrum. I only hear the Reberb as it moves away and about. The volume drops and rises in both headphones (L and R) when I move Pan and Far.
It seems then that my assumption was completely off. That is very useful information indeed.