]> git.tdb.fi Git - libs/demoscene.git/blob - source/sequencer.cpp
Use LoadableTypeRegistry to manage action types in Sequencer
[libs/demoscene.git] / source / sequencer.cpp
1 #include <cmath>
2 #include <msp/core/algorithm.h>
3 #include <msp/core/maputils.h>
4 #include <msp/core/raii.h>
5 #include "animate.h"
6 #include "fadeoverlay.h"
7 #include "sequencer.h"
8 #include "stage.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace DemoScene {
14
15 Sequencer::Sequencer(float bpm):
16         started(false),
17         beat(0),
18         next_event(0)
19 {
20         set_beats_per_minute(bpm);
21
22         register_action_type<Animate>("animate");
23         register_action_type<FadeOverlay::Fade>("fade");
24         register_action_type<Stage::UseInView>("use_stage");
25         register_action_type<Stage::SetCamera>("set_camera");
26 }
27
28 void Sequencer::set_beats_per_minute(float bpm)
29 {
30         secs_per_beat = Time::min/bpm;
31 }
32
33 void Sequencer::add_static_action(Action &act)
34 {
35         static_actions.push_back(&act);
36 }
37
38 void Sequencer::add_action(Action &act, float sb, float eb)
39 {
40         if(sb<0 || sb>eb)
41                 throw invalid_argument("Sequencer::add_action");
42
43         Segment seg;
44         seg.action = &act;
45         seg.start_beat = sb;
46         seg.end_beat = eb;
47         auto i = find_if(segments, [=](const Segment &s){ return s.start_beat>sb; });
48         segments.insert(i, seg);
49 }
50
51 void Sequencer::start()
52 {
53         started = true;
54         end = begin = segments.begin();
55         for(auto a: static_actions)
56                 a->start(0, numeric_limits<float>::max());
57         float start_beat = beat;
58         beat = -1;
59         advance_to(start_beat);
60 }
61
62 void Sequencer::seek(float b)
63 {
64         if(b<beat)
65                 throw logic_error("Sequencer::seek");
66
67         if(started)
68                 advance_to(b);
69         else
70                 beat = b;
71 }
72
73 void Sequencer::tick(const Time::TimeDelta &dt)
74 {
75         if(!started)
76                 start();
77         if(begin==segments.end())
78                 return;
79
80         advance_to(beat+dt/secs_per_beat);
81 }
82
83 void Sequencer::advance_to(float target_beat)
84 {
85         while(target_beat>next_event)
86                 advance_to(next_event);
87
88         float prev_beat = beat;
89         beat = target_beat;
90
91         while(end!=segments.end() && end->start_beat<=beat)
92                 ++end;
93
94         int ibeat = static_cast<int>(floor(beat));
95         bool do_beat = (ibeat!=static_cast<int>(floor(prev_beat)));
96
97         for(auto a: static_actions)
98         {
99                 if(do_beat)
100                         a->beat(ibeat);
101                 a->tick(beat, beat-prev_beat);
102         }
103
104         for(auto i=begin; i!=end; ++i)
105         {
106                 if(i->start_beat>prev_beat)
107                         i->action->start(i->start_beat, i->end_beat-i->start_beat);
108                 if(do_beat)
109                         i->action->beat(ibeat);
110                 if(i->end_beat>=prev_beat)
111                 {
112                         float tick_beat = min(beat, i->end_beat);
113                         i->action->tick(tick_beat, tick_beat-max(prev_beat, i->start_beat));
114                         if(i->end_beat<=beat)
115                                 i->action->end(i->end_beat);
116                 }
117         }
118
119         while(begin!=end && begin->end_beat<=beat)
120                 ++begin;
121
122         if(target_beat>=next_event)
123                 update_next_event();
124
125         if(begin==segments.end())
126                 signal_finished.emit();
127 }
128
129 void Sequencer::update_next_event()
130 {
131         next_event = numeric_limits<float>::max();
132
133         if(end!=segments.end())
134                 next_event = min(next_event, end->start_beat);
135
136         for(auto i=begin; i!=end; ++i)
137                 if(i->end_beat>beat)
138                         next_event = min(next_event, i->end_beat);
139 }
140
141
142 Sequencer::Loader::Loader(Sequencer &s, Demo &d):
143         DataFile::ObjectLoader<Sequencer>(s),
144         demo(d),
145         base_beat(0.0f)
146 {
147         add("base", &Loader::base);
148         add("define_action", &Loader::define_action);
149         add("instant", &Loader::instant);
150         add("repeat", &Loader::repeat);
151         add("segment", &Loader::segment);
152 }
153
154 void Sequencer::Loader::base(float b)
155 {
156         SetForScope<float> set_base(base_beat, base_beat+b);
157         load_sub_with(*this);
158 }
159
160 void Sequencer::Loader::define_action(const string &n)
161 {
162         ActionDefLoader ldr(obj, demo);
163         load_sub_with(ldr);
164         obj.named_actions[n] = ldr.get_action();
165 }
166
167 void Sequencer::Loader::instant(float beat)
168 {
169         segment(beat, beat);
170 }
171
172 void Sequencer::Loader::repeat(float b, float d, unsigned n)
173 {
174         for(unsigned i=0; i<n; ++i)
175         {
176                 SetForScope<float> set_base(base_beat, base_beat+b+i*d);
177                 load_sub_with(*this);
178         }
179 }
180
181 void Sequencer::Loader::segment(float start, float end)
182 {
183         SegmentLoader ldr(obj, base_beat+start, base_beat+end, demo);
184         load_sub_with(ldr);
185 }
186
187
188 Sequencer::ActionDefLoader::ActionDefLoader(Sequencer &s, Demo &d):
189         DataFile::ObjectLoader<Sequencer>(s),
190         demo(d)
191 {
192         obj.action_registry.add_all(*this);
193 }
194
195
196 Sequencer::SegmentLoader::SegmentLoader(Sequencer &s, float b, float e, Demo &d):
197         ActionDefLoader(s, d),
198         start_beat(b),
199         end_beat(e)
200 {
201         add("apply", &SegmentLoader::apply);
202 }
203
204 void Sequencer::SegmentLoader::action_loaded()
205 {
206         obj.add_action(*action, start_beat, end_beat);
207         obj.anonymous_actions.push_back(action.release());
208 }
209
210 void Sequencer::SegmentLoader::apply(const string &n)
211 {
212         obj.add_action(*get_item(obj.named_actions, n), start_beat, end_beat);
213 }
214
215 } // namespace DemoScene
216 } // namespace Msp