Open p0nce opened 7 years ago
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.
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:
[LegalIO(1, 2), LegalIO(2, 2)]
to be instantiated as mono to mono in some hosts.The way other frameworks do it:
effGetSpeakerArrangement
or effSetSpeakerArrangement
, always return 0Unfortunately 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.
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)