Skip to content

Commit

Permalink
Add option to apply MPE Timbre value as unipolar in the engine
Browse files Browse the repository at this point in the history
Implements #7960
  • Loading branch information
mkruselj committed Jan 14, 2025
1 parent 95ef2bb commit 98aa508
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 21 deletions.
11 changes: 11 additions & 0 deletions src/common/SurgePatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2890,6 +2890,13 @@ void SurgePatch::load_xml(const void *data, int datasize, bool is_preset)
dawExtraState.mpeEnabled = ival;
}

p = TINYXML_SAFE_TO_ELEMENT(de->FirstChild("mpeTimbreIsUnipolar"));

if (p && p->QueryIntAttribute("v", &ival) == TIXML_SUCCESS)
{
dawExtraState.mpeTimbreIsUnipolar = ival;
}

p = TINYXML_SAFE_TO_ELEMENT(de->FirstChild("oscPortIn"));

if (p && p->QueryIntAttribute("v", &ival) == TIXML_SUCCESS)
Expand Down Expand Up @@ -3707,6 +3714,10 @@ unsigned int SurgePatch::save_xml(void **data) // allocates mem, must be freed b
mpe.SetAttribute("v", dawExtraState.mpeEnabled ? 1 : 0);
dawExtraXML.InsertEndChild(mpe);

TiXmlElement mpeTimbreUni("mpeTimbreIsUnipolar");
mpeTimbreUni.SetAttribute("v", dawExtraState.mpeTimbreIsUnipolar ? 1 : 0);
dawExtraXML.InsertEndChild(mpeTimbreUni);

TiXmlElement oscPortIn("oscPortIn");
oscPortIn.SetAttribute("v", dawExtraState.oscPortIn);
dawExtraXML.InsertEndChild(oscPortIn);
Expand Down
3 changes: 3 additions & 0 deletions src/common/SurgeStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,7 @@ struct DAWExtraStateStorage

bool mpeEnabled = false;
int mpePitchBendRange = -1;
bool mpeTimbreIsUnipolar = false;

bool hasScale = false;
std::string scaleContents = "";
Expand Down Expand Up @@ -1683,7 +1684,9 @@ class alignas(16) SurgeStorage

Modulator::SmoothingMode smoothingMode = Modulator::SmoothingMode::LEGACY;
Modulator::SmoothingMode pitchSmoothingMode = Modulator::SmoothingMode::LEGACY;

float mpePitchBendRange = -1.0f;
bool mpeTimbreIsUnipolar = false;

std::atomic<int> otherscene_clients;

Expand Down
11 changes: 8 additions & 3 deletions src/common/SurgeSynthesizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ void SurgeSynthesizer::playNote(char channel, char key, char velocity, char detu
** and right now it doesn't
*/
bool noHold = !channelState[channel].hold;

if (mpeEnabled)
noHold = noHold && !channelState[0].hold;

Expand Down Expand Up @@ -2116,7 +2117,7 @@ float int7ToBipolarFloat(int x)
return (x - 64) * (1.f / 64.f);
}

return 0;
return 0.f;
}

void SurgeSynthesizer::channelController(char channel, int cc, int value)
Expand Down Expand Up @@ -2244,7 +2245,8 @@ void SurgeSynthesizer::channelController(char channel, int cc, int value)
{
if (mpeEnabled)
{
channelState[channel].timbre = int7ToBipolarFloat(value);
channelState[channel].timbre =
mpeTimbreIsUnipolar ? (value / 127.f) : int7ToBipolarFloat(value);
return;
}
break;
Expand Down Expand Up @@ -3496,7 +3498,7 @@ bool SurgeSynthesizer::isBipolarModulation(modsources tms) const
}
if (tms == ms_keytrack || tms == ms_lowest_key || tms == ms_highest_key ||
tms == ms_latest_key || tms == ms_pitchbend || tms == ms_random_bipolar ||
tms == ms_alternate_bipolar || tms == ms_timbre)
tms == ms_alternate_bipolar || (tms == ms_timbre && !mpeTimbreIsUnipolar))
return true;
else
return false;
Expand Down Expand Up @@ -5080,6 +5082,7 @@ void SurgeSynthesizer::populateDawExtraState()

