Skip to content

Commit 8567288

Browse files
committed
#34 Aggregared keys state to track coupled divisions.
1 parent 3eebdd8 commit 8567288

5 files changed

Lines changed: 79 additions & 10 deletions

File tree

Source/aeolus/division.cpp

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

572592
void 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,14 +622,28 @@ 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+
608647
bool Division::triggerVoicesForStop(int stopIndex, int note)
609648
{
610649
jassert(isPositiveAndBelow(stopIndex, _stops.size()));

Source/aeolus/division.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ class Division
8585
juce::String getName() const { return _name; }
8686
juce::String getMnemonic() const { return _mnemonic; }
8787

88+
/**
89+
* Remove all the links between the divisions.
90+
*/
91+
void clearLinkedDivisions();
92+
8893
/**
8994
* Populate linked divisions from the division names.
9095
* This method must be called by the engine when all the divisions
@@ -164,6 +169,12 @@ class Division
164169

165170
private:
166171

172+
/**
173+
* This will construct the keys aggregated state from the division's keys state
174+
* and all the coupled from divisions.
175+
*/
176+
void updateAggregatedKeysState();
177+
167178
bool triggerVoicesForStop(int stopIndex, int note);
168179

169180
bool isAlreadyVoiced(int stopIndex, int node);
@@ -176,6 +187,7 @@ class Division
176187
/// List of linked divisions names.
177188
juce::StringArray _linkedDivisionNames;
178189
std::vector<Link> _linkedDivisions;
190+
std::vector<Division*> _linkedFromDivisions;
179191

180192
bool _hasSwell; ///< Whetehr this division has a swell control.
181193
bool _hasTremulant; ///< Whether this division has a remulant control.
@@ -205,6 +217,7 @@ class Division
205217
List<Voice> _activeVoices; ///< Active voices on this division.
206218

207219
std::bitset<TOTAL_NOTES> _keysState; ///< MIDI keys state 1 = on, 0 = off.
220+
std::bitset<TOTAL_NOTES> _aggregatedKeysState; ///< MIDI keys state aggregated from the coupled divisions.
208221

209222
/// Tells whether this division has been triggered.
210223
/// This is used to avoid a division to be triggered multiple

Source/aeolus/engine.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,18 +732,26 @@ void Engine::populateDivisions()
732732
loadDivisionsFromConfig(stream);
733733
}
734734

735+
// Remove all the links if any.
736+
for (auto* division : _divisions) {
737+
division->clearLinkedDivisions();
738+
}
739+
740+
735741
// Update division links after they've been loaded.
736742
for (auto* division : _divisions) {
737743
division->populateLinkedDivisions();
738744
}
745+
746+
// @todo Do we want the divisions to be reordered by the couplings?
739747
}
740748

741749
// @internal Helper to populate key switches from a single number or a list
742750
static void populateKeySwitchesVector(std::vector<int>& switches, const var& v)
743751
{
744752
if (v.isVoid())
745753
return;
746-
754+
747755
switches.clear();
748756

749757
if (v.isInt()) {

Source/aeolus/voice.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ bool Voice::isForNote(int note) const noexcept
155155
return false;
156156
}
157157

158+
int Voice::getNote() const
159+
{
160+
if (_state.pipewave != nullptr)
161+
return _state.pipewave->getNote();
162+
163+
return -1;
164+
}
165+
158166
void Voice::resetAndReturnToPool()
159167
{
160168
_engine.getVoicePool().resetAndReturnToPool(this);

Source/aeolus/voice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class Voice : public ListItem<Voice>
5050
bool isOver() const noexcept;
5151
bool isActive() const noexcept;
5252
bool isForNote(int note) const noexcept;
53+
int getNote() const;
5354

5455
void setStopIndex(int idx) noexcept { _stopIndex = idx; }
5556
int stopIndex() const noexcept { return _stopIndex; }

0 commit comments

Comments
 (0)