Skip to content

Commit

Permalink
Segregate monophonic midi from polyphonic midi signals
Browse files Browse the repository at this point in the history
MIDIcc for instance should route to an overarching handler not
to each voice. So introduce a MonoVoiceResponder also.
I'm sure I will tweak this futher. Still not quite stable API here.
  • Loading branch information
baconpaul committed Oct 2, 2024
1 parent 952a4b8 commit ef93561
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 49 deletions.
66 changes: 25 additions & 41 deletions include/sst/voicemanager/managers/polymanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

namespace sst::voicemanager::managers
{
template <typename Cfg, typename Responder> struct PolyManager
template <typename Cfg, typename VoiceResponder, typename MonoResponder> struct PolyManager
{
int64_t mostRecentNoteCounter{1};

Expand Down Expand Up @@ -52,8 +52,9 @@ template <typename Cfg, typename Responder> struct PolyManager
std::array<VoiceInfo, Cfg::maxVoiceCount> voiceInfo;
std::array<typename Cfg::voice_t *, Cfg::maxVoiceCount> voiceInitWorkingBuffer;

Responder &responder;
PolyManager(Responder &r) : responder(r)
VoiceResponder &responder;
MonoResponder &monoResponder;
PolyManager(VoiceResponder &r, MonoResponder &m) : responder(r), monoResponder(m)
{
std::fill(lastPBByChannel.begin(), lastPBByChannel.end(), 0);
}
Expand Down Expand Up @@ -122,6 +123,21 @@ template <typename Cfg, typename Responder> struct PolyManager
}
*/

if (lastPBByChannel[channel] != 0)
{
monoResponder.setMIDIPitchBend(channel, lastPBByChannel[channel] + 8192);
}

int cid{0};
for (auto &mcc : midiCCCache[channel])
{
if (mcc != 0)
{
monoResponder.setMIDI1CC(channel, cid, mcc);
}
cid++;
}

auto voicesLaunched = responder.initializeMultipleVoices(
voiceInitWorkingBuffer, port, channel, key, noteid, velocity, retune);
if (voicesLaunched != voicesToBeLaunched)
Expand All @@ -144,21 +160,6 @@ template <typename Cfg, typename Responder> struct PolyManager
vi.gatedDueToSustain = false;
vi.activeVoiceCookie = voiceInitWorkingBuffer[voicesLeft - 1];

if (lastPBByChannel[channel] != 0)
{
responder.setVoiceMIDIPitchBend(vi.activeVoiceCookie,
lastPBByChannel[channel] + 8192);
}

int cid{0};
for (auto &mcc : midiCCCache[channel])
{
if (mcc != 0)
{
responder.setMIDI1CC(vi.activeVoiceCookie, cid, mcc);
}
cid++;
}
voicesLeft--;
if (voicesLeft == 0)
{
Expand Down Expand Up @@ -226,19 +227,13 @@ template <typename Cfg, typename Responder> struct PolyManager
}
}

std::array<uint16_t, 16> lastPBByChannel{};
void routeMIDIPitchBend(int16_t port, int16_t channel, uint16_t pb14bit)
std::array<int16_t, 16> lastPBByChannel{};
void routeMIDIPitchBend(int16_t port, int16_t channel, int16_t pb14bit)
{
if (channel >= 0 && channel < lastPBByChannel.size())
lastPBByChannel[channel] = pb14bit - 8192;

for (auto &vi : voiceInfo)
{
if (vi.matches(port, channel, -1, -1)) // all keys and notes on a channel for midi PB
{
responder.setVoiceMIDIPitchBend(vi.activeVoiceCookie, pb14bit);
}
}
monoResponder.setMIDIPitchBend(channel, pb14bit);
}

