Skip to content

Commit

Permalink
Fix Pedal Edge Case Bugs
Browse files Browse the repository at this point in the history
1. Midi channel 3 and 4 picked channel mask incorrectly.
   Make it mode aware and do the right thing
2. Multiple presses of a key on and off while the systain
   pedal was held mis-set-up the internal voice structures.

Closes surge-synthesizer#1554
  • Loading branch information
baconpaul committed Feb 15, 2020
1 parent 50f63fd commit 193b5be
Showing 1 changed file with 71 additions and 7 deletions.
78 changes: 71 additions & 7 deletions src/common/SurgeSynthesizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,37 @@ void SurgeSynthesizer::playNote(char channel, char key, char velocity, char detu

channelState[channel].keyState[key].keystate = velocity;
channelState[channel].keyState[key].lastdetune = detune;

/*
** OK so why is there hold stuff here? This is play not release.
** Well if you release a key with the pedal down it goes into the
** 'release me later' buffer. If you press the key again it stays there
** so even with the key held, you end up releasing it when you pedal.
**
** Or: NoteOn / Pedal On / Note Off / Note On / Pedal Off should leave the note ringing
**
** and right now it doesn't
*/
bool noHold = ! channelState[channel].hold;
if( mpeEnabled )
noHold = noHold && ! channelState[0].hold;

if( ! noHold )
{
for( int s=0; s<2; ++s )
{
for( auto &h : holdbuffer[s] )
{
if( h.first == channel && h.second == key )
{
h.first = -1;
h.second = -1;
}
}
}
}


}

void SurgeSynthesizer::softkillVoice(int s)
Expand Down Expand Up @@ -558,7 +589,9 @@ void SurgeSynthesizer::releaseNote(char channel, char key, char velocity)
if (noHold)
releaseNotePostHoldCheck(s, channel, key, velocity);
else
{
holdbuffer[s].push_back(std::make_pair(channel,key)); // hold pedal is down, add to bufffer
}
}
}

Expand Down Expand Up @@ -905,8 +938,6 @@ float int7ToBipolarFloat(int x)

void SurgeSynthesizer::channelController(char channel, int cc, int value)
{
int channelmask = ((channel == 0) ? 3 : 0) | ((channel == 1) ? 1 : 0) | ((channel == 2) ? 2 : 0);

float fval = (float)value * (1.f / 127.f);
// store all possible NRPN & RPNs in a short array .. just amounts for 128kb or thereabouts
// anyway
Expand Down Expand Up @@ -946,10 +977,35 @@ void SurgeSynthesizer::channelController(char channel, int cc, int value)
case 64:
{
channelState[channel].hold = value > 63; // check hold pedal
if (channelmask & 1)

// OK in single mode, only purge scene 0, but in split or dual purge both, and in chsplit
// pick based on channel
switch(storage.getPatch().scenemode.val.i)
{
case sm_single:
purgeHoldbuffer(storage.getPatch().scene_active.val.i);
break;
case sm_split:
case sm_dual:
purgeHoldbuffer(0);
if (channelmask & 2)
purgeHoldbuffer(1);
break;
case sm_chsplit:
if( mpeEnabled && channel == 0 ) // a control channel message
{
purgeHoldbuffer(0);
purgeHoldbuffer(1);
}
else
{
if( channel < ( (int)( storage.getPatch().splitkey.val.i / 8 ) + 1 ) )
purgeHoldbuffer(0);
else
purgeHoldbuffer(1);
}
break;
}

return;
}

Expand Down Expand Up @@ -1102,13 +1158,21 @@ void SurgeSynthesizer::purgeHoldbuffer(int scene)
{
auto channel = hp.first;
auto key = hp.second;
if (!channelState[0].hold && ! channelState[channel].hold )

if( channel < 0 || key < 0 )
{
releaseNotePostHoldCheck(scene, channel, key, 127);
// std::cout << "Caught tricky double releease condition!" << std::endl;
}
else
{
retainBuffer.push_back(hp);
if (!channelState[0].hold && ! channelState[channel].hold )
{
releaseNotePostHoldCheck(scene, channel, key, 127);
}
else
{
retainBuffer.push_back(hp);
}
}
}
holdbuffer[scene] = retainBuffer;
Expand Down

0 comments on commit 193b5be

Please sign in to comment.