From 0f5a2bafb9f1c3f64256e1899857b2f5cb3d8982 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 18 Dec 2014 07:53:39 +0000 Subject: Work towards engine/GUI separation. git-svn-id: http://svn.drobilla.net/lad/trunk/machina@5495 a436a847-0d15-0410-975c-d299462d15a1 --- src/client/ClientModel.cpp | 34 ++++++++- src/client/ClientModel.hpp | 16 ++-- src/client/ClientObject.cpp | 5 +- src/client/ClientObject.hpp | 4 +- src/engine/Controller.cpp | 150 +++++++++++++++++++------------------- src/engine/Engine.cpp | 8 +- src/engine/Updates.cpp | 6 +- src/engine/machina/Controller.hpp | 19 ++--- src/engine/machina/Model.hpp | 44 +++++++++++ src/engine/machina/types.hpp | 6 +- src/engine/wscript | 4 +- src/gui/MachinaCanvas.cpp | 21 +++--- src/gui/main.cpp | 14 ++-- 13 files changed, 207 insertions(+), 124 deletions(-) create mode 100644 src/engine/machina/Model.hpp diff --git a/src/client/ClientModel.cpp b/src/client/ClientModel.cpp index 17054d4..3a8770f 100644 --- a/src/client/ClientModel.cpp +++ b/src/client/ClientModel.cpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -31,13 +31,31 @@ ClientModel::find(uint64_t id) } } +SPtr +ClientModel::find(uint64_t id) const +{ + SPtr key(new ClientObjectKey(id)); + Objects::const_iterator i = _objects.find(key); + if (i != _objects.end()) { + return *i; + } else { + return SPtr(); + } +} + void -ClientModel::new_object(SPtr object) +ClientModel::new_object(uint64_t id, const Properties& properties) { - Objects::iterator i = _objects.find(object); + SPtr key(new ClientObjectKey(id)); + Objects::iterator i = _objects.find(key); if (i == _objects.end()) { + SPtr object(new ClientObject(id, properties)); _objects.insert(object); signal_new_object.emit(object); + } else { + for (const auto& p : properties) { + (*i)->set(p.first, p.second); + } } } @@ -56,7 +74,7 @@ ClientModel::erase_object(uint64_t id) } void -ClientModel::property(uint64_t id, URIInt key, const Atom& value) +ClientModel::set(uint64_t id, URIInt key, const Atom& value) { SPtr object = find(id); if (object) { @@ -64,5 +82,13 @@ ClientModel::property(uint64_t id, URIInt key, const Atom& value) } } +const Atom& +ClientModel::get(uint64_t id, URIInt key) const +{ + static const Atom null_atom; + SPtr object = find(id); + return object ? object->get(key) : null_atom; +} + } } diff --git a/src/client/ClientModel.hpp b/src/client/ClientModel.hpp index 6840c11..e65fb93 100644 --- a/src/client/ClientModel.hpp +++ b/src/client/ClientModel.hpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -21,6 +21,8 @@ #include +#include "machina/Model.hpp" + #include "ClientObject.hpp" namespace Raul { @@ -30,14 +32,18 @@ class Atom; namespace machina { namespace client { -class ClientModel +class ClientModel : public Model { public: - void new_object(SPtr object); + void new_object(uint64_t id, const Properties& properties); + void erase_object(uint64_t id); - void property(uint64_t id, URIInt key, const Atom& value); - SPtr find(uint64_t id); + SPtr find(uint64_t id); + SPtr find(uint64_t id) const; + + void set(uint64_t id, URIInt key, const Atom& value); + const Atom& get(uint64_t id, URIInt key) const; sigc::signal< void, SPtr > signal_new_object; sigc::signal< void, SPtr > signal_erase_object; diff --git a/src/client/ClientObject.cpp b/src/client/ClientObject.cpp index 9481d10..20b50a2 100644 --- a/src/client/ClientObject.cpp +++ b/src/client/ClientObject.cpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -21,9 +21,10 @@ namespace machina { namespace client { -ClientObject::ClientObject(uint64_t id) +ClientObject::ClientObject(uint64_t id, const Properties& properties) : _id(id) , _view(NULL) + , _properties(properties) {} ClientObject::ClientObject(const ClientObject& copy, uint64_t id) diff --git a/src/client/ClientObject.hpp b/src/client/ClientObject.hpp index cf00a2b..6520b11 100644 --- a/src/client/ClientObject.hpp +++ b/src/client/ClientObject.hpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -30,7 +30,7 @@ namespace client { class ClientObject { public: - explicit ClientObject(uint64_t id); + explicit ClientObject(uint64_t id, const Properties& properties={}); ClientObject(const ClientObject& copy, uint64_t id); inline uint64_t id() const { return _id; } diff --git a/src/engine/Controller.cpp b/src/engine/Controller.cpp index 8c27503..8f9e1a2 100644 --- a/src/engine/Controller.cpp +++ b/src/engine/Controller.cpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -14,12 +14,9 @@ along with Machina. If not, see . */ -#include "client/ClientModel.hpp" -#include "client/ClientObject.hpp" #include "machina/Controller.hpp" #include "machina/Engine.hpp" #include "machina/Machine.hpp" -#include "machina/Machine.hpp" #include "machina/Updates.hpp" #include "Edge.hpp" @@ -27,26 +24,32 @@ namespace machina { -Controller::Controller(SPtr engine, - client::ClientModel& client_model) +Controller::Controller(SPtr engine, + Model& model) : _engine(engine) - , _client_model(client_model) + , _model(model) , _updates(new Raul::RingBuffer(4096)) { _engine->driver()->set_update_sink(_updates); } uint64_t -Controller::create(const client::ClientObject& properties) +Controller::create(const Properties& properties) { - TimeDuration dur( - _engine->machine()->time().unit(), - properties.get(URIs::instance().machina_duration).get()); + std::map::const_iterator d = properties.find( + URIs::instance().machina_duration); + + double duration = 0.0; + if (d != properties.end()) { + duration = d->second.get(); + } else { + std::cerr << "warning: new object has no duration" << std::endl; + } + + TimeDuration dur(_engine->machine()->time().unit(), duration); SPtr node(new Node(dur)); - SPtr obj( - new client::ClientObject(properties, node->id())); _objects.insert(node); - _client_model.new_object(obj); + _model.new_object(node->id(), properties); _engine->machine()->add_node(node); return node->id(); } @@ -54,59 +57,55 @@ Controller::create(const client::ClientObject& properties) void Controller::announce(SPtr machine) { + if (!machine) { + return; + } + Forge& forge = _engine->forge(); + // Announce nodes for (const auto& n : machine->nodes()) { - // Find or create a new client object if necessary - SPtr obj = _client_model.find(n->id()); - if (!obj) { - obj = SPtr(new client::ClientObject(n->id())); - obj->set(URIs::instance().rdf_type, - forge.make_urid(URIs::instance().machina_Node)); - obj->set(URIs::instance().machina_duration, - forge.make(float(n->duration().to_double()))); - if (n->is_initial()) { - obj->set(URIs::instance().machina_initial, forge.make(true)); - } - - SPtr midi_action = dynamic_ptr_cast( - n->enter_action()); - if (midi_action) { - SPtr action = _client_model.find( - midi_action->id()); - if (!action) { - action = SPtr( - new client::ClientObject(midi_action->id())); - action->set(URIs::instance().machina_note_number, - forge.make((int32_t)midi_action->event()[1])); - _client_model.new_object(action); - } - obj->set(URIs::instance().machina_enter_action, - forge.make(int32_t(n->enter_action()->id()))); - } + Properties properties { + { URIs::instance().rdf_type, + forge.make_urid(URIs::instance().machina_Node) }, + { URIs::instance().machina_duration, + forge.make(float(n->duration().to_double())) } }; + if (n->is_initial()) { + properties.insert({ URIs::instance().machina_initial, + forge.make(true) }); } + + SPtr midi_action = dynamic_ptr_cast( + n->enter_action()); + if (midi_action) { + Properties action_properties { + { URIs::instance().machina_note_number, + forge.make((int32_t)midi_action->event()[1]) } }; + + _model.new_object(midi_action->id(), action_properties); + properties.insert({ URIs::instance().machina_enter_action, + forge.make(int32_t(n->enter_action()->id())) }); + } + _objects.insert(n); - _client_model.new_object(obj); + _model.new_object(n->id(), properties); } + // Announce edges for (const auto& n : machine->nodes()) { for (const auto& e : n->edges()) { - SPtr eobj = _client_model.find(e->id()); - if (!eobj) { - eobj = SPtr( - new client::ClientObject(e->id())); - eobj->set(URIs::instance().rdf_type, - forge.make_urid(URIs::instance().machina_Edge)); - eobj->set(URIs::instance().machina_probability, - forge.make(e->probability())); - eobj->set(URIs::instance().machina_tail_id, - forge.make((int32_t)n->id())); - eobj->set(URIs::instance().machina_head_id, - forge.make((int32_t)e->head()->id())); - } + const Properties properties { + { URIs::instance().rdf_type, + forge.make_urid(URIs::instance().machina_Edge) }, + { URIs::instance().machina_probability, + forge.make(e->probability()) }, + { URIs::instance().machina_tail_id, + forge.make((int32_t)n->id()) }, + { URIs::instance().machina_head_id, + forge.make((int32_t)e->head()->id()) } }; _objects.insert(e); - _client_model.new_object(eobj); + _model.new_object(e->id(), properties); } } } @@ -142,7 +141,7 @@ Controller::set_property(uint64_t object_id, SPtr object = find(object_id); if (object) { object->set(key, value); - _client_model.property(object_id, key, value); + _model.set(object_id, key, value); } } @@ -152,20 +151,30 @@ Controller::connect(uint64_t tail_id, uint64_t head_id) SPtr tail = dynamic_ptr_cast(find(tail_id)); SPtr head = dynamic_ptr_cast(find(head_id)); + if (!tail) { + std::cerr << "error: tail node " << tail_id << " not found" << std::endl; + return 0; + } else if (!head) { + std::cerr << "error: head node " << head_id << " not found" << std::endl; + return 0; + } + SPtr edge(new Edge(tail, head)); tail->add_edge(edge); _objects.insert(edge); Forge& forge = _engine->forge(); - SPtr obj(new client::ClientObject(edge->id())); - obj->set(URIs::instance().rdf_type, - forge.make_urid(URIs::instance().machina_Edge)); - obj->set(URIs::instance().machina_probability, forge.make(1.0f)); - obj->set(URIs::instance().machina_tail_id, forge.make((int32_t)tail->id())); - obj->set(URIs::instance().machina_head_id, forge.make((int32_t)head->id())); + const Properties properties = { + { URIs::instance().rdf_type, + forge.make_urid(URIs::instance().machina_Edge) }, + { URIs::instance().machina_probability, forge.make(1.0f) }, + { URIs::instance().machina_tail_id, + forge.make((int32_t)tail->id()) }, + { URIs::instance().machina_head_id, + forge.make((int32_t)head->id()) } }; - _client_model.new_object(obj); + _model.new_object(edge->id(), properties); return edge->id(); } @@ -178,7 +187,7 @@ Controller::disconnect(uint64_t tail_id, uint64_t head_id) SPtr edge = tail->remove_edge_to(head); if (edge) { - _client_model.erase_object(edge->id()); + _model.erase_object(edge->id()); } else { std::cerr << "Edge not found" << std::endl; } @@ -198,7 +207,7 @@ Controller::erase(uint64_t id) _engine->machine()->remove_node(node); } - _client_model.erase_object((*i)->id()); + _model.erase_object((*i)->id()); _objects.erase(i); } @@ -212,14 +221,7 @@ Controller::process_updates() Atom value; for (uint32_t i = 0; i < read_space; ) { i += read_set(_updates, &subject, &key, &value); - SPtr obj = _client_model.find(subject); - if (obj) { - obj->set(key, value); - } else { - SPtr obj(new client::ClientObject(subject)); - obj->set(key, value); - _client_model.new_object(obj); - } + _model.set(subject, key, value); } } diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 7eeafa4..969b7cc 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -41,13 +41,15 @@ Engine::new_driver(Forge& forge, const std::string& name, SPtr machine) { -#ifdef HAVE_JACK if (name == "jack") { +#ifdef HAVE_JACK JackDriver* driver = new JackDriver(forge, machine); driver->attach("machina"); return SPtr(driver); - } +#else + return SPtr(); #endif + } if (name == "smf") { return SPtr(new SMFDriver(forge, machine->time().unit())); } diff --git a/src/engine/Updates.cpp b/src/engine/Updates.cpp index 3193d41..846bf8d 100644 --- a/src/engine/Updates.cpp +++ b/src/engine/Updates.cpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -44,7 +44,7 @@ read_set(SPtr buf, URIInt* key, Atom* value) { - uint32_t update_type; + uint32_t update_type = 0; buf->read(sizeof(update_type), &update_type); if (update_type != UPDATE_SET) { return 0; @@ -53,7 +53,7 @@ read_set(SPtr buf, buf->read(sizeof(*subject), subject); buf->read(sizeof(*key), key); - LV2_Atom atom; + LV2_Atom atom = { 0, 0 }; buf->read(sizeof(LV2_Atom), &atom); *value = Atom(atom.size, atom.type, NULL); buf->read(atom.size, value->get_body()); diff --git a/src/engine/machina/Controller.hpp b/src/engine/machina/Controller.hpp index e745c9c..833b5b2 100644 --- a/src/engine/machina/Controller.hpp +++ b/src/engine/machina/Controller.hpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -24,8 +24,9 @@ #include "raul/RingBuffer.hpp" #include "raul/Maid.hpp" -#include "machina/types.hpp" +#include "machina/Model.hpp" #include "machina/URIs.hpp" +#include "machina/types.hpp" #include "Stateful.hpp" @@ -37,19 +38,13 @@ namespace machina { class Engine; class Machine; -class Stateful; - -namespace client { -class ClientModel; -class ClientObject; -} class Controller { public: - Controller(SPtr engine, client::ClientModel& client_model); + Controller(SPtr engine, Model& model); - uint64_t create(const client::ClientObject& obj); + uint64_t create(const Properties& properties); uint64_t connect(uint64_t tail_id, uint64_t head_id); void set_property(uint64_t object_id, URIInt key, const Atom& value); @@ -74,8 +69,8 @@ private: typedef std::set, StatefulComparator> Objects; Objects _objects; - SPtr _engine; - client::ClientModel& _client_model; + SPtr _engine; + Model& _model; SPtr _updates; }; diff --git a/src/engine/machina/Model.hpp b/src/engine/machina/Model.hpp new file mode 100644 index 0000000..32a332e --- /dev/null +++ b/src/engine/machina/Model.hpp @@ -0,0 +1,44 @@ +/* + This file is part of Machina. + Copyright 2014 David Robillard + + Machina is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or any later version. + + Machina 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Machina. If not, see . +*/ + +#ifndef MACHINA_MODEL_HPP +#define MACHINA_MODEL_HPP + +#include + +#include + +#include "machina/Atom.hpp" +#include "machina/types.hpp" + +namespace machina { + +class Model +{ +public: + virtual ~Model() {} + + virtual void new_object(uint64_t id, const Properties& properties) = 0; + + virtual void erase_object(uint64_t id) = 0; + + virtual void set(uint64_t id, URIInt key, const Atom& value) = 0; + virtual const Atom& get(uint64_t id, URIInt key) const = 0; +}; + +} // namespace machina + +#endif // MACHINA_MODEL_HPP diff --git a/src/engine/machina/types.hpp b/src/engine/machina/types.hpp index fff2601..e9ac7d0 100644 --- a/src/engine/machina/types.hpp +++ b/src/engine/machina/types.hpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -17,6 +17,7 @@ #ifndef MACHINA_TYPES_HPP #define MACHINA_TYPES_HPP +#include #include #include "raul/RingBuffer.hpp" @@ -27,6 +28,9 @@ typedef unsigned char byte; typedef uint32_t URIInt; +class Atom; +typedef std::map Properties; + #if __cplusplus >= 201103L template using SPtr = std::shared_ptr; diff --git a/src/engine/wscript b/src/engine/wscript index 80f03a4..e1fc1ab 100644 --- a/src/engine/wscript +++ b/src/engine/wscript @@ -23,7 +23,7 @@ def build(bld): Updates.cpp URIs.cpp ''' - if bld.is_defined('HAVE_EUGENE'): + if bld.env.HAVE_EUGENE: core_source += ''' Evolver.cpp Problem.cpp @@ -35,7 +35,7 @@ def build(bld): obj.name = 'libmachina_engine' obj.target = 'machina_engine' core_libs = 'RAUL GLIBMM GTHREAD RAUL SERD SORD JACK LV2' - if bld.is_defined('HAVE_EUGENE'): + if bld.env.HAVE_EUGENE: core_libs += ' EUGENE ' autowaf.use_lib(bld, obj, core_libs) diff --git a/src/gui/MachinaCanvas.cpp b/src/gui/MachinaCanvas.cpp index 76c029c..f7292bf 100644 --- a/src/gui/MachinaCanvas.cpp +++ b/src/gui/MachinaCanvas.cpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -182,14 +182,17 @@ MachinaCanvas::on_erase_object(SPtr object) void MachinaCanvas::action_create_node(double x, double y) { - machina::client::ClientObject obj(0); - obj.set(URIs::instance().rdf_type, - _app->forge().make_urid(URIs::instance().machina_Node)); - obj.set(URIs::instance().machina_canvas_x, _app->forge().make((float)x)); - obj.set(URIs::instance().machina_canvas_y, _app->forge().make((float)y)); - obj.set(URIs::instance().machina_duration, - _app->forge().make((float)_app->default_length())); - _app->controller()->create(obj); + const Properties props = { + { URIs::instance().rdf_type, + _app->forge().make_urid(URIs::instance().machina_Node) }, + { URIs::instance().machina_canvas_x, + _app->forge().make((float)x) }, + { URIs::instance().machina_canvas_y, + _app->forge().make((float)y) }, + { URIs::instance().machina_duration, + _app->forge().make((float)_app->default_length()) } }; + + _app->controller()->create(props); } void diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 407258d..547966f 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -1,6 +1,6 @@ /* This file is part of Machina. - Copyright 2007-2013 David Robillard + Copyright 2007-2014 David Robillard Machina is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -80,13 +80,13 @@ main(int argc, char** argv) machine = SPtr(new Machine(beats)); } - std::string driver_name = "smf"; -#ifdef HAVE_JACK - driver_name = "jack"; -#endif + // Create driver + SPtr driver(Engine::new_driver(forge, "jack", machine)); + if (!driver) { + cerr << "warning: Failed to create Jack driver, using SMF" << endl; + driver = SPtr(Engine::new_driver(forge, "smf", machine)); + } - // Build engine - SPtr driver(Engine::new_driver(forge, driver_name, machine)); SPtr engine(new Engine(forge, driver, rdf_world)); Gtk::Main app(argc, argv); -- cgit v1.2.1