summaryrefslogtreecommitdiffstats
path: root/arts/midi/midiclient_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'arts/midi/midiclient_impl.cc')
-rw-r--r--arts/midi/midiclient_impl.cc274
1 files changed, 274 insertions, 0 deletions
diff --git a/arts/midi/midiclient_impl.cc b/arts/midi/midiclient_impl.cc
new file mode 100644
index 00000000..d57e7fd7
--- /dev/null
+++ b/arts/midi/midiclient_impl.cc
@@ -0,0 +1,274 @@
+ /*
+
+ Copyright (C) 2000-2002 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ */
+
+#include "midiclient_impl.h"
+#include "midimanager_impl.h"
+#include "midimanagerport_impl.h"
+#include "midisyncgroup_impl.h"
+#include "timestampmath.h"
+
+#undef DEBUG_SYNC_DRIFT
+
+using namespace Arts;
+using namespace std;
+
+MidiClient_impl::MidiClient_impl(const MidiClientInfo& info,
+ MidiManager_impl *manager) :_info(info), manager(manager), syncGroup(0)
+{
+}
+
+MidiClient_impl::~MidiClient_impl()
+{
+ while(!_info.connections.empty())
+ disconnect(manager->findClient(_info.connections[0]));
+
+ if(syncGroup)
+ {
+ syncGroup->clientDied(this);
+ syncGroup = 0;
+ }
+ manager->removeClient(this);
+}
+
+MidiClientInfo MidiClient_impl::info()
+{
+ return _info;
+}
+
+void MidiClient_impl::title(const string &newvalue)
+{
+ _info.title = newvalue;
+}
+
+string MidiClient_impl::title()
+{
+ return _info.title;
+}
+
+void MidiClient_impl::addInputPort(MidiPort port)
+{
+ assert(_info.direction == mcdRecord);
+
+ ports.push_back(port);
+
+ // FIXME: should we synchronize inputPorts at all
+ rebuildConnections();
+}
+
+MidiPort MidiClient_impl::addOutputPort()
+{
+ assert(_info.direction == mcdPlay);
+
+ MidiPort port = MidiPort::_from_base(new MidiManagerPort_impl(this));
+ ports.push_back(port);
+
+ rebuildConnections();
+ return port;
+}
+
+void MidiClient_impl::removePort(MidiPort port)
+{
+ list<MidiPort>::iterator i = ports.begin();
+ while(i != ports.end())
+ {
+ if (i->_isEqual(port))
+ i = ports.erase(i);
+ else
+ i++;
+ }
+
+ rebuildConnections();
+}
+
+void MidiClient_impl::rebuildConnections()
+{
+ _connections.clear();
+
+ vector<long>::iterator li;
+ for(li = _info.connections.begin(); li != _info.connections.end(); li++)
+ {
+ MidiClient_impl *other = manager->findClient(*li);
+ assert(other);
+
+ list<MidiPort>::iterator pi;
+ for(pi = other->ports.begin(); pi != other->ports.end(); pi++)
+ {
+ MidiClientConnection mcc;
+ mcc.offset = TimeStamp(0,0);
+ mcc.port = *pi;
+ _connections.push_back(mcc);
+ }
+ }
+ adjustSync();
+}
+
+list<MidiClientConnection> *MidiClient_impl::connections()
+{
+ return &_connections;
+}
+
+static void removeElement(vector<long>& vec, long el)
+{
+ vector<long> tmp;
+ vec.swap(tmp);
+ vector<long>::iterator i;
+ for(i = tmp.begin(); i != tmp.end(); i++)
+ if(*i != el) vec.push_back(*i);
+}
+
+void MidiClient_impl::connect(MidiClient_impl *dest)
+{
+ assert(_info.direction != dest->_info.direction);
+
+ disconnect(dest);
+
+ _info.connections.push_back(dest->ID());
+ dest->_info.connections.push_back(ID());
+
+ list<MidiPort>::iterator pi;
+
+ /* add the other clients ports to our connection list */
+ for(pi = dest->ports.begin(); pi != dest->ports.end(); pi++)
+ {
+ MidiClientConnection mcc;
+ mcc.offset = TimeStamp(0,0);
+ mcc.port = *pi;
+ _connections.push_back(mcc);
+ }
+
+ /* add our ports to the other clients connection list */
+ for(pi = ports.begin(); pi != ports.end(); pi++)
+ {
+ MidiClientConnection mcc;
+ mcc.offset = TimeStamp(0,0);
+ mcc.port = *pi;
+ dest->_connections.push_back(mcc);
+ }
+ adjustSync();
+}
+
+void MidiClient_impl::disconnect(MidiClient_impl *dest)
+{
+ assert(_info.direction != dest->_info.direction);
+
+ removeElement(_info.connections,dest->ID());
+ removeElement(dest->_info.connections,ID());
+
+ list<MidiPort>::iterator pi;
+
+ /* remove the other clients ports from our connection list */
+ for(pi = dest->ports.begin(); pi != dest->ports.end(); pi++)
+ {
+ list<MidiClientConnection>::iterator ci = _connections.begin();
+
+ while(ci != _connections.end())
+ {
+ if(ci->port._isEqual(*pi))
+ ci = _connections.erase(ci);
+ else
+ ci++;
+ }
+ }
+
+ /* remove our ports from the other clients connection list */
+ for(pi = ports.begin(); pi != ports.end(); pi++)
+ {
+ list<MidiClientConnection>::iterator ci = dest->_connections.begin();
+
+ while(ci != dest->_connections.end())
+ {
+ if(ci->port._isEqual(*pi))
+ ci = dest->_connections.erase(ci);
+ else
+ ci++;
+ }
+ }
+ adjustSync();
+}
+
+void MidiClient_impl::synchronizeTo(const TimeStamp& time)
+{
+ list<MidiClientConnection>::iterator i;
+
+ for(i = _connections.begin(); i != _connections.end(); i++)
+ {
+ MidiClientConnection& mcc = *i;
+
+#ifdef DEBUG_SYNC_DRIFT
+ TimeStamp drift = mcc.offset; // debug drift
+#endif
+
+ mcc.offset = mcc.port.playTime();
+ timeStampDec(mcc.offset, time);
+
+#ifdef DEBUG_SYNC_DRIFT
+ timeStampDec(drift,mcc.offset); // debug drift
+ printf("SYNC DRIFT %30s %30s: %f\n",
+ mcc.port._interfaceName().c_str(), _info.title.c_str(),
+ timeStampToDouble(drift));
+#endif
+ }
+}
+
+void MidiClient_impl::setSyncGroup(MidiSyncGroup_impl *newSyncGroup)
+{
+ syncGroup = newSyncGroup;
+}
+
+void MidiClient_impl::adjustSync()
+{
+ if(syncGroup)
+ syncGroup->clientChanged(this);
+ else
+ synchronizeTo(systemMidiTimer.time());
+}
+
+TimeStamp MidiClient_impl::time()
+{
+ if(syncGroup)
+ return syncGroup->time();
+ else
+ return clientTime();
+}
+
+TimeStamp MidiClient_impl::playTime()
+{
+ if(syncGroup)
+ return syncGroup->playTime();
+ else
+ return systemMidiTimer.time();
+}
+
+TimeStamp MidiClient_impl::clientTime()
+{
+ TimeStamp result = playTime();
+
+ list<MidiClientConnection>::iterator i;
+ for(i = _connections.begin(); i != _connections.end(); i++)
+ {
+ TimeStamp time = i->port.time();
+ timeStampDec(time, i->offset);
+ result = timeStampMax(result, time);
+ }
+
+ return result;
+}