Skip to content

Commit c2022c1

Browse files
committed
[scenario] Implement an exclusive mode across scenario components
1 parent a883b26 commit c2022c1

File tree

4 files changed

+144
-14
lines changed

4 files changed

+144
-14
lines changed

src/ossia/editor/scenario/detail/scenario_execution.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ void scenario::run_interval(
219219
}
220220
}
221221

222+
void scenario::stop_interval(time_interval& itv)
223+
{
224+
itv.stop();
225+
226+
m_runningIntervals.erase(&itv);
227+
m_itv_end_map.erase(&itv);
228+
}
229+
222230
void scenario::state_impl(const ossia::token_request& tk)
223231
{
224232
node->request(tk);
@@ -272,6 +280,7 @@ void scenario::state_impl(const ossia::token_request& tk)
272280
});
273281
}
274282

283+
// Manual request (user clicked on the trigger)
275284
if(n->trigger_request)
276285
{
277286
if(m_waitingNodes.find(n) != m_waitingNodes.end())
@@ -316,7 +325,8 @@ void scenario::state_impl(const ossia::token_request& tk)
316325

317326
m_pendingEvents.clear();
318327

319-
// Check intervals that have been quantized
328+
// Check intervals that have been quantized through manual interaction
329+
// (the little play / stop buttons)
320330
for(auto it = m_itv_to_start.begin(); it != m_itv_to_start.end();)
321331
{
322332
auto [itv, ratio] = *it;
@@ -327,6 +337,7 @@ void scenario::state_impl(const ossia::token_request& tk)
327337
mark_end_discontinuous{}(*itv);
328338
itv->stop();
329339
}
340+
itv->set_parent_speed(tk.speed);
330341
itv->start();
331342
// itv->tick_current(*date, tk);
332343
// mark_start_discontinuous{}(*itv);
@@ -337,7 +348,20 @@ void scenario::state_impl(const ossia::token_request& tk)
337348
auto& end_ev = itv->get_end_event();
338349
end_ev.set_status(ossia::time_event::status::NONE);
339350

340-
it = m_itv_to_start.erase(it);
351+
if(m_exclusive)
352+
{
353+
for(auto& running : m_runningIntervals)
354+
{
355+
running->stop();
356+
}
357+
m_runningIntervals.clear();
358+
m_itv_to_start.clear();
359+
break;
360+
}
361+
else
362+
{
363+
it = m_itv_to_start.erase(it);
364+
}
341365
}
342366
else
343367
{

src/ossia/editor/scenario/detail/scenario_sync_execution.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ sync_status scenario::trigger_sync(
167167
else
168168
sync.m_status = time_sync::status::DONE_TRIGGERED;
169169

170+
if(m_exclusive)
171+
reset_all_components_except(sync);
172+
170173
return sync_status::DONE;
171174
}
172175

src/ossia/editor/scenario/scenario.cpp

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,16 @@ void scenario::reset_subgraph(
308308
}
309309
}
310310

311+
void scenario::set_exclusive(bool excl) noexcept
312+
{
313+
m_exclusive = excl;
314+
}
315+
316+
bool scenario::exclusive(bool excl) const noexcept
317+
{
318+
return m_exclusive;
319+
}
320+
311321
void scenario::mute_impl(bool m)
312322
{
313323
for(auto& itv : get_time_intervals())
@@ -320,15 +330,105 @@ void scenario::mute_impl(bool m)
320330
}
321331
}
322332

323-
void scenario::start_interval(time_interval& itv, double ratio)
333+
void scenario::request_start_interval(time_interval& itv, double ratio)
324334
{
325335
m_itv_to_start.emplace_back(quantized_interval{&itv, ratio});
326336
}
327-
void scenario::stop_interval(time_interval& itv, double ratio)
337+
void scenario::request_stop_interval(time_interval& itv, double ratio)
328338
{
329339
m_itv_to_stop.emplace_back(quantized_interval{&itv, ratio});
330340
}
331341

