Skip to content

Commit

Permalink
Mono Voice Priority Modes (#3362)
Browse files Browse the repository at this point in the history
This adds 3 new voice prioprity modes; always latest,highest, and lowest,
and adjusts the regular and MPE voice management to respect them.
It adds a collection of assertive regtests which test it, streams it
into the patch, and adds it to the UI.

Closes #3359
  • Loading branch information
baconpaul authored Dec 7, 2020
1 parent 02b1fec commit 3f66c20
Show file tree
Hide file tree
Showing 9 changed files with 819 additions and 85 deletions.
32 changes: 32 additions & 0 deletions src/common/SurgePatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,26 @@ void SurgePatch::load_xml(const void* data, int datasize, bool is_preset)
}
}

TiXmlElement* nonparamconfig = TINYXML_SAFE_TO_ELEMENT(patch->FirstChild("nonparamconfig"));
if( nonparamconfig )
{
for( int sc=0; sc < n_scenes; ++sc )
{
std::string mvname = "monoVoicePrority_" + std::to_string(sc);
auto *mv1 = TINYXML_SAFE_TO_ELEMENT(nonparamconfig->FirstChild( mvname.c_str() ));
storage->getPatch().scene[sc].monoVoicePriorityMode = ALWAYS_LATEST;
if( mv1 )
{
// Get value
int mvv;
if( mv1->QueryIntAttribute("v", &mvv ) == TIXML_SUCCESS )
{
storage->getPatch().scene[sc].monoVoicePriorityMode = (MonoVoicePriorityMode)mvv;
}
}
}
}

if (revision < 1)
{
for (int sc = 0; sc < n_scenes; sc++)
Expand Down Expand Up @@ -1463,6 +1483,7 @@ void SurgePatch::load_xml(const void* data, int datasize, bool is_preset)
// The Great Filter Remap of issue #3006
for (auto& sc : scene)
{
sc.monoVoicePriorityMode = NOTE_ON_LATEST_RETRIGGER_HIGHEST; // Older patches use Legacy mode
for (int u = 0; u < n_filterunits_per_scene; u++)
{
auto* fu = &(sc.filterunit[u]);
Expand Down Expand Up @@ -2005,6 +2026,17 @@ unsigned int SurgePatch::save_xml(void** data) // allocates mem, must be freed b
}
patch.InsertEndChild(parameters);

// TODO: Stream that priority mode here
TiXmlElement nonparamconfig( "nonparamconfig" );
for( int sc=0; sc < n_scenes; ++sc )
{
std::string mvname = "monoVoicePrority_" + std::to_string(sc);
TiXmlElement mvv(mvname.c_str());
mvv.SetAttribute("v", storage->getPatch().scene[sc].monoVoicePriorityMode);
nonparamconfig.InsertEndChild(mvv);
}
patch.InsertEndChild(nonparamconfig);

TiXmlElement eod( "extraoscdata" );
for (int sc = 0; sc < n_scenes; ++sc)
{
Expand Down
44 changes: 29 additions & 15 deletions src/common/SurgeStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,10 +440,35 @@ const char em_names[n_env_modes][16] =
"Analog",
};


/*
* How does the sustain pedal work in mono mode? Current modes for this are
*
* HOLD_ALL_NOTES (the default). If you release a note with the pedal down
* it does not release
*
* RELEASE_IF_OTHERS_HELD. If you release a note, and no other notes are down,
* do not release. But if you release and another note is down, return to that
* note (basically allow sustain pedal trills).
*/
enum MonoPedalMode {
HOLD_ALL_NOTES,
RELEASE_IF_OTHERS_HELD
};

enum MonoVoicePriorityMode {
NOTE_ON_LATEST_RETRIGGER_HIGHEST, // The legacy mode for 1.7.1 and earlier
ALWAYS_LATEST, // Could also be called "NOTE_ON_LATEST_RETRIGGER_LATEST"
ALWAYS_HIGHEST,
ALWAYS_LOWEST,
};


struct MidiKeyState
{
int keystate;
char lastdetune;
int64_t voiceOrder;
};

struct MidiChannelState
Expand Down Expand Up @@ -548,6 +573,8 @@ struct SurgeSceneStorage
std::vector<ModulationSource*> modsources;

bool modsource_doprocess[n_modsources];

MonoVoicePriorityMode monoVoicePriorityMode = ALWAYS_LATEST;
};

const int n_stepseqsteps = 16;
Expand Down Expand Up @@ -627,6 +654,8 @@ struct MSEGStorage {
struct FormulaModulatorStorage { // Currently an unused placeholder
};



/*
** There are a collection of things we want your DAW to save about your particular instance
** but don't want saved in your patch. So have this extra structure in the patch which we
Expand Down Expand Up @@ -793,21 +822,6 @@ enum surge_copysource
n_copysources,
};

/*
* How does the sustain pedal work in mono mode? Current modes for this are
*
* HOLD_ALL_NOTES (the default). If you release a note with the pedal down
* it does not release
*
* RELEASE_IF_OTHERS_HELD. If you release a note, and no other notes are down,
* do not release. But if you release and another note is down, return to that
* note (basically allow sustain pedal trills).
*/
enum MonoPedalMode {
HOLD_ALL_NOTES,
RELEASE_IF_OTHERS_HELD
};


/* STORAGE layer */

Expand Down
Loading

0 comments on commit 3f66c20

Please sign in to comment.