tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_Scene.cpp
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11namespace tracktion { inline namespace engine
12{
13
15 : state (v), edit (sl.edit), sceneList (sl)
16{
17 assert (v.hasType (IDs::SCENE));
18
19 auto um = &edit.getUndoManager();
20 name.referTo (state, IDs::name, um);
21 colour.referTo (state, IDs::colour, um);
22
23 state.addListener (this);
24}
25
27{
28 notifyListenersOfDeletion();
29}
30
31int Scene::getIndex()
32{
33 return sceneList.getScenes().indexOf (this);
34}
35
40
41void Scene::valueTreePropertyChanged (juce::ValueTree& v, const juce::Identifier& i)
42{
43 if (v != state)
44 return;
45
46 if (i == IDs::name || i == IDs::colour)
47 changed();
48}
49
50//==============================================================================
52 : scenesState (scenesState_), edit (e)
53{
54 checkForScenes();
55 scenesState.addListener (this);
56}
57
59{
60 listeners.add (l);
61}
62
64{
65 listeners.remove (l);
66}
67
68void SceneWatcher::checkForScenes()
69{
70 if (scenesState.getNumChildren() == 0)
71 {
72 stopTimer();
73 return;
74 }
75
76 if (! isTimerRunning())
77 startTimerHz (30);
78}
79
80SceneWatcher::RecordingState SceneWatcher::getRecordingState (ClipSlot& slot)
81{
82 auto dest = slot.getInputDestination();
83
84 if (dest && dest->input.isRecording (dest->targetID))
85 {
86 auto epc = dest->input.edit.getTransport().getCurrentPlaybackContext();
87 const auto currentTime = epc ? epc->getUnloopedPosition() : dest->input.edit.getTransport().getPosition();
88
89 if (currentTime < dest->input.getPunchInTime (dest->targetID))
90 return RecordingState::pending;
91 else
92 return RecordingState::recording;
93 }
94 return RecordingState::none;
95}
96
97void SceneWatcher::timerCallback()
98{
99 auto update = [&] (int trackIdx, int slotIdx, LaunchHandle::PlayState p, std::optional<LaunchHandle::QueueState> q, RecordingState r)
100 {
101 auto key = std::pair<int,int> (trackIdx, slotIdx);
102 auto itr = lastStates.find (key);
103
104 if (itr == lastStates.end())
105 {
106 lastStates[key] = { callback, p, q, r };
107 listeners.call ([trackIdx, slotIdx] (Listener& l) { l.slotUpdated (trackIdx, slotIdx); });
108 }
109 else if (itr->second.playState != p || itr->second.queueState != q || itr->second.recordingState != r)
110 {
111 itr->second.lastSeen = callback;
112 itr->second.playState = p;
113 itr->second.queueState = q;
114 itr->second.recordingState = r;
115 listeners.call ([trackIdx, slotIdx] (Listener& l) { l.slotUpdated (trackIdx, slotIdx); });
116 }
117 else
118 {
119 itr->second.lastSeen = callback;
120 }
121 };
122
123 auto trackIdx = 0;
124
125 for (auto at : getAudioTracks (edit))
126 {
127 auto slotIdx = 0;
128
129 for (auto slot : at->getClipSlotList().getClipSlots())
130 {
131 if (auto r = getRecordingState (*slot); r != RecordingState::none)
132 {
133 update (trackIdx, slotIdx, LaunchHandle::PlayState::stopped, {}, r);
134 }
135 else if (auto c = slot->getClip())
136 {
137 if (auto lh = c->getLaunchHandle())
138 {
139 auto p = lh->getPlayingStatus();
140 auto q = lh->getQueuedStatus();
141
142 update (trackIdx, slotIdx, p, q, r);
143 }
144 }
145
146 slotIdx++;
147 }
148
149 trackIdx++;
150 }
151
152 for (auto itr = lastStates.cbegin(); itr != lastStates.cend();)
153 {
154 if (itr->second.lastSeen != callback)
155 {
156 listeners.call ([itr] (Listener& l) { l.slotUpdated (itr->first.first, itr->first.second); });
157 lastStates.erase (itr++);
158 }
159 else
160 {
161 itr++;
162 }
163 }
164
165 callback++;
166}
167
168void SceneWatcher::valueTreeChildAdded (juce::ValueTree& p, juce::ValueTree& c)
169{
170 if (p == scenesState && c.hasType (IDs::SCENE))
171 checkForScenes();
172}
173
174void SceneWatcher::valueTreeChildRemoved (juce::ValueTree& p, juce::ValueTree& c, int)
175{
176 if (p == scenesState && c.hasType (IDs::SCENE))
177 checkForScenes();
178}
179
180
181//==============================================================================
182//==============================================================================
185 state (v),
186 edit (e)
187{
188 assert (parent.hasType (IDs::SCENES));
189 rebuildObjects();
190}
191
193{
194 freeObjects();
195}
196
197//==============================================================================
199{
200 return objects;
201}
202
204{
205 for (int i = size(); i < numScenes; ++i)
206 parent.appendChild (juce::ValueTree (IDs::SCENE), &edit.getUndoManager());
207
208 assert (objects.size() >= numScenes);
209
210 for (auto at : getAudioTracks (edit))
211 at->getClipSlotList().ensureNumberOfSlots (objects.size());
212}
213
215{
216 parent.addChild (juce::ValueTree (IDs::SCENE), idx, &edit.getUndoManager());
217
218 for (auto at : getAudioTracks (edit))
219 at->getClipSlotList().insertSlot (idx);
220
221 return getScenes()[idx];
222}
223
225{
226 assert (&scene.edit == &edit);
227 const int index = parent.indexOf (scene.state);
228 parent.removeChild (index, &edit.getUndoManager());
229
230 for (auto at : getAudioTracks (edit))
231 {
232 auto& csl = at->getClipSlotList();
233 auto cs = csl.getClipSlots()[index];
234 assert (cs != nullptr);
235
236 if (auto clip = cs->getClip())
237 clip->removeFromParent();
238
239 csl.deleteSlot (*csl.getClipSlots()[index]);
240 }
241}
242
243//==============================================================================
244bool SceneList::isSuitableType (const juce::ValueTree& v) const
245{
246 return v.hasType (IDs::SCENE);
247}
248
249Scene* SceneList::createNewObject (const juce::ValueTree& v)
250{
251 return new Scene (v, *this);
252}
253
254void SceneList::deleteObject (Scene* scene)
255{
256 delete scene;
257}
258
259void SceneList::newObjectAdded (Scene*)
260{
261}
262
263void SceneList::objectRemoved (Scene*)
264{
265}
266
267void SceneList::objectOrderChanged()
268{
269}
270
271
272}} // namespace tracktion { inline namespace engine
assert
T cbegin(T... args)
int indexOf(ParameterType elementToLookFor) const
void referTo(ValueTree &tree, const Identifier &property, UndoManager *um)
void stopTimer() noexcept
void startTimerHz(int timerFrequencyHz) noexcept
bool isTimerRunning() const noexcept
int getNumChildren() const noexcept
void addListener(Listener *listener)
The Tracktion Edit class!
juce::UndoManager & getUndoManager() noexcept
Returns the juce::UndoManager used for this Edit.
Represents the Scenes in an Edit.
void deleteScene(Scene &)
Deletes a specific Scene.
juce::Array< Scene * > getScenes()
Returns the Scenes in the Edit.
void ensureNumberOfScenes(int numScenes)
Adds Scenes to ensure numScenes are preset in the list.
Scene * insertScene(int index)
Inserts a new scene with the given index.
Edit & edit
The Edit this SceneList belongs to.
~SceneList() override
Destructor.
SceneList(const juce::ValueTree &, Edit &)
Creates a SceneList for an Edit with a given state.
void removeListener(Listener *)
Removes a previously added Listener.
SceneWatcher(const juce::ValueTree &scenesState, Edit &)
Creates a SceneWatcher.
void addListener(Listener *)
Adds a Listener.
A Scene is a collection of ClipSlots across tracks.
~Scene() override
Destructor.
Scene(const juce::ValueTree &, SceneList &)
Creates a Scene for a given state.
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
virtual void changed()
This should be called to send a change notification to any SelectableListeners that are registered wi...
T end(T... args)
T erase(T... args)
T find(T... args)
T is_pointer_v
#define TRANS(stringLiteral)
juce::Array< AudioTrack * > getAudioTracks(const Edit &edit)
Returns all the AudioTracks in an Edit.