summaryrefslogtreecommitdiffstats
path: root/flow/bus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flow/bus.cpp')
-rw-r--r--flow/bus.cpp367
1 files changed, 367 insertions, 0 deletions
diff --git a/flow/bus.cpp b/flow/bus.cpp
new file mode 100644
index 0000000..27e39c5
--- /dev/null
+++ b/flow/bus.cpp
@@ -0,0 +1,367 @@
+ /*
+
+ Copyright (C) 1998-2000 Stefan Westerfeld
+ stefan@space.twc.de
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#include "bus.h"
+#include "flowsystem.h"
+#include "debug.h"
+#include <iostream>
+#include <set>
+
+#ifdef __SUNPRO_CC
+/* SunPRO CC looses to link this when the_BusManager is static, because
+ later a template implementation file references this symbol. */
+#define the_BusManager __internal_aRts_the_BusManager__Bahh__
+#else
+static
+#endif
+ Arts::BusManager *the_BusManager = 0;
+
+using namespace Arts;
+using namespace std;
+
+// shutdown bus manager on termination
+
+namespace Arts {
+ static class BusManagerShutdown :public StartupClass
+ {
+ public:
+ void startup() { };
+ void shutdown()
+ {
+ if(::the_BusManager)
+ {
+ delete ::the_BusManager;
+ ::the_BusManager = 0;
+ }
+ }
+ } The_BusManagerShutdown;
+}
+
+BusManager::BusManager()
+{
+ // this constructor isn't public (Singleton)
+}
+
+BusManager *BusManager::the()
+{
+ if(!::the_BusManager) ::the_BusManager = new BusManager;
+ return(::the_BusManager);
+}
+
+BusManager::Bus *BusManager::findBus(const string& name)
+{
+ list<Bus *>::iterator bi;
+
+ for(bi = _busList.begin(); bi != _busList.end(); bi++)
+ {
+ if((*bi)->name == name) return(*bi);
+ }
+ Bus *bus = new Bus;
+ bus->left.start();
+ bus->right.start();
+ bus->name = name;
+ _busList.push_back(bus);
+
+ return(bus);
+}
+
+vector<string> *BusManager::busList()
+{
+ set<string> names;
+ set<string>::iterator si;
+
+ list<Bus *>::iterator bi;
+ for(bi = _busList.begin(); bi != _busList.end(); bi++)
+ names.insert((*bi)->name);
+
+ vector<string> *bl = new vector<string>;
+ for(si=names.begin();si != names.end();si++) bl->push_back(*si);
+ return bl;
+}
+
+void BusManager::addClient(const string& busname, BusClient *client)
+{
+ Bus *bus = findBus(busname);
+ bus->clients.push_back(client);
+
+ // attach the new client
+ client->snode()->virtualize("left", bus->left._node(), "invalue");
+ client->snode()->virtualize("right", bus->right._node(), "invalue");
+}
+
+void BusManager::removeClient(BusClient *client)
+{
+ list<Bus *>::iterator bi;
+ for(bi = _busList.begin(); bi != _busList.end(); bi++)
+ {
+ Bus *bus = *bi;
+
+ list<BusClient *>::iterator ci;
+ for(ci = bus->clients.begin(); ci != bus->clients.end(); ci++)
+ {
+ if(*ci == client)
+ {
+ bus->clients.erase(ci);
+
+ if(bus->clients.empty() && bus->servers.empty())
+ {
+ _busList.erase(bi);
+ delete bus;
+ }
+ else
+ {
+ client->snode()->devirtualize("left",
+ bus->left._node(), "invalue");
+ client->snode()->devirtualize("right",
+ bus->right._node(), "invalue");
+ }
+ return;
+ }
+ }
+ }
+}
+
+void BusManager::addServer(const string& busname, BusClient *server)
+{
+ Bus *bus = findBus(busname);
+ bus->servers.push_back(server);
+
+ server->snode()->virtualize("left",bus->left._node(),"outvalue");
+ server->snode()->virtualize("right",bus->right._node(),"outvalue");
+}
+
+void BusManager::removeServer(BusClient *server)
+{
+ list<Bus *>::iterator bi;
+
+ for(bi = _busList.begin(); bi != _busList.end(); bi++)
+ {
+ Bus *bus = *bi;
+
+ list<BusClient *>::iterator si;
+ for(si = bus->servers.begin(); si != bus->servers.end(); si++)
+ {
+ if(*si == server)
+ {
+ bus->servers.erase(si);
+ if(bus->clients.empty() && bus->servers.empty())
+ {
+ _busList.erase(bi);
+ delete bus;
+ }
+ else
+ {
+ server->snode()->devirtualize("left",
+ bus->left._node(), "outvalue");
+ server->snode()->devirtualize("right",
+ bus->right._node(),"outvalue");
+ }
+ return;
+ }
+ }
+ }
+}
+
+namespace Arts {
+
+class Synth_BUS_UPLINK_impl :public Synth_BUS_UPLINK_skel,
+ public StdSynthModule, public BusClient
+{
+ BusManager *bm;
+ bool running, active, relink;
+ string _busname;
+public:
+ Synth_BUS_UPLINK_impl();
+
+ string busname() { return _busname; }
+ void busname(const string& newname);
+ AutoSuspendState autoSuspend() { return asSuspend; }
+ void streamInit();
+ void streamEnd();
+ ScheduleNode *snode() { return _node(); }
+
+ void CallBack();
+
+ void connect();
+ void disconnect();
+};
+
+REGISTER_IMPLEMENTATION(Synth_BUS_UPLINK_impl);
+
+}
+
+Synth_BUS_UPLINK_impl::Synth_BUS_UPLINK_impl() :running(false)
+{
+ bm = BusManager::the();
+}
+
+void Synth_BUS_UPLINK_impl::streamInit()
+{
+ assert(!running);
+ running = true;
+ active = relink = false;
+
+ connect(); // connect to the BusManager
+}
+
+void Synth_BUS_UPLINK_impl::busname(const string& newname)
+{
+ _busname = newname;
+
+ /* TODO */
+ // to be sure that reconnection happens when outside the scheduling cycle
+ if(running)
+ {
+ relink = true;
+ CallBack();
+ }
+}
+
+void Synth_BUS_UPLINK_impl::connect()
+{
+ assert(active == false);
+ if(!_busname.empty())
+ {
+ active = true;
+ bm->addClient(_busname, this);
+ }
+}
+
+void Synth_BUS_UPLINK_impl::disconnect()
+{
+ if(active == true)
+ {
+ bm->removeClient(this);
+ active = false;
+ }
+}
+
+void Synth_BUS_UPLINK_impl::CallBack()
+{
+ if(relink)
+ {
+ disconnect();
+ connect();
+ relink = false;
+ }
+}
+
+void Synth_BUS_UPLINK_impl::streamEnd()
+{
+ disconnect();
+
+ assert(running);
+ running = false;
+}
+
+namespace Arts {
+
+class Synth_BUS_DOWNLINK_impl :public Synth_BUS_DOWNLINK_skel,
+ public StdSynthModule, public BusClient
+{
+ bool running, active, relink;
+ BusManager *bm;
+
+ string _busname;
+
+ void connect();
+ void disconnect();
+
+public:
+ string busname() { return _busname; }
+ void busname(const string& newname);
+
+ Synth_BUS_DOWNLINK_impl();
+ AutoSuspendState autoSuspend() { return asSuspend; }
+ void streamInit();
+ void streamEnd();
+ void CallBack();
+ ScheduleNode *snode() { return _node(); }
+};
+
+REGISTER_IMPLEMENTATION(Synth_BUS_DOWNLINK_impl);
+
+}
+
+Synth_BUS_DOWNLINK_impl::Synth_BUS_DOWNLINK_impl() :running(false)
+{
+ bm = BusManager::the();
+}
+
+void Synth_BUS_DOWNLINK_impl::streamInit()
+{
+ assert(!running);
+ running = true;
+
+ active = relink = false;
+ connect();
+}
+
+void Synth_BUS_DOWNLINK_impl::streamEnd()
+{
+ assert(running);
+ running = false;
+
+ disconnect();
+}
+
+void Synth_BUS_DOWNLINK_impl::connect()
+{
+ assert(active == false);
+ if(!_busname.empty())
+ {
+ active = true;
+ bm->addServer(_busname, this);
+ }
+}
+
+void Synth_BUS_DOWNLINK_impl::disconnect()
+{
+ if(active == true)
+ {
+ bm->removeServer(this);
+ active = false;
+ }
+}
+
+void Synth_BUS_DOWNLINK_impl::CallBack()
+{
+ if(relink)
+ {
+ disconnect();
+ connect();
+ relink = false;
+ }
+}
+
+void Synth_BUS_DOWNLINK_impl::busname(const string& newname)
+{
+ _busname = newname;
+
+ /* TODO */
+ // to be sure that reconnection happens when outside the scheduling cycle
+ if(running)
+ {
+ relink = true;
+ CallBack();
+ }
+}