342+
void scenario::reset_all_components_except(ossia::time_sync& n)
343+
{
344+
// For all nodes not in the component of n:
345+
// If:
346+
// - It is executing
347+
// - It has a previous interval executing
348+
// - It has a next interval executing
349+
// Then:
350+
// reset_component(n)
351+
352+
sync_set nodes_to_process;
353+
// 1. Compute the set of nodes to process
354+
{
355+
auto& stack = m_component_visit_stack;
356+
auto& cache = m_component_visit_cache;
357+
358+
stack.clear();
359+
cache.clear();
360+
361+
cache.insert(&n);
362+
stack.push_back(&n);
363+
364+
while(!stack.empty())
365+
{
366+
auto n = stack.back();
367+
stack.pop_back();
368+
369+
for(auto& ev : n->get_time_events())
370+
{
371+
for(auto& cst : ev->previous_time_intervals())
372+
{
373+
auto& pn = cst->get_start_event().get_time_sync();
374+
if(cache.find(&pn) == cache.end())
375+
{
376+
cache.insert(&pn);
377+
stack.push_back(&pn);
378+
}
379+
}
380+
381+
for(auto& cst : ev->next_time_intervals())
382+
{
383+
auto& pn = cst->get_end_event().get_time_sync();
384+
if(cache.find(&pn) == cache.end())
385+
{
386+
cache.insert(&pn);
387+
stack.push_back(&pn);
388+
}
389+
}
390+
}
391+
}
392+
393+
// At this point, "cache" contains the entire component of n
394+
for(auto& node : m_nodes)
395+
if(!cache.contains(node.get()))
396+
nodes_to_process.insert(node.get());
397+
398+
// Now nodes_to_process contains all the nodes that are not in the component of n
399+
}
400+
401+
// 2. Apply the algorithm mentioned above:
402+
for(auto& n : nodes_to_process)
403+
{
404+
if(n->is_being_triggered())
405+
goto disable_component;
406+
407+
for(auto& ev : n->get_time_events())
408+
{
409+
for(auto& cst : ev->previous_time_intervals())
410+
{
411+
if(cst->running())
412+
{
413+
goto disable_component;
414+
}
415+
}
416+
for(auto& cst : ev->next_time_intervals())
417+
{
418+
if(cst->running())
419+
{
420+
goto disable_component;
421+
}
422+
}
423+
}
424+
425+
continue;
426+
427+
disable_component:
428+
reset_component(*n);
429+
}
430+
}
431+
332432
void scenario::reset_component(ossia::time_sync& n)
333433
{
334434
auto& stack = m_component_visit_stack;
@@ -340,12 +440,6 @@ void scenario::reset_component(ossia::time_sync& n)
340440
cache.insert(&n);
341441
stack.push_back(&n);
342442

343-
auto disable_itv = [&](ossia::time_interval& itv) {
344-
itv.stop();
345-
m_runningIntervals.erase(&itv);
346-
m_itv_end_map.erase(&itv);
347-
};
348-
349443
while(!stack.empty())
350444
{
351445
auto n = stack.back();
@@ -357,7 +451,7 @@ void scenario::reset_component(ossia::time_sync& n)
357451
{
358452
for(auto& cst : ev->previous_time_intervals())
359453
{
360-
disable_itv(*cst);
454+
stop_interval(*cst);
361455

362456
auto& pn = cst->get_start_event().get_time_sync();
363457
if(cache.find(&pn) == cache.end())
@@ -369,7 +463,7 @@ void scenario::reset_component(ossia::time_sync& n)
369463

370464
for(auto& cst : ev->next_time_intervals())
371465
{
372-
disable_itv(*cst);
466+
stop_interval(*cst);
373467

374468
auto& pn = cst->get_end_event().get_time_sync();
375469
if(cache.find(&pn) == cache.end())

src/ossia/editor/scenario/scenario.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,13 @@ class OSSIA_EXPORT scenario final : public looping_process<scenario>
136136
* e.g. this is used when pressing the "play" button on a random interval in
137137
* score.
138138
*/
139-
void start_interval(ossia::time_interval&, double ratio = 0.0);
139+
void request_start_interval(ossia::time_interval&, double ratio = 0.0);
140140
/*! Used to stop an interval,
141141
* disregarding all the rules of the scenario.
142142
* e.g. this is used when pressing the "stop" button on a random interval in
143143
* score.
144144
*/
145-
void stop_interval(ossia::time_interval&, double ratio = 0.0);
145+
void request_stop_interval(ossia::time_interval&, double ratio = 0.0);
146146

147147
small_sync_vec get_roots() const noexcept;
148148

@@ -152,7 +152,11 @@ class OSSIA_EXPORT scenario final : public looping_process<scenario>
152152

153153
ossia::time_value last_date() const noexcept { return m_last_date; }
154154

155+
void set_exclusive(bool excl) noexcept;
156+
bool exclusive(bool excl) const noexcept;
157+
155158
private:
159+
void stop_all_intervals();
156160
ossia::time_value m_last_date{ossia::Infinite};
157161

158162
ptr_container<time_interval> m_intervals;
@@ -172,6 +176,9 @@ class OSSIA_EXPORT scenario final : public looping_process<scenario>
172176

173177
sync_set m_component_visit_cache;
174178
std::vector<ossia::time_sync*> m_component_visit_stack;
179+
180+
bool m_exclusive{};
181+
175182
// Used to start intervals off-time
176183
struct quantized_interval
177184
{
@@ -217,6 +224,8 @@ class OSSIA_EXPORT scenario final : public looping_process<scenario>
217224
ossia::time_interval& interval, const ossia::token_request& tk,
218225
const time_value& tick_ms, ossia::time_value tick, ossia::time_value offset);
219226

227+
void stop_interval(ossia::time_interval& itv);
220228
void reset_component(ossia::time_sync& n);
229+
void reset_all_components_except(ossia::time_sync& n);
221230
};
222231
}

0 commit comments

Comments
 (0)