Skip to content

Commit

Permalink
Mono Note in addition to Poly Voice mode (#1444)
Browse files Browse the repository at this point in the history
Initrocuce mono note mode
With layerd groups and stuff
And initial support for priority in the menu

Legato and cleanup still to do, but mergable
Mono - checkpoint one. Test at a keyboard

mono done
  • Loading branch information
baconpaul authored Nov 6, 2024
1 parent 736c3b0 commit c508b76
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 19 deletions.
124 changes: 121 additions & 3 deletions src-ui/app/edit-screen/components/GroupSettingsCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ GroupSettingsCard::GroupSettingsCard(SCXTEditor *e)
});
addAndMakeVisible(*polyMenu);

polyModeMenu = std::make_unique<jcmp::TextPushButton>();
polyModeMenu->setLabel("POLY");
polyModeMenu->setOnCallback([w = juce::Component::SafePointer(this)]() {
if (w)
w->showPolyModeMenu();
});
addAndMakeVisible(*polyModeMenu);

prioGlyph = mkg(jcmp::GlyphPainter::GlyphType::NOTE_PRIORITY);
prioMenu = mkm("LAST", "Priority");
glideGlpyh = mkg(jcmp::GlyphPainter::GlyphType::CURVE);
Expand Down Expand Up @@ -119,6 +127,7 @@ void GroupSettingsCard::resized()
spair(outputGlyph, outputMenu);
r = r.translated(0, rowHeight);
spair(polyGlygh, polyMenu);
polyModeMenu->setBounds(polyMenu->getBounds().translated(polyMenu->getWidth() + 2, 0));
r = r.translated(0, rowHeight);
spair(prioGlyph, prioMenu);
r = r.translated(0, rowHeight);
Expand All @@ -139,13 +148,25 @@ void GroupSettingsCard::resized()

void GroupSettingsCard::rebuildFromInfo()
{
if (info.hasIndependentPolyLimit)
if (info.vmPlayModeInt == (int32_t)engine::Engine::voiceManager_t::PlayMode::MONO_NOTES)
{
polyMenu->setLabel(std::to_string(info.polyLimit));
polyMenu->setEnabled(false);
polyModeMenu->setLabel("MONO");
repaint();
}
else
{
polyMenu->setLabel("PART");
polyMenu->setEnabled(true);
polyModeMenu->setLabel("POLY");
if (info.hasIndependentPolyLimit)
{
polyMenu->setLabel(std::to_string(info.polyLimit));
}
else
{
polyMenu->setLabel("PART");
}
repaint();
}
}

Expand Down Expand Up @@ -181,4 +202,101 @@ void GroupSettingsCard::showPolyMenu()
p.showMenuAsync(editor->defaultPopupMenuOptions());
}

