summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/io.h
blob: 3dc2c84b4f6d1f47fdf5e980e7b7c33585c2716a (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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
/*
    Copyright (C) 2000 Paul Davis 

    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., 675 Mass Ave, Cambridge, MA 02139, USA.

    $Id$
*/

#ifndef __ardour_io_h__
#define __ardour_io_h__

#include <string>
#include <vector>
#include <cmath>
#include <sigc++/signal.h>
#include <jack/jack.h>

#include <glibmm/thread.h>

#include <pbd/fastlog.h>
#include <pbd/undo.h>
#include <pbd/statefuldestructible.h> 
#include <pbd/controllable.h>

#include <ardour/ardour.h>
#include <ardour/utils.h>
#include <ardour/curve.h>
#include <ardour/types.h>
#include <ardour/data_type.h>

using std::string;
using std::vector;

class XMLNode;

namespace ARDOUR {

class Session;
class AudioEngine;
class Port;
class Connection;
class Panner;

/** A collection of input and output ports with connections.
 *
 * An IO can contain ports of varying types, making routes/inserts/etc with
 * varied combinations of types (eg MIDI and audio) possible.
 */
class IO : public PBD::StatefulDestructible
{

  public:
	static const string state_node_name;

	IO (Session&, string name, 
	    int input_min = -1, int input_max = -1, 
	    int output_min = -1, int output_max = -1,
	    DataType default_type = DataType::AUDIO);

	IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);

	virtual ~IO();

	int input_minimum() const { return _input_minimum; }
	int input_maximum() const { return _input_maximum; }
	int output_minimum() const { return _output_minimum; }
	int output_maximum() const { return _output_maximum; }

	void set_input_minimum (int n);
	void set_input_maximum (int n);
	void set_output_minimum (int n);
	void set_output_maximum (int n);

	DataType default_type() const { return _default_type; }

	const string& name() const { return _name; }
	virtual int set_name (string str, void *src);
	
	virtual void silence  (nframes_t, nframes_t offset);

	// These should be moved in to a separate object that manipulates an IO
	
	void pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff);
	void pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start_frame, nframes_t end_frame, 
			    nframes_t nframes, nframes_t offset);
	void collect_input  (vector<Sample*>&, uint32_t nbufs, nframes_t nframes, nframes_t offset);
	void deliver_output (vector<Sample*>&, uint32_t nbufs, nframes_t nframes, nframes_t offset);
	void deliver_output_no_pan (vector<Sample*>&, uint32_t nbufs, nframes_t nframes, nframes_t offset);
	void just_meter_input (nframes_t start_frame, nframes_t end_frame, 
			       nframes_t nframes, nframes_t offset);

	virtual uint32_t n_process_buffers () { return 0; }

	virtual void   set_gain (gain_t g, void *src);
	void           inc_gain (gain_t delta, void *src);
	gain_t         gain () const { return _desired_gain; }
	virtual gain_t effective_gain () const;

	Panner& panner() { return *_panner; }

	int ensure_io (uint32_t, uint32_t, bool clear, void *src);

	int use_input_connection (Connection&, void *src);
	int use_output_connection (Connection&, void *src);

	Connection *input_connection() const { return _input_connection; }
	Connection *output_connection() const { return _output_connection; }

	int add_input_port (string source, void *src, DataType type = DataType::NIL);
	int add_output_port (string destination, void *src, DataType type = DataType::NIL);

	int remove_input_port (Port *, void *src);
	int remove_output_port (Port *, void *src);

	int set_input (Port *, void *src);

	int connect_input (Port *our_port, string other_port, void *src);
	int connect_output (Port *our_port, string other_port, void *src);

	int disconnect_input (Port *our_port, string other_port, void *src);
	int disconnect_output (Port *our_port, string other_port, void *src);

	int disconnect_inputs (void *src);
	int disconnect_outputs (void *src);

	nframes_t output_latency() const;
	nframes_t input_latency() const;
	void           set_port_latency (nframes_t);

	Port *output (uint32_t n) const {
		if (n < _noutputs) {
			return _outputs[n];
		} else {
			return 0;
		}
	}

	Port *input (uint32_t n) const {
		if (n < _ninputs) {
			return _inputs[n];
		} else {
			return 0;
		}
	}

	uint32_t n_inputs () const { return _ninputs; }
	uint32_t n_outputs () const { return _noutputs; }

	sigc::signal<void,IOChange,void*> input_changed;
	sigc::signal<void,IOChange,void*> output_changed;

	sigc::signal<void,void*> gain_changed;
	sigc::signal<void,void*> name_changed;

	virtual XMLNode& state (bool full);
	XMLNode& get_state (void);
	int set_state (const XMLNode&);

	static int  disable_connecting (void);
	static int  enable_connecting (void);
	static int  disable_ports (void);
	static int  enable_ports (void);
	static int  disable_panners (void);
	static int  reset_panners (void);
	
	static sigc::signal<int> PortsLegal;
	static sigc::signal<int> PannersLegal;
	static sigc::signal<int> ConnectingLegal;
	static sigc::signal<void,uint32_t> MoreOutputs;
	static sigc::signal<int> PortsCreated;

	PBD::Controllable& gain_control() {
		return _gain_control;
	}

	/* Peak metering */

	float peak_input_power (uint32_t n) { 
		if (_ninputs == 0) {
			return minus_infinity();
		} else if (n < std::max (_ninputs, _noutputs)) {
			return _visible_peak_power[n];
		} else {
			return minus_infinity();
		}
	}

	float max_peak_power (uint32_t n) {
		if (_ninputs == 0) {
			return minus_infinity();
		} else if (n < std::max (_ninputs, _noutputs)) {
			return _max_peak_power[n];
		} else {
			return minus_infinity();
		}
	}

	void reset_max_peak_meters ();

	
    static void update_meters();

  private: 

    static sigc::signal<void>   Meter;
    static Glib::StaticMutex    m_meter_signal_lock;
    sigc::connection            m_meter_connection;

  public:

	/* automation */

	static void set_automation_interval (jack_nframes_t frames) {
		_automation_interval = frames;
	}

	static jack_nframes_t automation_interval() { 
		return _automation_interval;
	}

	void clear_automation ();

	bool gain_automation_recording() const { 
		return (_gain_automation_curve.automation_state() & (Write|Touch));
	}

	bool gain_automation_playback() const {
		return (_gain_automation_curve.automation_state() & Play) ||
			((_gain_automation_curve.automation_state() & Touch) && 
			 !_gain_automation_curve.touching());
	}

	virtual void set_gain_automation_state (AutoState);
	AutoState gain_automation_state() const { return _gain_automation_curve.automation_state(); }
	sigc::signal<void> gain_automation_state_changed;

	virtual void set_gain_automation_style (AutoStyle);
	AutoStyle gain_automation_style () const { return _gain_automation_curve.automation_style(); }
	sigc::signal<void> gain_automation_style_changed;

	virtual void transport_stopped (nframes_t now);
	void automation_snapshot (nframes_t now);

	ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }

	void start_gain_touch ();
	void end_gain_touch ();

	void start_pan_touch (uint32_t which);
	void end_pan_touch (uint32_t which);

	void defer_pan_reset ();
	void allow_pan_reset ();

	/* the session calls this for master outs before
	   anyone else. controls outs too, at some point.
	*/

	XMLNode *pending_state_node;
	int ports_became_legal ();

  private:
	mutable Glib::Mutex io_lock;

  protected:
	Session&            _session;
	Panner*             _panner;
	gain_t              _gain;
	gain_t              _effective_gain;
	gain_t              _desired_gain;
	Glib::Mutex         declick_lock;
	vector<Port*>       _outputs;
	vector<Port*>       _inputs;
	vector<float>       _peak_power;
	vector<float>       _visible_peak_power;
	vector<float>       _max_peak_power;
	string              _name;
	Connection*         _input_connection;
	Connection*         _output_connection;
	bool                 no_panner_reset;
	XMLNode*             deferred_state;
	DataType            _default_type;
	bool                _ignore_gain_on_deliver;
	

	virtual void set_deferred_state() {}

	void reset_peak_meters();
	void reset_panner ();

	virtual uint32_t pans_required() const { return _ninputs; }

	static void apply_declick (vector<Sample*>&, uint32_t nbufs, nframes_t nframes, 
				   gain_t initial, gain_t target, bool invert_polarity);

	struct GainControllable : public PBD::Controllable {
	    GainControllable (std::string name, IO& i) : Controllable (name), io (i) {}
	 
	    void set_value (float val);
	    float get_value (void) const;
   
	    IO& io;
	};

	GainControllable _gain_control;

	nframes_t last_automation_snapshot;
	static nframes_t _automation_interval;

	AutoState      _gain_automation_state;
	AutoStyle      _gain_automation_style;

	bool     apply_gain_automation;
	Curve    _gain_automation_curve;
	
	Glib::Mutex automation_lock;

	virtual int set_automation_state (const XMLNode&);
	virtual XMLNode& get_automation_state ();
	virtual int load_automation (std::string path);

	/* AudioTrack::deprecated_use_diskstream_connections() needs these */

	int set_inputs (const string& str);
	int set_outputs (const string& str);

	static bool connecting_legal;
	static bool ports_legal;

  private:

	uint32_t _ninputs;
	uint32_t _noutputs;

	/* are these the best variable names ever, or what? */

	sigc::connection input_connection_configuration_connection;
	sigc::connection output_connection_configuration_connection;
	sigc::connection input_connection_connection_connection;
	sigc::connection output_connection_connection_connection;

	static bool panners_legal;
	
	int connecting_became_legal ();
	int panners_became_legal ();
	sigc::connection connection_legal_c;
	sigc::connection port_legal_c;
	sigc::connection panner_legal_c;

	int _input_minimum;
	int _input_maximum;
	int _output_minimum;
	int _output_maximum;


	static int parse_io_string (const string&, vector<string>& chns);

	static int parse_gain_string (const string&, vector<string>& chns);
	
	int set_sources (vector<string>&, void *src, bool add);
	int set_destinations (vector<string>&, void *src, bool add);

	int ensure_inputs (uint32_t, bool clear, bool lockit, void *src);
	int ensure_outputs (uint32_t, bool clear, bool lockit, void *src);

	void drop_input_connection ();
	void drop_output_connection ();

	void input_connection_configuration_changed ();
	void input_connection_connection_changed (int);
	void output_connection_configuration_changed ();
	void output_connection_connection_changed (int);

	int create_ports (const XMLNode&);
	int make_connections (const XMLNode&);

	void setup_peak_meters ();
	void meter ();

	bool ensure_inputs_locked (uint32_t, bool clear, void *src);
	bool ensure_outputs_locked (uint32_t, bool clear, void *src);

	int32_t find_input_port_hole ();
	int32_t find_output_port_hole ();
};

} // namespace ARDOUR

#endif /*__ardour_io_h__ */