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