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