diff options
Diffstat (limited to 'src/server/Event.hpp')
-rw-r--r-- | src/server/Event.hpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/server/Event.hpp b/src/server/Event.hpp new file mode 100644 index 00000000..d9095def --- /dev/null +++ b/src/server/Event.hpp @@ -0,0 +1,163 @@ +/* + This file is part of Ingen. + Copyright 2007-2016 David Robillard <http://drobilla.net/> + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef INGEN_ENGINE_EVENT_HPP +#define INGEN_ENGINE_EVENT_HPP + +#include <atomic> + +#include "raul/Deletable.hpp" +#include "raul/Noncopyable.hpp" +#include "raul/Path.hpp" + +#include "ingen/Interface.hpp" +#include "ingen/Node.hpp" +#include "ingen/Status.hpp" +#include "ingen/types.hpp" + +#include "types.hpp" + +namespace Ingen { +namespace Server { + +class Engine; +class RunContext; +class PreProcessContext; + +/** An event (command) to perform some action on Ingen. + * + * Virtually all operations on Ingen are implemented as events. An event has + * three distinct execution phases: + * + * 1) Pre-process: In a non-realtime thread, prepare event for execution + * 2) Execute: In the audio thread, execute (apply) event + * 3) Post-process: In a non-realtime thread, finalize event + * (e.g. clean up and send replies) + * + * \ingroup engine + */ +class Event : public Raul::Deletable, public Raul::Noncopyable +{ +public: + /** Event mode to distinguish normal events from undo events. */ + enum class Mode { NORMAL, UNDO, REDO }; + + /** Execution mode for events that block and unblock preprocessing. */ + enum class Execution { + NORMAL, ///< Normal pipelined execution + ATOMIC, ///< Block pre-processing until this event is executed + BLOCK, ///< Begin atomic block of events + UNBLOCK ///< Finish atomic executed block of events + }; + + /** Pre-process event before execution (non-realtime). */ + virtual bool pre_process(PreProcessContext& ctx) = 0; + + /** Execute this event in the audio thread (realtime). */ + virtual void execute(RunContext& context) = 0; + + /** Post-process event after execution (non-realtime). */ + virtual void post_process() = 0; + + /** Write the inverse of this event to `sink`. */ + virtual void undo(Interface& target) {} + + /** Return true iff this event has been pre-processed. */ + inline bool is_prepared() const { return _status != Status::NOT_PREPARED; } + + /** Return the time stamp of this event. */ + inline SampleCount time() const { return _time; } + + /** Set the time stamp of this event. */ + inline void set_time(SampleCount time) { _time = time; } + + /** Get the next event to be processed after this one. */ + Event* next() const { return _next.load(); } + + /** Set the next event to be processed after this one. */ + void next(Event* ev) { _next = ev; } + + /** Return the status (success or error code) of this event. */ + Status status() const { return _status; } + + /** Return the blocking behaviour of this event (after construction). */ + virtual Execution get_execution() const { return Execution::NORMAL; } + + /** Return undo mode of this event. */ + Mode get_mode() const { return _mode; } + + /** Set the undo mode of this event. */ + void set_mode(Mode mode) { _mode = mode; } + + inline Engine& engine() { return _engine; } + +protected: + Event(Engine& engine, SPtr<Interface> client, int32_t id, FrameTime time) + : _engine(engine) + , _next(nullptr) + , _request_client(std::move(client)) + , _request_id(id) + , _time(time) + , _status(Status::NOT_PREPARED) + , _mode(Mode::NORMAL) + {} + + /** Constructor for internal events only */ + explicit Event(Engine& engine) + : _engine(engine) + , _next(nullptr) + , _request_id(0) + , _time(0) + , _status(Status::NOT_PREPARED) + , _mode(Mode::NORMAL) + {} + + inline bool pre_process_done(Status st) { + _status = st; + return st == Status::SUCCESS; + } + + inline bool pre_process_done(Status st, const URI& subject) { + _err_subject = subject; + return pre_process_done(st); + } + + inline bool pre_process_done(Status st, const Raul::Path& subject) { + return pre_process_done(st, path_to_uri(subject)); + } + + /** Respond to the originating client. */ + inline Status respond() { + if (_request_client && _request_id) { + _request_client->response(_request_id, _status, _err_subject); + } + return _status; + } + + Engine& _engine; + std::atomic<Event*> _next; + SPtr<Interface> _request_client; + int32_t _request_id; + FrameTime _time; + Status _status; + std::string _err_subject; + Mode _mode; +}; + +} // namespace Server +} // namespace Ingen + +#endif // INGEN_ENGINE_EVENT_HPP |