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