#include <vector>
#include <sigc++/signal.h>
+#include <msp/core/maputils.h>
+#include <msp/core/refptr.h>
+#include <msp/datafile/loadabletyperegistry.h>
+#include <msp/datafile/objectloader.h>
#include <msp/time/timedelta.h>
#include <msp/time/timestamp.h>
+#include "action.h"
-class Action;
+namespace Msp {
+namespace DemoScene {
+
+class Demo;
class Sequencer
{
+public:
+ class Loader: public Msp::DataFile::ObjectLoader<Sequencer>
+ {
+ private:
+ Demo &demo;
+ float base_beat;
+
+ public:
+ Loader(Sequencer &, Demo &);
+
+ private:
+ void base(float);
+ void define_action(const std::string &);
+ void instant(float);
+ void repeat(float, float, unsigned);
+ void segment(float, float);
+ };
+
private:
+ class ActionDefLoader: public Msp::DataFile::ObjectLoader<Sequencer>
+ {
+ protected:
+ template<typename T>
+ struct AddAction
+ {
+ static void add(ActionDefLoader &ldr, const std::string &kw) { ldr.add(kw, &ActionDefLoader::action_def<T>); }
+ };
+
+ Demo &demo;
+ Msp::RefPtr<Action> action;
+
+ public:
+ ActionDefLoader(Sequencer &, Demo &);
+
+ Action *get_action() { return action.release(); }
+
+ protected:
+ virtual void action_loaded() { }
+
+ private:
+ template<typename T>
+ void action_def();
+
+ friend class Sequencer;
+ };
+
struct Segment
{
Action *action;
float end_beat;
};
+ class SegmentLoader: public ActionDefLoader
+ {
+ private:
+ float start_beat;
+ float end_beat;
+
+ public:
+ SegmentLoader(Sequencer &, float, float, Demo &);
+
+ private:
+ virtual void action_loaded();
+
+ void apply(const std::string &);
+ };
+
public:
sigc::signal<void> signal_finished;
private:
+ DataFile::LoadableTypeRegistry<ActionDefLoader, ActionDefLoader::AddAction> action_registry;
+ std::map<std::string, Action *> named_actions;
+ std::vector<Action *> anonymous_actions;
+
Msp::Time::TimeDelta secs_per_beat;
std::vector<Action *> static_actions;
std::vector<Segment> segments;
public:
Sequencer(float = 120.0f);
+ template<typename T>
+ void register_action_type(const std::string &);
+
void set_beats_per_minute(float);
float get_beats_per_minute() const { return Msp::Time::min/secs_per_beat; }
void add_static_action(Action &);
float get_current_beat() const { return beat; }
};
+template<typename T>
+inline void Sequencer::register_action_type(const std::string &n)
+{
+ action_registry.register_type<T>(n);
+}
+
+template<typename T>
+void Sequencer::ActionDefLoader::action_def()
+{
+ if(action)
+ throw std::runtime_error("Only one action per definition is allowed");
+
+ Msp::RefPtr<T> act = new T;
+ load_sub(*act, demo);
+ act->validate();
+ action = act.release();
+ action_loaded();
+}
+
+} // namespace DemoScene
+} // namespace Msp
+
#endif