summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/port_manager.h
blob: fd8fd102b06a5ccb44eb591eb8772de59881c80d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
 * Copyright (C) 2013-2019 Paul Davis <paul@linuxaudiosystems.com>
 * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef __libardour_port_manager_h__
#define __libardour_port_manager_h__

#include <exception>
#include <map>
#include <string>
#include <vector>

#include <stdint.h>

#include <boost/shared_ptr.hpp>

#include "pbd/rcu.h"
#include "pbd/ringbuffer.h"

#include "ardour/chan_count.h"
#include "ardour/midiport_manager.h"
#include "ardour/port.h"

namespace ARDOUR {

class PortEngine;
class AudioBackend;
class Session;

class LIBARDOUR_API PortManager
{
public:
	typedef std::map<std::string, boost::shared_ptr<Port> > Ports;
	typedef std::list<boost::shared_ptr<Port> >             PortList;

	PortManager ();
	virtual ~PortManager () {}

	PortEngine& port_engine ();

	uint32_t    port_name_size () const;
	std::string my_name () const;

	/* Port registration */

	boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname, bool async = false, PortFlags extra_flags = PortFlags (0));
	boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname, bool async = false, PortFlags extra_flags = PortFlags (0));
	int                     unregister_port (boost::shared_ptr<Port>);

	/* Port connectivity */

	int connect (const std::string& source, const std::string& destination);
	int disconnect (const std::string& source, const std::string& destination);
	int disconnect (boost::shared_ptr<Port>);
	int disconnect (std::string const&);
	int reestablish_ports ();
	int reconnect_ports ();

	bool connected (const std::string&);
	bool physically_connected (const std::string&);
	int  get_connections (const std::string&, std::vector<std::string>&);

	/* Naming */

	boost::shared_ptr<Port> get_port_by_name (const std::string&);
	void                    port_renamed (const std::string&, const std::string&);
	std::string             make_port_name_relative (const std::string& name) const;
	std::string             make_port_name_non_relative (const std::string& name) const;
	std::string             get_pretty_name_by_name (const std::string& portname) const;
	std::string             short_port_name_from_port_name (std::string const& full_name) const;
	bool                    port_is_mine (const std::string& fullname) const;

	static bool port_is_control_only (std::string const&);

	/* other Port management */

	bool      port_is_physical (const std::string&) const;
	void      get_physical_outputs (DataType      type, std::vector<std::string>&,
	                                MidiPortFlags include = MidiPortFlags (0),
	                                MidiPortFlags exclude = MidiPortFlags (0));
	void      get_physical_inputs (DataType      type, std::vector<std::string>&,
	                               MidiPortFlags include = MidiPortFlags (0),
	                               MidiPortFlags exclude = MidiPortFlags (0));

	ChanCount n_physical_outputs () const;
	ChanCount n_physical_inputs () const;

	int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&);
	int get_ports (DataType, PortList&);

	void set_port_pretty_name (std::string const&, std::string const&);

	void remove_all_ports ();

	void clear_pending_port_deletions ();

	virtual void add_pending_port_deletion (Port*) = 0;

	PBD::RingBuffer<Port*>& port_deletions_pending ()
	{
		return _port_deletions_pending;
	}

	bool check_for_ambiguous_latency (bool log = false) const;

	/* per-Port monitoring */

	bool can_request_input_monitoring () const;
	void request_input_monitoring (const std::string&, bool) const;
	void ensure_input_monitoring (const std::string&, bool) const;

	class PortRegistrationFailure : public std::exception
	{
	public:
		PortRegistrationFailure (std::string const& why = "")
			: reason (why) {}

		~PortRegistrationFailure () throw () {}

		const char* what () const throw ()
		{
			return reason.c_str ();
		}

	private:
		std::string reason;
	};

	/* the port engine will invoke these callbacks when the time is right */

	void registration_callback ();
	int  graph_order_callback ();
	void connect_callback (const std::string&, const std::string&, bool connection);

	bool port_remove_in_progress () const
	{
		return _port_remove_in_progress;
	}

	struct MidiPortInformation {
		std::string   backend;
		std::string   pretty_name;
		bool          input;
		MidiPortFlags properties;
		bool          exists;

		MidiPortInformation (std::string const& b, std::string const& pretty, bool input, MidiPortFlags flags, bool xists)
			: backend (b)
			, pretty_name (pretty)
			, input (input)
			, properties (flags)
			, exists (xists)
		{}

		MidiPortInformation ()
			: properties (MidiPortFlags (0))
			, exists (false)
		{}
	};

	void fill_midi_port_info ();

	MidiPortInformation midi_port_information (std::string const&);
	void                get_known_midi_ports (std::vector<std::string>&);
	void                get_midi_selection_ports (std::vector<std::string>&);
	void                add_midi_port_flags (std::string const&, MidiPortFlags);
	void                remove_midi_port_flags (std::string const&, MidiPortFlags);

	/** Emitted if the list of ports to be used for MIDI selection tracking changes */
	PBD::Signal0<void> MidiSelectionPortsChanged;
	/** Emitted if anything other than the selection property for a MIDI port changes */
	PBD::Signal0<void> MidiPortInfoChanged;

	/** Emitted if the backend notifies us of a graph order event */
	PBD::Signal0<void> GraphReordered;

	/** Emitted if a Port is registered or unregistered */
	PBD::Signal0<void> PortRegisteredOrUnregistered;

	/** Emitted if a Port is connected or disconnected.
	 *  The Port parameters are the ports being connected / disconnected, or 0 if they are not known to Ardour.
	 *  The std::string parameters are the (long) port names.
	 *  The bool parameter is true if ports were connected, or false for disconnected.
	 */
	PBD::Signal5<void, boost::weak_ptr<Port>, std::string, boost::weak_ptr<Port>, std::string, bool> PortConnectedOrDisconnected;

protected:
	boost::shared_ptr<AudioBackend> _backend;

	SerializedRCUManager<Ports> ports;

	bool                   _port_remove_in_progress;
	PBD::RingBuffer<Port*> _port_deletions_pending;

	boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input, bool async = false, PortFlags extra_flags = PortFlags (0));
	void                    port_registration_failure (const std::string& portname);

	/** List of ports to be used between \ref cycle_start() and \ref cycle_end() */
	boost::shared_ptr<Ports> _cycle_ports;

	void silence (pframes_t nframes, Session* s = 0);
	void silence_outputs (pframes_t nframes);
	void check_monitoring ();
	/** Signal the start of an audio cycle.
	 * This MUST be called before any reading/writing for this cycle.
	 * Realtime safe.
	 */
	void cycle_start (pframes_t nframes, Session* s = 0);

	/** Signal the end of an audio cycle.
	 * This signifies that the cycle began with @ref cycle_start has ended.
	 * This MUST be called at the end of each cycle.
	 * Realtime safe.
	 */
	void cycle_end (pframes_t nframes, Session* s = 0);

	void cycle_end_fade_out (gain_t, gain_t, pframes_t, Session* s = 0);

	typedef std::map<std::string, MidiPortInformation> MidiPortInfo;

	mutable Glib::Threads::Mutex midi_port_info_mutex;
	MidiPortInfo                 midi_port_info;

	static std::string midi_port_info_file ();
	bool               midi_info_dirty;
	void               save_midi_port_info ();
	void               load_midi_port_info ();
	void               fill_midi_port_info_locked ();

	void filter_midi_ports (std::vector<std::string>&, MidiPortFlags, MidiPortFlags);

	void set_port_buffer_sizes (pframes_t);
};

} // namespace ARDOUR

#endif /* __libardour_port_manager_h__ */