void GroupSettingsCard::showPolyModeMenu()
{
auto p = juce::PopupMenu();
p.addSectionHeader("Group Voice/Note Mode");
p.addSeparator();

p.addItem(
"Poly", true,
info.vmPlayModeInt == (uint32_t)engine::Engine::voiceManager_t::PlayMode::POLY_VOICES,
[w = juce::Component::SafePointer(this)]() {
if (!w)
return;
w->info.vmPlayModeInt = (uint32_t)engine::Engine::voiceManager_t::PlayMode::POLY_VOICES;

w->rebuildFromInfo();
w->sendToSerialization(messaging::client::UpdateGroupOutputInfoPolyphony{w->info});
});
p.addItem(
"Mono", true,
info.vmPlayModeInt == (uint32_t)engine::Engine::voiceManager_t::PlayMode::MONO_NOTES,
[w = juce::Component::SafePointer(this)]() {
if (!w)
return;
w->info.vmPlayModeInt = (uint32_t)engine::Engine::voiceManager_t::PlayMode::MONO_NOTES;
w->info.vmPlayModeFeaturesInt =
(uint64_t)engine::Engine::voiceManager_t::MonoPlayModeFeatures::NATURAL_MONO;

w->rebuildFromInfo();
w->sendToSerialization(messaging::client::UpdateGroupOutputInfoPolyphony{w->info});
});
p.addItem("Legato", false, false, [w = juce::Component::SafePointer(this)]() {
if (!w)
return;
});
p.addSeparator();
p.addSectionHeader("Mono Release Priority");
// I could ovciously structure this better
p.addItem(
"Latest", false,
info.vmPlayModeFeaturesInt &
(uint32_t)engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_LATEST,
[w = juce::Component::SafePointer(this)]() {
if (!w)
return;
w->info.vmPlayModeInt = (uint32_t)engine::Engine::voiceManager_t::PlayMode::MONO_NOTES;
w->info.vmPlayModeFeaturesInt &=
~(uint64_t)
engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_HIGHEST;
w->info.vmPlayModeFeaturesInt &= ~(
uint64_t)engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_LOWEST;
w->info.vmPlayModeFeaturesInt |= (uint64_t)
engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_LATEST;

w->rebuildFromInfo();
w->sendToSerialization(messaging::client::UpdateGroupOutputInfoPolyphony{w->info});
});
p.addItem(
"Highest", false,
info.vmPlayModeFeaturesInt &
(uint32_t)engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_HIGHEST,
[w = juce::Component::SafePointer(this)]() {
if (!w)
return;
w->info.vmPlayModeInt = (uint32_t)engine::Engine::voiceManager_t::PlayMode::MONO_NOTES;
w->info.vmPlayModeFeaturesInt |= (uint64_t)
engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_HIGHEST;
w->info.vmPlayModeFeaturesInt &= ~(
uint64_t)engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_LOWEST;
w->info.vmPlayModeFeaturesInt &= ~(
uint64_t)engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_LATEST;

w->rebuildFromInfo();
w->sendToSerialization(messaging::client::UpdateGroupOutputInfoPolyphony{w->info});
});
p.addItem(
"Lowest", false,
info.vmPlayModeFeaturesInt &
(uint32_t)engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_LOWEST,
[w = juce::Component::SafePointer(this)]() {
if (!w)
return;
w->info.vmPlayModeInt = (uint32_t)engine::Engine::voiceManager_t::PlayMode::MONO_NOTES;
w->info.vmPlayModeFeaturesInt |= (uint64_t)
engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_LOWEST;
w->info.vmPlayModeFeaturesInt &= ~(
uint64_t)engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_LOWEST;
w->info.vmPlayModeFeaturesInt &=
~(uint64_t)
engine::Engine::voiceManager_t::MonoPlayModeFeatures::ON_RELEASE_TO_HIGHEST;

w->rebuildFromInfo();
w->sendToSerialization(messaging::client::UpdateGroupOutputInfoPolyphony{w->info});
});

p.showMenuAsync(editor->defaultPopupMenuOptions());
}

} // namespace scxt::ui::app::edit_screen
3 changes: 2 additions & 1 deletion src-ui/app/edit-screen/components/GroupSettingsCard.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct GroupSettingsCard : juce::Component, HasEditor
std::unique_ptr<sst::jucegui::components::GlyphPainter> midiGlyph, outputGlyph, polyGlygh,
prioGlyph, glideGlpyh, volGlyph, panGlyph, tuneGlyph;
std::unique_ptr<sst::jucegui::components::Label> pbLabel, SRCLabel;
std::unique_ptr<sst::jucegui::components::TextPushButton> polyMenu;
std::unique_ptr<sst::jucegui::components::TextPushButton> polyMenu, polyModeMenu;
std::unique_ptr<sst::jucegui::components::MenuButton> midiMenu, outputMenu, prioMenu, glideMenu,
srcMenu;
std::unique_ptr<sst::jucegui::components::DraggableTextEditableValue> pbDnVal, pbUpDrag,
Expand All @@ -67,6 +67,7 @@ struct GroupSettingsCard : juce::Component, HasEditor
engine::Group::GroupOutputInfo &info;

void showPolyMenu();
void showPolyModeMenu();
};
} // namespace scxt::ui::app::edit_screen
#endif // GROUPSETTINGSCARD_H
1 change: 1 addition & 0 deletions src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ static constexpr bool uiStructure{false};
static constexpr bool groupZoneMutation{false};
static constexpr bool memoryPool{false};
static constexpr bool voiceResponder{false};
static constexpr bool voiceLifecycle{false};
static constexpr bool generatorInitialization{false};
} // namespace log

Expand Down
2 changes: 2 additions & 0 deletions src/engine/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ struct Engine : MoveableOnly<Engine>, SampleRateSupport
uint16_t channel, uint16_t key, int32_t noteId, float velocity);

