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