des.mpeEnabled = mpeEnabled;
des.mpePitchBendRange = storage.mpePitchBendRange;
des.mpeTimbreIsUnipolar = mpeTimbreIsUnipolar;

des.isDirty = storage.getPatch().isDirty;

Expand Down Expand Up @@ -5150,6 +5153,8 @@ void SurgeSynthesizer::loadFromDawExtraState()
storage.mpePitchBendRange = des.mpePitchBendRange;
}

mpeTimbreIsUnipolar = des.mpeTimbreIsUnipolar;

storage.getPatch().isDirty = des.isDirty;

storage.monoPedalMode = (MonoPedalMode)des.monoPedalMode;
Expand Down
1 change: 1 addition & 0 deletions src/common/SurgeSynthesizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ class alignas(16) SurgeSynthesizer
bool &mpeEnabled;
int mpeVoices = 0;
int mpeGlobalPitchBendRange = 0;
bool mpeTimbreIsUnipolar = false;

std::bitset<128> disallowedLearnCCs{0};
std::array<uint64_t, 128> midiKeyPressedForScene[n_scenes];
Expand Down
3 changes: 3 additions & 0 deletions src/common/UserDefaults.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ std::string defaultKeyToString(DefaultKey k)
case MPEPitchBendRange:
r = "mpePitchBendRange";
break;
case MPETimbreIsUnipolar:
r = "mpeTimbreIsUnipolar";
break;
case UseCh2Ch3ToPlayScenesIndividually:
r = "useCh2Ch3ToPlayScenesIndividually";
break;
Expand Down
1 change: 1 addition & 0 deletions src/common/UserDefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ enum DefaultKey
VirtualKeyboardLayout,

MPEPitchBendRange,
MPETimbreIsUnipolar,
PitchSmoothingMode,
UseCh2Ch3ToPlayScenesIndividually,
MenuBasedMIDILearnChannel,
Expand Down
1 change: 1 addition & 0 deletions src/surge-xt/gui/SurgeGUIEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ class SurgeGUIEditor : public Surge::GUI::IComponentTagValue::Listener,
const Surge::Storage::DefaultKey &key, int defaultValue,
std::function<void(Modulator::SmoothingMode)> setSmooth);

void makeMpeTimbreMenu(juce::PopupMenu &menu, const bool asSubMenu);
juce::PopupMenu makeMpeMenu(const juce::Point<int> &rect, bool showhelp);
juce::PopupMenu makeTuningMenu(const juce::Point<int> &rect, bool showhelp);
juce::PopupMenu makeZoomMenu(const juce::Point<int> &rect, bool showhelp);
Expand Down
62 changes: 44 additions & 18 deletions src/surge-xt/gui/SurgeGUIEditorMenuStructures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,40 @@ juce::PopupMenu SurgeGUIEditor::makeLfoMenu(const juce::Point<int> &where)
return lfoSubMenu;
}

void SurgeGUIEditor::makeMpeTimbreMenu(juce::PopupMenu &menu, const bool asSubMenu)
{
using namespace Surge::Storage;

auto storage = &(synth->storage);
const bool mpeTimbreUnipolar =
getUserDefaultValue(&(synth->storage), MPETimbreIsUnipolar, false);

auto setter = [this, storage](bool value) {
synth->mpeTimbreIsUnipolar = true;
updateUserDefaultValue(storage, MPETimbreIsUnipolar, true);
refresh_mod();
synth->refresh_editor = true;
};

if (asSubMenu)
{
auto entries = asSubMenu ? juce::PopupMenu() : menu;

entries.addItem("Unipolar", true, mpeTimbreUnipolar, [setter]() { setter(true); });
entries.addItem("Bipolar", true, !mpeTimbreUnipolar, [setter]() { setter(false); });

menu.addSubMenu(Surge::GUI::toOSCase("MPE Timbre Value Range"), entries);
}
else
{
menu.addItem("Unipolar", true, mpeTimbreUnipolar, [setter]() { setter(true); });
menu.addItem("Bipolar", true, !mpeTimbreUnipolar, [setter]() { setter(false); });
}
}