void routeMIDIMPEChannelPitchBend(int16_t port, int16_t channel, uint16_t pb14bit)
Expand Down Expand Up @@ -309,14 +304,9 @@ template <typename Cfg, typename Responder> struct PolyManager
void routeMIDI1CC(int16_t port, int16_t channel, int8_t cc, int8_t val)
{
midiCCCache[channel][cc] = val;
for (auto &vi : voiceInfo)
{
if (vi.matches(port, channel, -1, -1)) // all keys and notes on a channel for midi PB
{
responder.setMIDI1CC(vi.activeVoiceCookie, cc, val);
}
}
monoResponder.setMIDI1CC(channel, cc, val);
}

void routePolyphonicAftertouch(int16_t port, int16_t channel, int16_t key, int8_t pat)
{
for (auto &vi : voiceInfo)
Expand All @@ -330,13 +320,7 @@ template <typename Cfg, typename Responder> struct PolyManager

void routeChannelPressure(int16_t port, int16_t channel, int8_t pat)
{
for (auto &vi : voiceInfo)
{
if (vi.matches(port, channel, -1, -1)) // all keys and notes on a channel for midi PB
{
responder.setChannelPressure(vi.activeVoiceCookie, pat);
}
}
monoResponder.setMIDIChannelPressure(channel, pat);
}
};
} // namespace sst::voicemanager::managers
Expand Down
7 changes: 4 additions & 3 deletions include/sst/voicemanager/voicemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

namespace sst::voicemanager
{
template <typename Cfg, typename Responder> struct VoiceManager
template <typename Cfg, typename Responder, typename MonoResponder> struct VoiceManager
{
enum VoiceMode
{
Expand All @@ -39,7 +39,8 @@ template <typename Cfg, typename Responder> struct VoiceManager
int8_t mpeGlobalChannel{0};

Responder &responder;
VoiceManager(Responder &r) : responder(r), polyManager(r)
MonoResponder &monoResponder;
VoiceManager(Responder &r, MonoResponder &m) : responder(r), monoResponder(m), polyManager(r, m)
{
polyManager.registerVoiceEndCallback();
}
Expand Down Expand Up @@ -192,7 +193,7 @@ template <typename Cfg, typename Responder> struct VoiceManager

static float midiToFloatVelocity(uint8_t vel) { return 1.f * vel / 127.f; }

using polymanager_t = sst::voicemanager::managers::PolyManager<Cfg, Responder>;
using polymanager_t = sst::voicemanager::managers::PolyManager<Cfg, Responder, MonoResponder>;
polymanager_t polyManager;
};
} // namespace sst::voicemanager
Expand Down
15 changes: 10 additions & 5 deletions tests/basic_poly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,9 @@ struct ConcreteResp
return 1;
}

void setMIDI1CC(void *v, int32_t cc, int32_t val) {}

void releaseVoice(void *v, float velocity) { innards.release(v, velocity); }
void retriggerVoiceWithNewNoteID(void *v, int32_t noteid, float velocity) {}

void setVoiceMIDIPitchBend(void *v, uint16_t) {}
int beginVoiceCreationTransaction(uint16_t port, uint16_t channel, uint16_t key, int32_t noteid,
float velocity)
{
Expand Down Expand Up @@ -126,16 +123,24 @@ struct ConcreteResp
} innards;
};

using voicemanager_t = sst::voicemanager::VoiceManager<Config, ConcreteResp>;
struct ConcreteMonoResp
{
void setMIDIPitchBend(int16_t channel, int16_t pb14bit) {}
void setMIDI1CC(int16_t channel, int16_t cc, int16_t val) {}
void setMIDIChannelPressure(int16_t channel, int16_t pres) {}
};

using voicemanager_t = sst::voicemanager::VoiceManager<Config, ConcreteResp, ConcreteMonoResp>;

TEST_CASE("Basic Poly Note On Note Off")
{
ConcreteResp concreteResp;
ConcreteMonoResp concreteMonoResp;

SECTION("OnOff")
{
// voice manager: consumes config
voicemanager_t vm(concreteResp);
voicemanager_t vm(concreteResp, concreteMonoResp);

// Send a midi message note on, see voice and gated voice tick up
uint16_t port{0}, channel{0}, key{60}, velocity{90};
Expand Down

0 comments on commit ef93561

Please sign in to comment.