1 /*
2  * Copyright (C) 1998-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2013-2017 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include "ardour/audioengine.h"
21 #include "ardour/async_midi_port.h"
22 #include "ardour/midiport_manager.h"
23 #include "ardour/rc_configuration.h"
24 
25 #include "pbd/i18n.h"
26 
27 using namespace ARDOUR;
28 using namespace std;
29 using namespace MIDI;
30 using namespace PBD;
31 
32 
MidiPortManager()33 MidiPortManager::MidiPortManager ()
34 {
35 	create_ports ();
36 }
37 
~MidiPortManager()38 MidiPortManager::~MidiPortManager ()
39 {
40 	Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
41 	if (_scene_in) {
42 		AudioEngine::instance()->unregister_port (_scene_in);
43 	}
44 	if (_scene_out) {
45 		AudioEngine::instance()->unregister_port (_scene_out);
46 	}
47 	if (_mtc_output_port) {
48 		AudioEngine::instance()->unregister_port (_mtc_output_port);
49 	}
50 	if (_midi_clock_output_port) {
51 		AudioEngine::instance()->unregister_port (_midi_clock_output_port);
52 	}
53 
54 }
55 
56 void
create_ports()57 MidiPortManager::create_ports ()
58 {
59 	/* this method is idempotent */
60 
61 	if (_mmc_in) {
62 		return;
63 	}
64 
65 	_mmc_in  = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("MMC in"), true);
66 	_mmc_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("MMC out"), true);
67 
68 	_scene_in  = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("Scene in"), true);
69 	_scene_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Scene out"), true);
70 
71 	_vkbd_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("x-virtual-keyboard"), true, IsTerminal);
72 	boost::dynamic_pointer_cast<AsyncMIDIPort>(_vkbd_out)->set_flush_at_cycle_start (true);
73 
74 	/* Now register ports used to send positional sync data (MTC and MIDI Clock) */
75 
76 	boost::shared_ptr<ARDOUR::Port> p;
77 
78 	p = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("MTC out"));
79 	_mtc_output_port= boost::dynamic_pointer_cast<MidiPort> (p);
80 
81 	p = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("MIDI Clock out"), false, TransportGenerator);
82 	_midi_clock_output_port= boost::dynamic_pointer_cast<MidiPort> (p);
83 }
84 
85 void
set_midi_port_states(const XMLNodeList & nodes)86 MidiPortManager::set_midi_port_states (const XMLNodeList&nodes)
87 {
88 	XMLProperty const * prop;
89 	typedef map<std::string,boost::shared_ptr<Port> > PortMap;
90 	PortMap ports;
91 	const int version = 0;
92 
93 	ports.insert (make_pair (_mtc_output_port->name(), _mtc_output_port));
94 	ports.insert (make_pair (_midi_clock_output_port->name(), _midi_clock_output_port));
95 	ports.insert (make_pair (_mmc_in->name(), _mmc_in));
96 	ports.insert (make_pair (_mmc_out->name(), _mmc_out));
97 	ports.insert (make_pair (_vkbd_out->name(), _vkbd_out));
98 	ports.insert (make_pair (_scene_out->name(), _scene_out));
99 	ports.insert (make_pair (_scene_in->name(), _scene_in));
100 
101 	for (XMLNodeList::const_iterator n = nodes.begin(); n != nodes.end(); ++n) {
102 		if ((prop = (*n)->property (X_("name"))) == 0) {
103 			continue;
104 		}
105 
106 		PortMap::iterator p = ports.find (prop->value());
107 		if (p == ports.end()) {
108 			continue;
109 		}
110 
111 		p->second->set_state (**n, version);
112 	}
113 }
114 
115 list<XMLNode*>
get_midi_port_states() const116 MidiPortManager::get_midi_port_states () const
117 {
118 	typedef map<std::string,boost::shared_ptr<Port> > PortMap;
119 	PortMap ports;
120 	list<XMLNode*> s;
121 
122 	ports.insert (make_pair (_mtc_output_port->name(), _mtc_output_port));
123 	ports.insert (make_pair (_midi_clock_output_port->name(), _midi_clock_output_port));
124 	ports.insert (make_pair (_mmc_in->name(), _mmc_in));
125 	ports.insert (make_pair (_mmc_out->name(), _mmc_out));
126 	ports.insert (make_pair (_vkbd_out->name(), _vkbd_out));
127 	ports.insert (make_pair (_scene_out->name(), _scene_out));
128 	ports.insert (make_pair (_scene_in->name(), _scene_in));
129 
130 	for (PortMap::const_iterator p = ports.begin(); p != ports.end(); ++p) {
131 		s.push_back (&p->second->get_state());
132 	}
133 
134 	return s;
135 }
136 
137 boost::shared_ptr<AsyncMIDIPort>
vkbd_output_port() const138 MidiPortManager::vkbd_output_port () const
139 {
140 	return boost::dynamic_pointer_cast<AsyncMIDIPort> (_vkbd_out);
141 }
142