juce::PopupMenu SurgeGUIEditor::makeMpeMenu(const juce::Point<int> &where, bool showhelp)
{
auto mpeSubMenu = juce::PopupMenu();

auto hu = helpURLForSpecial("mpe-menu");

if (hu != "" && showhelp)
Expand All @@ -219,22 +249,15 @@ juce::PopupMenu SurgeGUIEditor::makeMpeMenu(const juce::Point<int> &where, bool
mpeSubMenu.addSeparator();
}

std::string endis = "Enable MPE";

if (synth->mpeEnabled)
{
endis = "Disable MPE";
}

mpeSubMenu.addItem(endis.c_str(), [this]() { toggleMPE(); });
mpeSubMenu.addItem(fmt::format("{}able MPE", synth->mpeEnabled ? "En" : "Dis"),
[this]() { toggleMPE(); });

mpeSubMenu.addSeparator();

std::ostringstream oss;
oss << "Change MPE Pitch Bend Range (Current: " << synth->storage.mpePitchBendRange
<< " Semitones)";
auto str = fmt::format("Change MPE Pitch Bend Range (Current: {} Semitones)",
synth->storage.mpePitchBendRange);

mpeSubMenu.addItem(Surge::GUI::toOSCase(oss.str().c_str()), [this, where]() {
mpeSubMenu.addItem(Surge::GUI::toOSCase(str), [this, where]() {
const auto c{std::to_string(int(synth->storage.mpePitchBendRange))};
promptForMiniEdit(
c, "Enter a new value:", "MPE Pitch Bend Range", where,
Expand All @@ -245,12 +268,11 @@ juce::PopupMenu SurgeGUIEditor::makeMpeMenu(const juce::Point<int> &where, bool
mpeStatus);
});

std::ostringstream oss2;
int def = Surge::Storage::getUserDefaultValue(&(synth->storage),
Surge::Storage::MPEPitchBendRange, 48);
oss2 << "Change Default MPE Pitch Bend Range (Current: " << def << " Semitones)";
const int def = Surge::Storage::getUserDefaultValue(&(synth->storage),
Surge::Storage::MPEPitchBendRange, 48);
str = fmt::format("Change Default MPE Pitch Bend Range (Current: {} Semitones)", def);

mpeSubMenu.addItem(Surge::GUI::toOSCase(oss2.str().c_str()), [this, where]() {
mpeSubMenu.addItem(Surge::GUI::toOSCase(str), [this, where]() {
const auto c{std::to_string(int(synth->storage.mpePitchBendRange))};
promptForMiniEdit(
c, "Enter a default value:", "Default MPE Pitch Bend Range", where,
Expand All @@ -269,6 +291,10 @@ juce::PopupMenu SurgeGUIEditor::makeMpeMenu(const juce::Point<int> &where, bool

mpeSubMenu.addSubMenu(Surge::GUI::toOSCase("MPE Pitch Bend Smoothing"), smoothMenu);

mpeSubMenu.addSeparator();

makeMpeTimbreMenu(mpeSubMenu, true);

return mpeSubMenu;
}

Expand Down
14 changes: 14 additions & 0 deletions src/surge-xt/gui/SurgeGUIEditorValueCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,18 +917,31 @@ int32_t SurgeGUIEditor::controlModifierClicked(Surge::GUI::IComponentTagValue *c
}

auto lurl = hu;

if (lurl != "")
{
lurl = fullyResolvedHelpURL(lurl);
}

auto hmen = std::make_unique<Surge::Widgets::MenuTitleHelpComponent>(
ModulatorName::modulatorNameWithIndex(&synth->storage, current_scene, modsource,
modsource_index, false, false),
lurl);
hmen->setSkin(currentSkin, bitmapStore);

auto hment = hmen->getTitle();

contextMenu.addCustomItem(-1, std::move(hmen), nullptr, hment);

contextMenu.addSeparator();

if (modsource == ms_timbre && synth->mpeEnabled)
{
makeMpeTimbreMenu(contextMenu, false);

contextMenu.addSeparator();
}

int n_total_md = synth->storage.getPatch().param_ptr.size();
const int max_md = 4096;

Expand Down Expand Up @@ -1220,6 +1233,7 @@ int32_t SurgeGUIEditor::controlModifierClicked(Surge::GUI::IComponentTagValue *c
pm.get() ? std::move(pm) : nullptr, at);
}
}

int sc = limit_range(synth->storage.getPatch().scene_active.val.i, 0, n_scenes - 1);

// for macros only
Expand Down

0 comments on commit 98aa508

Please sign in to comment.