]> git.tdb.fi Git - libs/demoscene.git/blob - source/sequencer.h
Put everything in namespace Msp::DemoScene
[libs/demoscene.git] / source / sequencer.h
1 #ifndef MSP_DEMOSCENE_SEQUENCER_H_
2 #define MSP_DEMOSCENE_SEQUENCER_H_
3
4 #include <vector>
5 #include <sigc++/signal.h>
6 #include <msp/core/maputils.h>
7 #include <msp/core/refptr.h>
8 #include <msp/datafile/objectloader.h>
9 #include <msp/time/timedelta.h>
10 #include <msp/time/timestamp.h>
11 #include "action.h"
12
13 namespace Msp {
14 namespace DemoScene {
15
16 class Demo;
17
18 class Sequencer
19 {
20 public:
21         class Loader: public Msp::DataFile::ObjectLoader<Sequencer>
22         {
23         private:
24                 Demo &demo;
25
26         public:
27                 Loader(Sequencer &, Demo &);
28
29         private:
30                 void define_action(const std::string &);
31                 void instant(float);
32                 void segment(float, float);
33         };
34
35 private:
36         class ActionDefLoader;
37         class SegmentLoader;
38
39         class RegisteredAction
40         {
41         public:
42                 typedef void (ActionDefLoader::*DefLoaderFunc)();
43                 typedef void (SegmentLoader::*LoaderFunc)();
44
45                 virtual ~RegisteredAction() { }
46                 virtual DefLoaderFunc get_def_loader_func() const = 0;
47                 virtual LoaderFunc get_loader_func() const = 0;
48         };
49
50         template<typename T>
51         class RegisteredActionType: public RegisteredAction
52         {
53         public:
54                 virtual DefLoaderFunc get_def_loader_func() const;
55                 virtual LoaderFunc get_loader_func() const;
56         };
57
58         class ActionDefLoader: public Msp::DataFile::ObjectLoader<Sequencer>
59         {
60         private:
61                 Demo &demo;
62                 Msp::RefPtr<Action> action;
63
64         public:
65                 ActionDefLoader(Sequencer &, Demo &);
66
67                 Action *get_action() { return action.release(); }
68
69         private:
70                 virtual void finished();
71
72                 template<typename T>
73                 void action_def();
74
75                 template<typename T>
76                 friend class RegisteredActionType;
77         };
78
79         struct Segment
80         {
81                 Action *action;
82                 float start_beat;
83                 float end_beat;
84         };
85
86         class SegmentLoader: public Msp::DataFile::ObjectLoader<Sequencer>
87         {
88         private:
89                 float start_beat;
90                 float end_beat;
91                 Demo &demo;
92
93         public:
94                 SegmentLoader(Sequencer &, float, float, Demo &);
95
96         private:
97                 template<typename T>
98                 void action();
99
100                 void apply(const std::string &);
101
102                 template<typename T>
103                 friend class RegisteredActionType;
104         };
105
106 public:
107         sigc::signal<void> signal_finished;
108
109 private:
110         std::map<std::string, RegisteredAction *> action_types;
111         std::map<std::string, Action *> named_actions;
112         std::vector<Action *> anonymous_actions;
113
114         Msp::Time::TimeDelta secs_per_beat;
115         std::vector<Action *> static_actions;
116         std::vector<Segment> segments;
117         std::vector<Segment>::const_iterator begin;
118         std::vector<Segment>::const_iterator end;
119         bool started;
120         float beat;
121         float next_event;
122
123 public:
124         Sequencer(float = 120.0f);
125
126         template<typename T>
127         void register_action_type(const std::string &);
128
129         void set_beats_per_minute(float);
130         float get_beats_per_minute() const { return Msp::Time::min/secs_per_beat; }
131         void add_static_action(Action &);
132         void add_action(Action &, float, float);
133
134         void start();
135         void seek(float);
136         void tick(const Msp::Time::TimeDelta &);
137 private:
138         void advance_to(float);
139         void update_next_event();
140 public:
141         float get_current_beat() const { return beat; }
142 };
143
144 template<typename T>
145 inline void Sequencer::register_action_type(const std::string &n)
146 {
147         if(action_types.count(n))
148                 throw Msp::key_error(n);
149
150         action_types[n] = new RegisteredActionType<T>;
151 }
152
153 template<typename T>
154 Sequencer::RegisteredAction::DefLoaderFunc Sequencer::RegisteredActionType<T>::get_def_loader_func() const
155 {
156         return &ActionDefLoader::action_def<T>;
157 }
158
159 template<typename T>
160 Sequencer::RegisteredAction::LoaderFunc Sequencer::RegisteredActionType<T>::get_loader_func() const
161 {
162         return &SegmentLoader::action<T>;
163 }
164
165 template<typename T>
166 void Sequencer::ActionDefLoader::action_def()
167 {
168         if(action)
169                 throw std::runtime_error("Only one action per definition is allowed");
170
171         Msp::RefPtr<T> act = new T;
172         load_sub(*act, demo);
173         action = act;
174 }
175
176 template<typename T>
177 void Sequencer::SegmentLoader::action()
178 {
179         Msp::RefPtr<T> act = new T;
180         load_sub(*act, demo);
181         obj.add_action(*act, start_beat, end_beat);
182         obj.anonymous_actions.push_back(act.release());
183 }
184
185 } // namespace DemoScene
186 } // namespace Msp
187
188 #endif