#include <vector>
#include <sigc++/signal.h>
+#include <msp/core/maputils.h>
+#include <msp/core/refptr.h>
+#include <msp/datafile/objectloader.h>
#include <msp/time/timedelta.h>
#include <msp/time/timestamp.h>
+#include "action.h"
-class Action;
+class Demo;
class Sequencer
{
+public:
+ class Loader: public Msp::DataFile::ObjectLoader<Sequencer>
+ {
+ private:
+ Demo &demo;
+
+ public:
+ Loader(Sequencer &, Demo &);
+
+ private:
+ void define_action(const std::string &);
+ void instant(float);
+ void segment(float, float);
+ };
+
private:
+ class ActionDefLoader;
+
+ class RegisteredAction
+ {
+ public:
+ typedef void (ActionDefLoader::*LoaderFunc)();
+
+ virtual ~RegisteredAction() { }
+ virtual LoaderFunc get_loader_func() const = 0;
+ };
+
+ template<typename T>
+ class RegisteredActionType: public RegisteredAction
+ {
+ public:
+ virtual LoaderFunc get_loader_func() const;
+ };
+
+ class ActionDefLoader: public Msp::DataFile::ObjectLoader<Sequencer>
+ {
+ private:
+ Demo &demo;
+ Msp::RefPtr<Action> action;
+
+ public:
+ ActionDefLoader(Sequencer &, Demo &);
+
+ Action *get_action() { return action.release(); }
+
+ private:
+ virtual void finished();
+
+ template<typename T>
+ void action_def();
+
+ template<typename T>
+ friend class RegisteredActionType;
+ };
+
struct Segment
{
Action *action;
float end_beat;
};
+ class SegmentLoader: public Msp::DataFile::ObjectLoader<Sequencer>
+ {
+ private:
+ float start_beat;
+ float end_beat;
+
+ public:
+ SegmentLoader(Sequencer &, float, float);
+
+ private:
+ void apply(const std::string &);
+ };
+
public:
sigc::signal<void> signal_finished;
private:
+ std::map<std::string, RegisteredAction *> action_types;
+ std::map<std::string, Action *> named_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)
+{
+ if(action_types.count(n))
+ throw Msp::key_error(n);
+
+ action_types[n] = new RegisteredActionType<T>;
+}
+
+template<typename T>
+Sequencer::RegisteredAction::LoaderFunc Sequencer::RegisteredActionType<T>::get_loader_func() const
+{
+ return &ActionDefLoader::action_def<T>;
+}
+
+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);
+ action = act;
+}
+
#endif