int32_t initializeMultipleVoices(
int32_t voiceCount,
const sst::voicemanager::VoiceInitInstructionsEntry<VMConfig>::buffer_t &,
sst::voicemanager::VoiceInitBufferEntry<VMConfig>::buffer_t &voiceInitWorkingBuffer,
uint16_t port, uint16_t channel, uint16_t key, int32_t noteId, float velocity,
float retune);
Expand Down
24 changes: 21 additions & 3 deletions src/engine/engine_voice_responder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ int32_t Engine::VoiceManagerResponder::beginVoiceCreationTransaction(
auto &z = engine.zoneByPath(path);

voiceCreationWorkingBuffer[voicesCreated] = {path, -1};
if (z->parentGroup->outputInfo.hasIndependentPolyLimit)
if (z->parentGroup->outputInfo.hasIndependentPolyLimit ||
z->parentGroup->outputInfo.vmPlayModeInt !=
(uint32_t)Engine::voiceManager_t::PlayMode::POLY_VOICES)
{
SCLOG_IF(voiceResponder, "-- Setting polyphony group to " << (uint64_t)z->parentGroup);
buffer[idx].polyphonyGroup = (uint64_t)z->parentGroup;
}
else
Expand All @@ -69,17 +72,30 @@ int32_t Engine::VoiceManagerResponder::beginVoiceCreationTransaction(
}

int32_t Engine::VoiceManagerResponder::initializeMultipleVoices(
int32_t voiceCount,
const sst::voicemanager::VoiceInitInstructionsEntry<VMConfig>::buffer_t &voiceInstructionBuffer,
sst::voicemanager::VoiceInitBufferEntry<VMConfig>::buffer_t &voiceInitWorkingBuffer,
uint16_t port, uint16_t channel, uint16_t key, int32_t noteId, float velocity, float retune)
{
assert(transactionValid);
assert(transactionVoiceCount > 0);
auto useKey = engine.midikeyRetuner.remapKeyTo(channel, key);
auto nts = transactionVoiceCount;
assert(nts == voiceCount);
SCLOG_IF(voiceResponder, "voice initiation of " << nts << " voices");
int32_t actualCreated{0};
int outIdx{0};
for (auto idx = 0; idx < nts; ++idx)
{
if (voiceInstructionBuffer[idx].instruction ==
sst::voicemanager::VoiceInitInstructionsEntry<
scxt::engine::Engine::VMConfig>::Instruction::SKIP)
{
SCLOG_IF(voiceResponder, "Skipping voice at index " << idx);
voiceInitWorkingBuffer[outIdx].voice = nullptr;
outIdx++;
continue;
}
const auto &[path, variantIndex] = voiceCreationWorkingBuffer[idx];
auto &z = engine.zoneByPath(path);
auto nbSampleLoadedInZone = z->getNumSampleLoaded();
Expand All @@ -95,7 +111,8 @@ int32_t Engine::VoiceManagerResponder::initializeMultipleVoices(
v->attack();
actualCreated++;
}
voiceInitWorkingBuffer[idx].voice = v;
voiceInitWorkingBuffer[outIdx].voice = v;
outIdx++;
SCLOG_IF(voiceResponder, "-- Created single voice for single zone ("
<< std::hex << v << std::dec << ")");
}
Expand Down Expand Up @@ -172,7 +189,8 @@ int32_t Engine::VoiceManagerResponder::initializeMultipleVoices(
v->attack();
actualCreated++;
}
voiceInitWorkingBuffer[idx].voice = v;
voiceInitWorkingBuffer[outIdx].voice = v;
outIdx++;
}
}
}
Expand Down
23 changes: 20 additions & 3 deletions src/engine/group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,13 +608,30 @@ void Group::onRoutingChanged() { SCLOG_ONCE("Implement Group LFO modulator use o

void Group::resetPolyAndPlaymode(engine::Engine &e)
{
if (!outputInfo.hasIndependentPolyLimit)
if (outputInfo.vmPlayModeInt == (uint32_t)Engine::voiceManager_t::PlayMode::MONO_NOTES)
{
// TODO we really want a 'clear'
if (outputInfo.vmPlayModeFeaturesInt == 0)
{
outputInfo.vmPlayModeFeaturesInt =
(uint64_t)Engine::voiceManager_t::MonoPlayModeFeatures::NATURAL_MONO;
}
auto pgrp = (uint64_t)this;
SCLOG_IF(voiceResponder, "Setting up mono group " << pgrp);
e.voiceManager.guaranteeGroup(pgrp);
e.voiceManager.setPlaymode(pgrp, Engine::voiceManager_t::PlayMode::MONO_NOTES,
outputInfo.vmPlayModeFeaturesInt);
}
else
{
e.voiceManager.setPolyphonyGroupVoiceLimit((uint64_t)this, outputInfo.polyLimit);
assert(outputInfo.vmPlayModeInt == (uint32_t)Engine::voiceManager_t::PlayMode::POLY_VOICES);
if (!outputInfo.hasIndependentPolyLimit)
{
// TODO we really want a 'clear'
}
else
{
e.voiceManager.setPolyphonyGroupVoiceLimit((uint64_t)this, outputInfo.polyLimit);
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/engine/group.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ struct Group : MoveableOnly<Group>,

bool hasIndependentPolyLimit{false};
int32_t polyLimit{0};

// I wish I could define these as the enum
// but this includes before engine and template blah
// makes it not quite worth it
uint32_t vmPlayModeInt{0};
uint64_t vmPlayModeFeaturesInt{0};
} outputInfo;

GroupTriggerConditions triggerConditions;
Expand Down
4 changes: 1 addition & 3 deletions src/engine/zone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ template <bool OS> void Zone::processWithOS(scxt::engine::Engine &onto)

for (int i = 0; i < cleanupIdx; ++i)
{
#if DEBUG_VOICE_LIFECYCLE
SCLOG("Cleanup Voice at " << SCDBGV((int)toCleanUp[i]->key));
#endif
SCLOG_IF(voiceLifecycle, "Cleanup Voice at " << SCD((int)toCleanUp[i]->key));
toCleanUp[i]->cleanupVoice();
}
}
Expand Down
Loading

0 comments on commit c508b76

Please sign in to comment.