@@ -181,14 +181,19 @@ void Division::setPersistentState(const juce::var& v)
181181 }
182182}
183183
184- void Division::populateLinkedDivisions ()
184+ void Division::clearLinkedDivisions ()
185185{
186186 _linkedDivisions.clear ();
187+ _linkedFromDivisions.clear ();
188+ }
187189
190+ void Division::populateLinkedDivisions ()
191+ {
188192 for (const auto & name : _linkedDivisionNames) {
189193 if (auto * division = _engine.getDivisionByName (name)) {
190- Link link{division, false };
194+ Link link{ division, false };
191195 _linkedDivisions.push_back (link);
196+ division->_linkedFromDivisions .push_back (this );
192197 }
193198 }
194199}
@@ -358,7 +363,10 @@ void Division::noteOn(int note, int midiChannel)
358363 for (int stopIndex = 0 ; stopIndex < (int )_stops.size (); ++stopIndex)
359364 triggerVoicesForStop (stopIndex, note);
360365
361- _keysState.set (note);
366+ if (midiChannel != 0 ) {
367+ // Update keys state only when triggered by the assigned MIDI channel
368+ _keysState.set (note);
369+ }
362370
363371 // Forward to the linked divisions
364372 for (auto & link : _linkedDivisions) {
@@ -387,7 +395,10 @@ void Division::noteOff(int note, int midiChannel)
387395 voice = voice->next ();
388396 }
389397
390- _keysState.reset (note);
398+ if (midiChannel != 0 ) {
399+ // Update keys state only when triggered by the assigned MIDI channel.
400+ _keysState.reset (note);
401+ }
391402
392403 // Forward to the linked divisions
393404 for (auto & link : _linkedDivisions) {
@@ -438,6 +449,7 @@ bool Division::process(AudioBuffer<float>& targetBuffer, AudioBuffer<float>& voi
438449 jassert (targetBuffer.getNumSamples () == SUB_FRAME_LENGTH);
439450 jassert (voiceBuffer.getNumSamples () == SUB_FRAME_LENGTH);
440451
452+ updateAggregatedKeysState ();
441453 releaseVoicesOfDisabledStops ();
442454 triggerVoicesOfEnabledStops ();
443455
@@ -554,28 +566,38 @@ void Division::releaseVoicesOfDisabledStops()
554566 auto * voice = _activeVoices.first ();
555567
556568 while (voice != nullptr ) {
569+ bool shouldRelease{ false };
570+
557571 if (voice->isActive ()) {
558572 const int stopIndex = voice->stopIndex ();
559573
560574 if (isPositiveAndBelow (stopIndex, _stops.size ())) {
561575 const auto & stop = _stops[stopIndex];
562576
563577 if (!stop.isEnabled ())
564- voice->release ();
578+ shouldRelease = true ;
579+
580+ if (voice->getNote () >= 0 && !_aggregatedKeysState[voice->getNote ()])
581+ shouldRelease = true ;
565582 }
566583 }
567584
585+ if (shouldRelease)
586+ voice->release ();
587+
568588 voice = voice->next ();
569589 }
570590}
571591
572592void Division::triggerVoicesOfEnabledStops ()
573593{
574- if (_keysState .none ()) {
594+ if (_aggregatedKeysState .none ()) {
575595 // No keys are pressed
576596 return ;
577597 }
578598
599+ std::bitset<TOTAL_NOTES> missingNotes{ _aggregatedKeysState };
600+
579601 for (int stopIndex = 0 ; stopIndex < _stops.size (); ++stopIndex) {
580602 auto & stop = _stops[stopIndex];
581603
@@ -587,8 +609,11 @@ void Division::triggerVoicesOfEnabledStops()
587609 auto * voice = _activeVoices.first ();
588610
589611 while (voice != nullptr ) {
590- if (voice->stopIndex () == stopIndex) {
612+ const int voiceNote{ voice->getNote () };
613+
614+ if (voice->stopIndex () == stopIndex && voiceNote >= 0 && _aggregatedKeysState[voiceNote]) {
591615 hasVoices = true ;
616+ missingNotes[voiceNote] = 0 ;
592617 break ;
593618 }
594619
@@ -597,18 +622,35 @@ void Division::triggerVoicesOfEnabledStops()
597622
598623 // Trigger voices for enabled stops
599624 if (!hasVoices) {
600- for (int note = 0 ; note < _keysState .size (); ++note) {
601- if (_keysState [note])
625+ for (int note = 0 ; note < missingNotes .size (); ++note) {
626+ if (missingNotes [note])
602627 triggerVoicesForStop (stopIndex, note);
603628 }
604629 }
605630 }
606631}
607632
633+ void Division::updateAggregatedKeysState ()
634+ {
635+ _aggregatedKeysState = _keysState;
636+
637+ for (const auto * division : _linkedFromDivisions) {
638+ for (const auto & link : division->_linkedDivisions ) {
639+ if (link.division == this && link.enabled ) {
640+ _aggregatedKeysState |= division->_aggregatedKeysState ;
641+ break ;
642+ }
643+ }
644+ }
645+ }
646+
608647bool Division::triggerVoicesForStop (int stopIndex, int note)
609648{
610649 jassert (isPositiveAndBelow (stopIndex, _stops.size ()));
611650
651+ if (isAlreadyVoiced (stopIndex, note))
652+ return true ;
653+
612654 const auto & stop = _stops[stopIndex];
613655
614656 if (!stop.isEnabled ())
@@ -640,4 +682,19 @@ bool Division::triggerVoicesForStop(int stopIndex, int note)
640682 return voiceTriggered;
641683}
642684
685+ bool Division::isAlreadyVoiced (int stopIndex, int note)
686+ {
687+ auto * voice = _activeVoices.first ();
688+
689+ while (voice != nullptr ) {
690+ if (voice->isActive () && voice->stopIndex () == stopIndex && voice->isForNote (note)) {
691+ return true ;
692+ }
693+
694+ voice = voice->next ();
695+ }
696+
697+ return false ;
698+ }
699+
643700AEOLUS_NAMESPACE_END
0 commit comments