1 /*
2  * Copyright (C) 1999-2019 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2006-2007 Jesse Chappell <jesse@essej.net>
4  * Copyright (C) 2006-2009 Sampo Savolainen <v2@iki.fi>
5  * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
6  * Copyright (C) 2006-2016 Tim Mayberry <mojofunk@gmail.com>
7  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8  * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
9  * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
10  * Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
11  * Copyright (C) 2014-2019 Ben Loftis <ben@harrisonconsoles.com>
12  * Copyright (C) 2015 GZharun <grygoriiz@wavesglobal.com>
13  * Copyright (C) 2016-2018 Len Ovens <len@ovenwerks.net>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with this program; if not, write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28  */
29 
30 #include <cstdio>
31 
32 #include <boost/algorithm/string/erase.hpp>
33 
34 #include "pbd/i18n.h"
35 
36 #include "ardour/async_midi_port.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/bundle.h"
39 #include "ardour/session.h"
40 #include "ardour/user_bundle.h"
41 
42 using namespace ARDOUR;
43 using std::string;
44 
45 void
add_bundle(boost::shared_ptr<Bundle> bundle,bool emit_signal)46 Session::add_bundle (boost::shared_ptr<Bundle> bundle, bool emit_signal)
47 {
48 	{
49 		RCUWriter<BundleList> writer (_bundles);
50 		boost::shared_ptr<BundleList> b = writer.get_copy ();
51 		b->push_back (bundle);
52 	}
53 
54 	if (emit_signal) {
55 		BundleAddedOrRemoved (); /* EMIT SIGNAL */
56 		set_dirty();
57 	}
58 }
59 
60 void
remove_bundle(boost::shared_ptr<Bundle> bundle)61 Session::remove_bundle (boost::shared_ptr<Bundle> bundle)
62 {
63 	bool removed = false;
64 
65 	{
66 		RCUWriter<BundleList> writer (_bundles);
67 		boost::shared_ptr<BundleList> b = writer.get_copy ();
68 		BundleList::iterator i = find (b->begin(), b->end(), bundle);
69 
70 		if (i != b->end()) {
71 			b->erase (i);
72 			removed = true;
73 		}
74 	}
75 
76 	if (removed) {
77 		 BundleAddedOrRemoved (); /* EMIT SIGNAL */
78 	}
79 
80 	set_dirty();
81 }
82 
83 boost::shared_ptr<Bundle>
bundle_by_name(string name) const84 Session::bundle_by_name (string name) const
85 {
86 	boost::shared_ptr<BundleList> b = _bundles.reader ();
87 
88 	for (BundleList::const_iterator i = b->begin(); i != b->end(); ++i) {
89 		if ((*i)->name() == name) {
90 			return* i;
91 		}
92 	}
93 
94 	return boost::shared_ptr<Bundle> ();
95 }
96 
97 void
setup_bundles()98 Session::setup_bundles ()
99 {
100 
101 	{
102 		RCUWriter<BundleList> writer (_bundles);
103 		boost::shared_ptr<BundleList> b = writer.get_copy ();
104 		for (BundleList::iterator i = b->begin(); i != b->end();) {
105 			if (boost::dynamic_pointer_cast<UserBundle>(*i)) {
106 				++i;
107 				continue;
108 			}
109 			i = b->erase(i);
110 		}
111 	}
112 
113 	std::vector<string> inputs[DataType::num_types];
114 	std::vector<string> outputs[DataType::num_types];
115 
116 	for (uint32_t i = 0; i < DataType::num_types; ++i) {
117 		get_physical_ports (inputs[i], outputs[i], DataType (DataType::Symbol (i)),
118 		                    MidiPortFlags (0), /* no specific inclusions */
119 		                    MidiPortFlags (MidiPortControl|MidiPortVirtual) /* exclude control & virtual ports */
120 			);
121 	}
122 
123 	/* now add virtual Vkeybd, compare to PortGroupList::gather */
124 	if (_midi_ports) {
125 		boost::shared_ptr<Port> ap = boost::dynamic_pointer_cast<Port> (vkbd_output_port ());
126 		inputs[DataType::MIDI].push_back (AudioEngine::instance()->make_port_name_non_relative (ap->name ()));
127 
128 		/* JACK semantics prevent us directly calling the
129 		   pretty-name/metadata API from a server callback, and this is
130 		   called from a port registration callback. So defer to the
131 		   auto-connect thread, which does this sort of thing anyway.
132 		*/
133 
134 		g_atomic_int_set (&_update_pretty_names, 1);
135 		auto_connect_thread_wakeup ();
136 	}
137 
138 	/* Create a set of Bundle objects that map
139 	   to the physical I/O currently available.  We create both
140 	   mono and stereo bundles, so that the common cases of mono
141 	   and stereo tracks get bundles to put in their mixer strip
142 	   in / out menus.  There may be a nicer way of achieving that;
143 	   it doesn't really scale that well to higher channel counts
144 	*/
145 
146 	/* mono output bundles */
147 
148 	for (uint32_t np = 0; np < outputs[DataType::AUDIO].size(); ++np) {
149 		char buf[64];
150 		std::string pn = _engine.get_pretty_name_by_name (outputs[DataType::AUDIO][np]);
151 		if (!pn.empty()) {
152 			snprintf (buf, sizeof (buf), _("out %s"), pn.c_str());
153 		} else {
154 			snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
155 		}
156 
157 		boost::shared_ptr<Bundle> c (new Bundle (buf, true));
158 		c->add_channel (_("mono"), DataType::AUDIO);
159 		c->set_port (0, outputs[DataType::AUDIO][np]);
160 
161 		add_bundle (c, false);
162 	}
163 
164 	/* stereo output bundles */
165 
166 	for (uint32_t np = 0; np < outputs[DataType::AUDIO].size(); np += 2) {
167 		if (np + 1 < outputs[DataType::AUDIO].size()) {
168 			char buf[32];
169 			snprintf (buf, sizeof(buf), _("out %" PRIu32 "+%" PRIu32), np + 1, np + 2);
170 			boost::shared_ptr<Bundle> c (new Bundle (buf, true));
171 			c->add_channel (_("L"), DataType::AUDIO);
172 			c->set_port (0, outputs[DataType::AUDIO][np]);
173 			c->add_channel (_("R"), DataType::AUDIO);
174 			c->set_port (1, outputs[DataType::AUDIO][np + 1]);
175 
176 			add_bundle (c, false);
177 		}
178 	}
179 
180 	/* mono input bundles */
181 
182 	for (uint32_t np = 0; np < inputs[DataType::AUDIO].size(); ++np) {
183 		char buf[64];
184 		std::string pn = _engine.get_pretty_name_by_name (inputs[DataType::AUDIO][np]);
185 		if (!pn.empty()) {
186 			snprintf (buf, sizeof (buf), _("in %s"), pn.c_str());
187 		} else {
188 			snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
189 		}
190 
191 		boost::shared_ptr<Bundle> c (new Bundle (buf, false));
192 		c->add_channel (_("mono"), DataType::AUDIO);
193 		c->set_port (0, inputs[DataType::AUDIO][np]);
194 
195 		add_bundle (c, false);
196 	}
197 
198 	/* stereo input bundles */
199 
200 	for (uint32_t np = 0; np < inputs[DataType::AUDIO].size(); np += 2) {
201 		if (np + 1 < inputs[DataType::AUDIO].size()) {
202 			char buf[32];
203 			snprintf (buf, sizeof(buf), _("in %" PRIu32 "+%" PRIu32), np + 1, np + 2);
204 
205 			boost::shared_ptr<Bundle> c (new Bundle (buf, false));
206 			c->add_channel (_("L"), DataType::AUDIO);
207 			c->set_port (0, inputs[DataType::AUDIO][np]);
208 			c->add_channel (_("R"), DataType::AUDIO);
209 			c->set_port (1, inputs[DataType::AUDIO][np + 1]);
210 
211 			add_bundle (c, false);
212 		}
213 	}
214 
215 	/* MIDI input bundles */
216 
217 	for (uint32_t np = 0; np < inputs[DataType::MIDI].size(); ++np) {
218 		string n = inputs[DataType::MIDI][np];
219 
220 		std::string pn = _engine.get_pretty_name_by_name (n);
221 		if (!pn.empty()) {
222 			n = pn;
223 		} else {
224 			boost::erase_first (n, X_("alsa_pcm:"));
225 		}
226 		boost::shared_ptr<Bundle> c (new Bundle (n, false));
227 		c->add_channel ("", DataType::MIDI);
228 		c->set_port (0, inputs[DataType::MIDI][np]);
229 		add_bundle (c, false);
230 	}
231 
232 	/* MIDI output bundles */
233 
234 	for (uint32_t np = 0; np < outputs[DataType::MIDI].size(); ++np) {
235 		string n = outputs[DataType::MIDI][np];
236 		std::string pn = _engine.get_pretty_name_by_name (n);
237 		if (!pn.empty()) {
238 			n = pn;
239 		} else {
240 			boost::erase_first (n, X_("alsa_pcm:"));
241 		}
242 		boost::shared_ptr<Bundle> c (new Bundle (n, true));
243 		c->add_channel ("", DataType::MIDI);
244 		c->set_port (0, outputs[DataType::MIDI][np]);
245 		add_bundle (c, false);
246 	}
247 
248 	// we trust the backend to only calls us if there's a change
249 	BundleAddedOrRemoved (); /* EMIT SIGNAL */
250 }
251