v15b: fix CC7 to VSTi (legacy tag kHostMidiCC+cc + volume-param fallback), CC lane grid + 0/+- labels
This commit is contained in:
@@ -76,6 +76,8 @@ using Steinberg::Vst::ParamID;
|
||||
using Steinberg::Vst::ParamValue;
|
||||
using Steinberg::Vst::IMidiMapping;
|
||||
using Steinberg::Vst::IParamValueQueue;
|
||||
using Steinberg::Vst::ParameterInfo;
|
||||
using Steinberg::Vst::TChar;
|
||||
using Steinberg::Vst::kNoParamId;
|
||||
using Steinberg::Vst::BusInfo;
|
||||
using Steinberg::Vst::kAudio;
|
||||
@@ -154,6 +156,11 @@ struct Vst3HostState {
|
||||
// every overlapping voice gets a unique id and note-off releases them all.
|
||||
int32 nextNoteId = 1;
|
||||
std::vector<int32> noteIdsByPitch[128];
|
||||
// CC → plugin param tag cache for the no-IMidiMapping volume fallback
|
||||
// (scanVolumeParam). 0 = unresolved; kNoParamId = no matching param.
|
||||
bool ccParamResolved[128] = {};
|
||||
bool ccLogged[128] = {};
|
||||
ParamID ccParamTag[128] = {};
|
||||
};
|
||||
|
||||
// Resolve the plugin's ParamID for a MIDI CC / pitch-bend, preferring the
|
||||
@@ -173,6 +180,39 @@ ParamID midiControllerTag(IPtr<IEditController>& controller, int16 channel,
|
||||
return legacyTag;
|
||||
}
|
||||
|
||||
// Case-insensitive substring match of an ASCII token on a UTF-16 SDK string.
|
||||
bool titleContains(const TChar* s, const char* token) {
|
||||
for (int i = 0; i < 127 && s[i] != 0; ++i) {
|
||||
int j = 0;
|
||||
for (; token[j]; ++j) {
|
||||
if (i + j >= 127 || s[i + j] == 0) break;
|
||||
char c = (char)(s[i + j] & 0x7F);
|
||||
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
|
||||
if (c != token[j]) break;
|
||||
}
|
||||
if (token[j] == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// No-IMidiMapping fallback: scan the controller's parameter list for the
|
||||
// first volume/gain/output/level/master param (priority order) and use its
|
||||
// tag for CC 7/11. Plugins without mapping ignore the legacy kHostMidiCC
|
||||
// tags, so CC volume curves die there without this scan.
|
||||
ParamID scanVolumeParam(IPtr<IEditController>& controller) {
|
||||
if (!controller) return kNoParamId;
|
||||
static const char* tokens[] = {"volume", "gain", "output", "level", "master"};
|
||||
int32 count = controller->getParameterCount();
|
||||
for (int32 i = 0; i < count; ++i) {
|
||||
ParameterInfo info = {};
|
||||
if (controller->getParameterInfo(i, info) != kResultOk) continue;
|
||||
for (const char* t : tokens) {
|
||||
if (titleContains(info.title, t)) return info.id;
|
||||
}
|
||||
}
|
||||
return kNoParamId;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
@@ -474,7 +514,22 @@ void Vst3Instrument::controlChange(uint32_t channel, uint32_t cc, uint32_t value
|
||||
auto* s = static_cast<Vst3HostState*>(state_);
|
||||
if (!s || !s->controller) return;
|
||||
ParamID tag = midiControllerTag(s->controller, 0, (int16)cc,
|
||||
kHostMidiCC);
|
||||
kHostMidiCC + cc);
|
||||
// IMidiMapping absent (common): plugin cannot resolve kHostMidiCC+cc, so
|
||||
// fall back to a scanned volume param (resolved once per CC).
|
||||
if (cc < 128 && tag == kHostMidiCC + cc && !s->ccParamResolved[cc]) {
|
||||
s->ccParamResolved[cc] = true;
|
||||
s->ccParamTag[cc] = scanVolumeParam(s->controller);
|
||||
std::cerr << "[midi] cc=" << cc << " no IMidiMapping → volume-param tag=0x"
|
||||
<< std::hex << s->ccParamTag[cc] << std::dec << std::endl;
|
||||
}
|
||||
if (cc < 128 && tag == kHostMidiCC + cc) tag = s->ccParamTag[cc];
|
||||
if (cc < 128 && !s->ccLogged[cc]) {
|
||||
s->ccLogged[cc] = true;
|
||||
std::cerr << "[midi] cc=" << cc << " tag=0x" << std::hex << tag
|
||||
<< std::dec << " v=" << value << std::endl;
|
||||
}
|
||||
if (tag == kNoParamId) return;
|
||||
ParamValue v = value / 127.0;
|
||||
// setParamNormalized covers single-component plugins; the param queue
|
||||
// reaches split plugins that read inputParameterChanges inside process().
|
||||
|
||||
Reference in New Issue
Block a user