368 lines
9.4 KiB
C++
368 lines
9.4 KiB
C++
/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
|
|
*
|
|
* Ingen 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 2 of the License, or (at your option) 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 General Public License for details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "Store.h"
|
|
#include "ObjectModel.h"
|
|
#include "PatchModel.h"
|
|
#include "NodeModel.h"
|
|
#include "PortModel.h"
|
|
#include "PluginModel.h"
|
|
#include "PatchModel.h"
|
|
#include "SigClientInterface.h"
|
|
|
|
namespace Ingen {
|
|
namespace Client {
|
|
|
|
|
|
|
|
Store::Store(CountedPtr<SigClientInterface> emitter)
|
|
{
|
|
//emitter.new_plugin_sig.connect(sigc::mem_fun(this, &Store::add_plugin));
|
|
emitter->object_destroyed_sig.connect(sigc::mem_fun(this, &Store::destruction_event));
|
|
emitter->new_plugin_sig.connect(sigc::mem_fun(this, &Store::new_plugin_event));
|
|
emitter->new_patch_sig.connect(sigc::mem_fun(this, &Store::new_patch_event));
|
|
emitter->new_node_sig.connect(sigc::mem_fun(this, &Store::new_node_event));
|
|
emitter->new_port_sig.connect(sigc::mem_fun(this, &Store::new_port_event));
|
|
emitter->patch_enabled_sig.connect(sigc::mem_fun(this, &Store::patch_enabled_event));
|
|
emitter->patch_disabled_sig.connect(sigc::mem_fun(this, &Store::patch_disabled_event));
|
|
emitter->connection_sig.connect(sigc::mem_fun(this, &Store::connection_event));
|
|
emitter->disconnection_sig.connect(sigc::mem_fun(this, &Store::disconnection_event));
|
|
emitter->metadata_update_sig.connect(sigc::mem_fun(this, &Store::metadata_update_event));
|
|
emitter->control_change_sig.connect(sigc::mem_fun(this, &Store::control_change_event));
|
|
}
|
|
|
|
|
|
void
|
|
Store::clear()
|
|
{
|
|
m_objects.clear();
|
|
m_plugins.clear();
|
|
|
|
}
|
|
|
|
|
|
void
|
|
Store::add_plugin_orphan(CountedPtr<NodeModel> node)
|
|
{
|
|
cerr << "WARNING: Node " << node->path() << " received, but plugin "
|
|
<< node->plugin_uri() << " unknown." << endl;
|
|
|
|
map<string, list<CountedPtr<NodeModel> > >::iterator spawn
|
|
= m_plugin_orphans.find(node->plugin_uri());
|
|
|
|
if (spawn != m_plugin_orphans.end()) {
|
|
spawn->second.push_back(node);
|
|
} else {
|
|
list<CountedPtr<NodeModel> > l;
|
|
l.push_back(node);
|
|
m_plugin_orphans[node->plugin_uri()] = l;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
Store::resolve_plugin_orphans(CountedPtr<PluginModel> plugin)
|
|
{
|
|
map<string, list<CountedPtr<NodeModel> > >::iterator spawn
|
|
= m_plugin_orphans.find(plugin->uri());
|
|
|
|
if (spawn != m_plugin_orphans.end()) {
|
|
cerr << "XXXXXXXXXX PLUGIN-ORPHAN PLUGIN FOUND!! XXXXXXXXXXXXXXXXX" << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
Store::add_orphan(CountedPtr<ObjectModel> child)
|
|
{
|
|
cerr << "WARNING: Orphan object " << child->path() << " received." << endl;
|
|
|
|
map<Path, list<CountedPtr<ObjectModel> > >::iterator children
|
|
= m_orphans.find(child->path().parent());
|
|
|
|
if (children != m_orphans.end()) {
|
|
children->second.push_back(child);
|
|
} else {
|
|
list<CountedPtr<ObjectModel> > l;
|
|
l.push_back(child);
|
|
m_orphans[child->path().parent()] = l;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
Store::resolve_orphans(CountedPtr<ObjectModel> parent)
|
|
{
|
|
map<Path, list<CountedPtr<ObjectModel> > >::iterator children
|
|
= m_orphans.find(parent->path());
|
|
|
|
if (children != m_orphans.end()) {
|
|
cerr << "XXXXXXXXXXXXX ORPHAN PARENT FOUND!! XXXXXXXXXXXXXXXXX" << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
Store::add_object(CountedPtr<ObjectModel> object)
|
|
{
|
|
assert(object->path() != "");
|
|
assert(m_objects.find(object->path()) == m_objects.end());
|
|
|
|
if (object->path() != "/") {
|
|
CountedPtr<ObjectModel> parent = this->object(object->path().parent());
|
|
if (parent) {
|
|
assert(object->path().is_child_of(parent->path()));
|
|
object->set_parent(parent);
|
|
parent->add_child(object);
|
|
assert(object->parent() == parent);
|
|
} else {
|
|
add_orphan(object);
|
|
}
|
|
}
|
|
|
|
m_objects[object->path()] = object;
|
|
|
|
new_object_sig.emit(object);
|
|
|
|
resolve_orphans(object);
|
|
|
|
//cout << "[Store] Added " << object->path() << endl;
|
|
}
|
|
|
|
|
|
CountedPtr<ObjectModel>
|
|
Store::remove_object(const Path& path)
|
|
{
|
|
map<Path, CountedPtr<ObjectModel> >::iterator i = m_objects.find(path);
|
|
|
|
if (i != m_objects.end()) {
|
|
assert((*i).second->path() == path);
|
|
CountedPtr<ObjectModel> result = (*i).second;
|
|
m_objects.erase(i);
|
|
//cout << "[Store] Removed " << path << endl;
|
|
|
|
if (result)
|
|
result->destroyed_sig.emit();
|
|
|
|
if (result->path() != "/") {
|
|
CountedPtr<ObjectModel> parent = this->object(result->path().parent());
|
|
if (parent) {
|
|
parent->remove_child(result);
|
|
}
|
|
}
|
|
return result;
|
|
|
|
} else {
|
|
cerr << "[Store] Unable to find object " << path << " to remove." << endl;
|
|
return CountedPtr<ObjectModel>();
|
|
}
|
|
}
|
|
|
|
|
|
CountedPtr<PluginModel>
|
|
Store::plugin(const string& uri)
|
|
{
|
|
assert(uri.length() > 0);
|
|
map<string, CountedPtr<PluginModel> >::iterator i = m_plugins.find(uri);
|
|
if (i == m_plugins.end())
|
|
return CountedPtr<PluginModel>();
|
|
else
|
|
return (*i).second;
|
|
}
|
|
|
|
|
|
CountedPtr<ObjectModel>
|
|
Store::object(const Path& path)
|
|
{
|
|
assert(path.length() > 0);
|
|
map<Path, CountedPtr<ObjectModel> >::iterator i = m_objects.find(path);
|
|
if (i == m_objects.end())
|
|
return CountedPtr<ObjectModel>();
|
|
else
|
|
return (*i).second;
|
|
}
|
|
|
|
void
|
|
Store::add_plugin(CountedPtr<PluginModel> pm)
|
|
{
|
|
// FIXME: dupes?
|
|
|
|
m_plugins[pm->uri()] = pm;
|
|
}
|
|
|
|
|
|
|
|
/* ****** Signal Handlers ******** */
|
|
|
|
|
|
void
|
|
Store::destruction_event(const Path& path)
|
|
{
|
|
CountedPtr<ObjectModel> removed = remove_object(path);
|
|
removed->controller().reset();
|
|
cerr << "Store removed object " << path
|
|
<< " controller count: " << removed->controller().use_count();
|
|
removed.reset();
|
|
cerr << ", model count: " << removed.use_count() << endl;
|
|
}
|
|
|
|
void
|
|
Store::new_plugin_event(const string& type, const string& uri, const string& name)
|
|
{
|
|
CountedPtr<PluginModel> p(new PluginModel(type, uri));
|
|
p->name(name);
|
|
add_plugin(p);
|
|
resolve_plugin_orphans(p);
|
|
}
|
|
|
|
|
|
void
|
|
Store::new_patch_event(const Path& path, uint32_t poly)
|
|
{
|
|
CountedPtr<PatchModel> p(new PatchModel(path, poly));
|
|
add_object(p);
|
|
}
|
|
|
|
|
|
void
|
|
Store::new_node_event(const string& plugin_type, const string& plugin_uri, const Path& node_path, bool is_polyphonic, uint32_t num_ports)
|
|
{
|
|
// FIXME: num_ports unused
|
|
|
|
CountedPtr<PluginModel> plug = plugin(plugin_uri);
|
|
if (!plug) {
|
|
CountedPtr<NodeModel> n(new NodeModel(plugin_uri, node_path));
|
|
n->polyphonic(is_polyphonic);
|
|
add_plugin_orphan(n);
|
|
} else {
|
|
CountedPtr<NodeModel> n(new NodeModel(plug, node_path));
|
|
n->polyphonic(is_polyphonic);
|
|
add_object(n);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
Store::new_port_event(const Path& path, const string& type, bool is_output)
|
|
{
|
|
// FIXME: this sucks
|
|
|
|
PortModel::Type ptype = PortModel::CONTROL;
|
|
if (type == "AUDIO") ptype = PortModel::AUDIO;
|
|
else if (type == "CONTROL") ptype = PortModel::CONTROL;
|
|
else if (type== "MIDI") ptype = PortModel::MIDI;
|
|
else cerr << "[Store] WARNING: Unknown port type received (" << type << ")" << endl;
|
|
|
|
PortModel::Direction pdir = is_output ? PortModel::OUTPUT : PortModel::INPUT;
|
|
|
|
CountedPtr<PortModel> p(new PortModel(path, ptype, pdir));
|
|
add_object(p);
|
|
}
|
|
|
|
|
|
void
|
|
Store::patch_enabled_event(const Path& path)
|
|
{
|
|
CountedPtr<PatchModel> patch = PtrCast<PatchModel>(object(path));
|
|
if (patch)
|
|
patch->enable();
|
|
}
|
|
|
|
|
|
void
|
|
Store::patch_disabled_event(const Path& path)
|
|
{
|
|
CountedPtr<PatchModel> patch = PtrCast<PatchModel>(object(path));
|
|
if (patch)
|
|
patch->disable();
|
|
}
|
|
|
|
|
|
void
|
|
Store::metadata_update_event(const Path& subject_path, const string& predicate, const string& value)
|
|
{
|
|
CountedPtr<ObjectModel> subject = object(subject_path);
|
|
if (subject)
|
|
subject->set_metadata(predicate, value);
|
|
else
|
|
cerr << "ERROR: metadata for nonexistant object." << endl;
|
|
}
|
|
|
|
|
|
void
|
|
Store::control_change_event(const Path& port_path, float value)
|
|
{
|
|
CountedPtr<PortModel> port = PtrCast<PortModel>(object(port_path));
|
|
if (port)
|
|
port->value(value);
|
|
else
|
|
cerr << "ERROR: metadata for nonexistant object." << endl;
|
|
}
|
|
|
|
|
|
void
|
|
Store::connection_event(const Path& src_port_path, const Path& dst_port_path)
|
|
{
|
|
CountedPtr<PortModel> src_port = PtrCast<PortModel>(object(src_port_path));
|
|
CountedPtr<PortModel> dst_port = PtrCast<PortModel>(object(dst_port_path));
|
|
|
|
assert(src_port);
|
|
assert(dst_port);
|
|
|
|
src_port->connected_to(dst_port);
|
|
dst_port->connected_to(src_port);
|
|
|
|
CountedPtr<ConnectionModel> cm(new ConnectionModel(src_port, dst_port));
|
|
|
|
CountedPtr<PatchModel> patch = PtrCast<PatchModel>(this->object(cm->patch_path()));
|
|
|
|
if (patch)
|
|
patch->add_connection(cm);
|
|
else
|
|
cerr << "ERROR: connection in nonexistant patch" << endl;
|
|
}
|
|
|
|
|
|
void
|
|
Store::disconnection_event(const Path& src_port_path, const Path& dst_port_path)
|
|
{
|
|
// Find the ports and create a ConnectionModel just to get at the parent path
|
|
// finding logic in ConnectionModel. So I'm lazy.
|
|
|
|
CountedPtr<PortModel> src_port = PtrCast<PortModel>(object(src_port_path));
|
|
CountedPtr<PortModel> dst_port = PtrCast<PortModel>(object(dst_port_path));
|
|
|
|
assert(src_port);
|
|
assert(dst_port);
|
|
|
|
src_port->disconnected_from(dst_port);
|
|
dst_port->disconnected_from(src_port);
|
|
|
|
CountedPtr<ConnectionModel> cm(new ConnectionModel(src_port, dst_port));
|
|
|
|
CountedPtr<PatchModel> patch = PtrCast<PatchModel>(this->object(cm->patch_path()));
|
|
|
|
if (patch)
|
|
patch->remove_connection(src_port_path, dst_port_path);
|
|
else
|
|
cerr << "ERROR: disconnection in nonexistant patch" << endl;
|
|
}
|
|
|
|
|
|
} // namespace Client
|
|
} // namespace Ingen
|
|
|