andrewm@0
|
1 /*
|
andrewm@0
|
2 TouchKeys: multi-touch musical keyboard control software
|
andrewm@0
|
3 Copyright (c) 2013 Andrew McPherson
|
andrewm@0
|
4
|
andrewm@0
|
5 This program is free software: you can redistribute it and/or modify
|
andrewm@0
|
6 it under the terms of the GNU General Public License as published by
|
andrewm@0
|
7 the Free Software Foundation, either version 3 of the License, or
|
andrewm@0
|
8 (at your option) any later version.
|
andrewm@0
|
9
|
andrewm@0
|
10 This program is distributed in the hope that it will be useful,
|
andrewm@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@0
|
13 GNU General Public License for more details.
|
andrewm@0
|
14
|
andrewm@0
|
15 You should have received a copy of the GNU General Public License
|
andrewm@0
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@0
|
17
|
andrewm@0
|
18 =====================================================================
|
andrewm@0
|
19
|
andrewm@0
|
20 Trigger.h: interface for objects to notify one another that new data
|
andrewm@0
|
21 has arrived. TriggerSource can send triggers to any object inheriting
|
andrewm@0
|
22 from TriggerDestination. Methods of keeping sources and destinations
|
andrewm@0
|
23 in sync are included in each class.
|
andrewm@0
|
24 */
|
andrewm@0
|
25
|
andrewm@0
|
26 #ifndef KEYCONTROL_TRIGGER_H
|
andrewm@0
|
27 #define KEYCONTROL_TRIGGER_H
|
andrewm@0
|
28
|
andrewm@0
|
29 #include <iostream>
|
andrewm@0
|
30 #include <set>
|
andrewm@0
|
31 #include "../JuceLibraryCode/JuceHeader.h"
|
andrewm@0
|
32 #include "Types.h"
|
andrewm@0
|
33
|
andrewm@0
|
34 class TriggerDestination;
|
andrewm@0
|
35
|
andrewm@0
|
36 /*
|
andrewm@0
|
37 * TriggerSource
|
andrewm@0
|
38 *
|
andrewm@0
|
39 * Provides a set of routines for an object that sends triggers with an associated timestamp. All Node
|
andrewm@0
|
40 * objects inherit from Trigger, but other objects may use these routines as well.
|
andrewm@0
|
41 */
|
andrewm@0
|
42
|
andrewm@0
|
43 class TriggerSource {
|
andrewm@0
|
44 friend class TriggerDestination;
|
andrewm@0
|
45 protected:
|
andrewm@0
|
46 // Send a trigger event out to all our registered listeners. The type of the accompanying
|
andrewm@0
|
47 // data will be set by the template of the subclass.
|
andrewm@0
|
48 void sendTrigger(timestamp_type timestamp);
|
andrewm@0
|
49
|
andrewm@0
|
50 public:
|
andrewm@0
|
51 // ***** Constructor *****
|
andrewm@0
|
52
|
andrewm@0
|
53 TriggerSource() {} // No instantiating this class directly!
|
andrewm@0
|
54
|
andrewm@0
|
55 // ***** Destructor *****
|
andrewm@0
|
56
|
andrewm@0
|
57 ~TriggerSource() { clearTriggerDestinations(); }
|
andrewm@0
|
58
|
andrewm@0
|
59 // ***** Connection Management *****
|
andrewm@0
|
60
|
andrewm@0
|
61 bool hasTriggerDestinations() { return triggerDestinations_.size() > 0; }
|
andrewm@0
|
62
|
andrewm@0
|
63 private:
|
andrewm@0
|
64 // For internal use or use by friend class NodeBase only
|
andrewm@0
|
65
|
andrewm@0
|
66 // These methods manage the list of objects to whom the triggers should be sent. All objects
|
andrewm@0
|
67 // will inherit from the Triggerable base class. These shouldn't be called by the user directly;
|
andrewm@0
|
68 // rather, they're called by Triggerable when it registers itself.
|
andrewm@0
|
69
|
andrewm@0
|
70 void addTriggerDestination(TriggerDestination* dest);
|
andrewm@0
|
71 void removeTriggerDestination(TriggerDestination* dest);
|
andrewm@0
|
72 void clearTriggerDestinations();
|
andrewm@0
|
73
|
andrewm@0
|
74 // When sources are added or removed, they are first stored in separate locations to be updated
|
andrewm@0
|
75 // prior to each new call of sendTrigger(). This way, destinations which are updated from functions
|
andrewm@0
|
76 // called from sendTrigger() do not render the set inconsistent in the middle.
|
andrewm@0
|
77 void processAddRemoveQueue();
|
andrewm@0
|
78
|
andrewm@0
|
79 private:
|
andrewm@0
|
80 std::set<TriggerDestination*> triggerDestinations_;
|
andrewm@0
|
81 std::set<TriggerDestination*> triggersToAdd_;
|
andrewm@0
|
82 std::set<TriggerDestination*> triggersToRemove_;
|
andrewm@0
|
83 bool triggerDestinationsModified_;
|
andrewm@0
|
84 CriticalSection triggerSourceMutex_;
|
andrewm@0
|
85 };
|
andrewm@0
|
86
|
andrewm@0
|
87 /*
|
andrewm@0
|
88 * TriggerDestination
|
andrewm@0
|
89 *
|
andrewm@0
|
90 * This class accepts a Trigger event. Designed to be inherited by more complex objects.
|
andrewm@0
|
91 */
|
andrewm@0
|
92
|
andrewm@0
|
93 class TriggerDestination {
|
andrewm@0
|
94 friend class TriggerSource;
|
andrewm@0
|
95 public:
|
andrewm@0
|
96 // ***** Constructors *****
|
andrewm@0
|
97
|
andrewm@0
|
98 TriggerDestination() {}
|
andrewm@0
|
99 TriggerDestination(TriggerDestination const& obj) : registeredTriggerSources_(obj.registeredTriggerSources_) {}
|
andrewm@0
|
100
|
andrewm@0
|
101 // This defines what we actually do when a trigger is received. It should be implemented
|
andrewm@0
|
102 // by the subclass.
|
andrewm@0
|
103 virtual void triggerReceived(TriggerSource* who, timestamp_type timestamp) { /*std::cout << " received this = " << this << " who = " << who << std::endl;*/ }
|
andrewm@0
|
104
|
andrewm@0
|
105 // These methods register and unregister sources of triggers.
|
andrewm@0
|
106
|
andrewm@0
|
107 void registerForTrigger(TriggerSource* src) {
|
andrewm@0
|
108 //std::cout<<"registerForTrigger: this = " << this << " src = " << src << std::endl;
|
andrewm@0
|
109
|
andrewm@0
|
110 if(src == 0 || (void*)src == (void*)this)
|
andrewm@0
|
111 return;
|
andrewm@0
|
112 ScopedLock sl(triggerDestMutex_);
|
andrewm@0
|
113 src->addTriggerDestination(this);
|
andrewm@0
|
114 registeredTriggerSources_.insert(src);
|
andrewm@0
|
115 }
|
andrewm@0
|
116
|
andrewm@0
|
117 void unregisterForTrigger(TriggerSource* src) {
|
andrewm@0
|
118 if(src == 0 || (void*)src == (void*)this)
|
andrewm@0
|
119 return;
|
andrewm@0
|
120 ScopedLock sl(triggerDestMutex_);
|
andrewm@0
|
121 src->removeTriggerDestination(this);
|
andrewm@0
|
122 registeredTriggerSources_.erase(src);
|
andrewm@0
|
123 }
|
andrewm@0
|
124
|
andrewm@0
|
125 void clearTriggers() {
|
andrewm@0
|
126 ScopedLock sl(triggerDestMutex_);
|
andrewm@0
|
127 std::set<TriggerSource*>::iterator it;
|
andrewm@0
|
128 for(it = registeredTriggerSources_.begin(); it != registeredTriggerSources_.end(); it++)
|
andrewm@0
|
129 (*it)->removeTriggerDestination(this);
|
andrewm@0
|
130 registeredTriggerSources_.clear();
|
andrewm@0
|
131 }
|
andrewm@0
|
132
|
andrewm@0
|
133 protected:
|
andrewm@0
|
134 // This method is called by a TriggerBase object when it is deleted, so that we know not
|
andrewm@0
|
135 // to contact it later when this object is deleted. This is different than unregisterForTrigger()
|
andrewm@0
|
136 // because it only removes the reference and does not call the TriggerBase object (which would create
|
andrewm@0
|
137 // an infinite loop).
|
andrewm@0
|
138
|
andrewm@0
|
139 void triggerSourceDeleted(TriggerSource* src) { registeredTriggerSources_.erase(src); }
|
andrewm@0
|
140
|
andrewm@0
|
141 public:
|
andrewm@0
|
142 // ***** Destructor *****
|
andrewm@0
|
143 //
|
andrewm@0
|
144 // Remove all trigger sources before this object goes away
|
andrewm@0
|
145
|
andrewm@0
|
146 virtual ~TriggerDestination() { clearTriggers(); }
|
andrewm@0
|
147
|
andrewm@0
|
148 private:
|
andrewm@0
|
149 // Keep an internal registry of who we've asked to send us triggers. It's important to keep
|
andrewm@0
|
150 // a list of these so that when this object is destroyed, all triggers are automatically unregistered.
|
andrewm@0
|
151 std::set<TriggerSource*> registeredTriggerSources_;
|
andrewm@0
|
152 CriticalSection triggerDestMutex_;
|
andrewm@0
|
153 };
|
andrewm@0
|
154
|
andrewm@0
|
155
|
andrewm@0
|
156
|
andrewm@0
|
157 #endif /* KEYCONTROL_TRIGGER_H */ |