Skip to content

Commit

Permalink
[scenario] Implement an exclusive mode across scenario components
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed May 25, 2023
1 parent a883b26 commit c2022c1
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 14 deletions.
28 changes: 26 additions & 2 deletions src/ossia/editor/scenario/detail/scenario_execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ void scenario::run_interval(
}
}

void scenario::stop_interval(time_interval& itv)
{
itv.stop();

m_runningIntervals.erase(&itv);
m_itv_end_map.erase(&itv);
}

void scenario::state_impl(const ossia::token_request& tk)
{
node->request(tk);
Expand Down Expand Up @@ -272,6 +280,7 @@ void scenario::state_impl(const ossia::token_request& tk)
});
}

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

m_pendingEvents.clear();

// Check intervals that have been quantized
// Check intervals that have been quantized through manual interaction
// (the little play / stop buttons)
for(auto it = m_itv_to_start.begin(); it != m_itv_to_start.end();)
{
auto [itv, ratio] = *it;
Expand All @@ -327,6 +337,7 @@ void scenario::state_impl(const ossia::token_request& tk)
mark_end_discontinuous{}(*itv);
itv->stop();
}
itv->set_parent_speed(tk.speed);
itv->start();
// itv->tick_current(*date, tk);
// mark_start_discontinuous{}(*itv);
Expand All @@ -337,7 +348,20 @@ void scenario::state_impl(const ossia::token_request& tk)
auto& end_ev = itv->get_end_event();
end_ev.set_status(ossia::time_event::status::NONE);

it = m_itv_to_start.erase(it);
if(m_exclusive)
{
for(auto& running : m_runningIntervals)
{
running->stop();
}
m_runningIntervals.clear();
m_itv_to_start.clear();
break;
}
else
{
it = m_itv_to_start.erase(it);
}
}
else
{
Expand Down
3 changes: 3 additions & 0 deletions src/ossia/editor/scenario/detail/scenario_sync_execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ sync_status scenario::trigger_sync(
else
sync.m_status = time_sync::status::DONE_TRIGGERED;

if(m_exclusive)
reset_all_components_except(sync);

return sync_status::DONE;
}

Expand Down
114 changes: 104 additions & 10 deletions src/ossia/editor/scenario/scenario.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,16 @@ void scenario::reset_subgraph(
}
}

void scenario::set_exclusive(bool excl) noexcept
{
m_exclusive = excl;
}

bool scenario::exclusive(bool excl) const noexcept
{
return m_exclusive;
}

void scenario::mute_impl(bool m)
{
for(auto& itv : get_time_intervals())
Expand All @@ -320,15 +330,105 @@ void scenario::mute_impl(bool m)
}
}

void scenario::start_interval(time_interval& itv, double ratio)
void scenario::request_start_interval(time_interval& itv, double ratio)
{
m_itv_to_start.emplace_back(quantized_interval{&itv, ratio});
}
void scenario::stop_interval(time_interval& itv, double ratio)
void scenario::request_stop_interval(time_interval& itv, double ratio)
{
m_itv_to_stop.emplace_back(quantized_interval{&itv, ratio});
}

void scenario::reset_all_components_except(ossia::time_sync& n)
{
// For all nodes not in the component of n:
// If:
// - It is executing
// - It has a previous interval executing
// - It has a next interval executing
// Then:
// reset_component(n)

sync_set nodes_to_process;
// 1. Compute the set of nodes to process
{
auto& stack = m_component_visit_stack;
auto& cache = m_component_visit_cache;

stack.clear();
cache.clear();

cache.insert(&n);
stack.push_back(&n);

while(!stack.empty())
{
auto n = stack.back();
stack.pop_back();

for(auto& ev : n->get_time_events())
{
for(auto& cst : ev->previous_time_intervals())
{
auto& pn = cst->get_start_event().get_time_sync();
if(cache.find(&pn) == cache.end())
{
cache.insert(&pn);
stack.push_back(&pn);
}
}

for(auto& cst : ev->next_time_intervals())
{
auto& pn = cst->get_end_event().get_time_sync();
if(cache.find(&pn) == cache.end())
{
cache.insert(&pn);
stack.push_back(&pn);
}
}
}
}

// At this point, "cache" contains the entire component of n
for(auto& node : m_nodes)
if(!cache.contains(node.get()))
nodes_to_process.insert(node.get());

// Now nodes_to_process contains all the nodes that are not in the component of n
}

// 2. Apply the algorithm mentioned above:
for(auto& n : nodes_to_process)
{
if(n->is_being_triggered())
goto disable_component;

for(auto& ev : n->get_time_events())
{
for(auto& cst : ev->previous_time_intervals())
{
if(cst->running())
{
goto disable_component;
}
}
for(auto& cst : ev->next_time_intervals())
{
if(cst->running())
{
goto disable_component;
}
}
}

continue;

disable_component:
reset_component(*n);
}
}

void scenario::reset_component(ossia::time_sync& n)
{
auto& stack = m_component_visit_stack;
Expand All @@ -340,12 +440,6 @@ void scenario::reset_component(ossia::time_sync& n)
cache.insert(&n);
stack.push_back(&n);

auto disable_itv = [&](ossia::time_interval& itv) {
itv.stop();
m_runningIntervals.erase(&itv);
m_itv_end_map.erase(&itv);
};

while(!stack.empty())
{
auto n = stack.back();
Expand All @@ -357,7 +451,7 @@ void scenario::reset_component(ossia::time_sync& n)
{
for(auto& cst : ev->previous_time_intervals())
{
disable_itv(*cst);
stop_interval(*cst);

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

for(auto& cst : ev->next_time_intervals())
{
disable_itv(*cst);
stop_interval(*cst);

auto& pn = cst->get_end_event().get_time_sync();
if(cache.find(&pn) == cache.end())
Expand Down
13 changes: 11 additions & 2 deletions src/ossia/editor/scenario/scenario.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ class OSSIA_EXPORT scenario final : public looping_process<scenario>
* e.g. this is used when pressing the "play" button on a random interval in
* score.
*/
void start_interval(ossia::time_interval&, double ratio = 0.0);
void request_start_interval(ossia::time_interval&, double ratio = 0.0);
/*! Used to stop an interval,
* disregarding all the rules of the scenario.
* e.g. this is used when pressing the "stop" button on a random interval in
* score.
*/
void stop_interval(ossia::time_interval&, double ratio = 0.0);
void request_stop_interval(ossia::time_interval&, double ratio = 0.0);

small_sync_vec get_roots() const noexcept;

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

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

void set_exclusive(bool excl) noexcept;
bool exclusive(bool excl) const noexcept;

private:
void stop_all_intervals();
ossia::time_value m_last_date{ossia::Infinite};

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

sync_set m_component_visit_cache;
std::vector<ossia::time_sync*> m_component_visit_stack;

bool m_exclusive{};

// Used to start intervals off-time
struct quantized_interval
{
Expand Down Expand Up @@ -217,6 +224,8 @@ class OSSIA_EXPORT scenario final : public looping_process<scenario>
ossia::time_interval& interval, const ossia::token_request& tk,
const time_value& tick_ms, ossia::time_value tick, ossia::time_value offset);

void stop_interval(ossia::time_interval& itv);
void reset_component(ossia::time_sync& n);
void reset_all_components_except(ossia::time_sync& n);
};
}

0 comments on commit c2022c1

Please sign in to comment.