@@ -93,6 +93,7 @@ RipplerXAudioProcessor::RipplerXAudioProcessor()
9393 std::make_unique<juce::AudioParameterInt>(" bend_range" , " PitchBend Range" , 1 , 24 , 2 ),
9494 std::make_unique<juce::AudioParameterBool>(" stereoizer" , " Stereoizer" , true ),
9595 std::make_unique<juce::AudioParameterBool>(" reuse_voices" , " Reuse Voices" , false ),
96+ std::make_unique<juce::AudioParameterBool>(" fadeout_repeats" , " Fadeout Repeated Notes" , false ),
9697 }),
9798 mtsClientPtr{nullptr }
9899#endif
@@ -383,19 +384,24 @@ bool RipplerXAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts)
383384// Sort the array by release time if the note is not pressed, otherwise sort by press time.
384385// The release time sort should take priority over press time sort.
385386int RipplerXAudioProcessor::pickVoice (int note) {
386- int pick = 0 ;
387387 bool reuseVoices = (bool )params.getRawParameterValue (" reuse_voices" )->load ();
388388
389+ // Priority 1: note already playing in a voice
390+ if (reuseVoices) {
391+ for (int i = 0 ; i < polyphony; ++i) {
392+ if (voices[i]->note == note) {
393+ return i;
394+ }
395+ }
396+ }
397+
398+ int pick = 0 ;
389399 for (int i = 1 ; i < polyphony; ++i) {
390400 const auto & v1 = voices[i];
391401 const auto & v2 = voices[pick];
392402
393- if (v1->note == note && reuseVoices) {
394- pick = i;
395- break ;
396- }
397403 // Priority 2: Released voices come before pressed ones
398- else if (!v1->isPressed && v2->isPressed ) {
404+ if (!v1->isPressed && v2->isPressed ) {
399405 pick = i;
400406 }
401407 else if (v1->isPressed && !v2->isPressed ) {
@@ -419,16 +425,19 @@ void RipplerXAudioProcessor::onNote(MIDIMsg msg)
419425 auto srate = getSampleRate ();
420426
421427 int nvoice = pickVoice (msg.note );
422- DBG (" " << nvoice);
423428 Voice& voice = *voices[nvoice];
424429
430+ bool reuse_voices = (bool )params.getRawParameterValue (" reuse_voices" )->load ();
431+ bool fadeout_repeats = (bool )params.getRawParameterValue (" fadeout_repeats" )->load ();
432+ bool skip_fadeout = reuse_voices && !fadeout_repeats && voice.note == msg.note ;
433+
425434 auto mallet_type = (MalletType)params.getRawParameterValue (" mallet_type" )->load ();
426435 auto mallet_stiff = (double )params.getRawParameterValue (" mallet_stiff" )->load ();
427436 auto mallet_ktrack = (double )params.getRawParameterValue (" mallet_ktrack" )->load ();
428437 auto vel_mallet_stiff = (double )params.getRawParameterValue (" vel_mallet_stiff" )->load ();
429438 auto malletFreq = fmax (100.0 , fmin (5000.0 , exp (log (mallet_stiff) + msg.vel / 127.0 * vel_mallet_stiff * 2.0 * (log (5000.0 ) - log (100.0 )))));
430439
431- voice.trigger (srate, msg.note , msg.vel / 127.0 , mallet_type, malletFreq, mallet_ktrack, mtsClientPtr);
440+ voice.trigger (srate, msg.note , msg.vel / 127.0 , mallet_type, malletFreq, mallet_ktrack, skip_fadeout, mtsClientPtr);
432441}
433442
434443void RipplerXAudioProcessor::offNote (MIDIMsg msg)
0 commit comments